Prev: 8DCC Up: Map Next: 8FD0
8DE3: Print Handler
The default print handler for the state machine pointer at PrintState_Handler. Called on initialisation, and restored after each byte is consumed. Dispatches each byte of a messaging string to the appropriate action based on its value:
Byte Action
20–7F Print the ASCII character.
80–FF Replace with 21 ("!") and print.
0D Carriage return: reset X to left margin, advance Y by one line.
10–1A Control code: install a parameter handler into PrintState_Handler.
All others Replace with 3F ("?") and print.
Input
A Byte to print or control code
PrintHandler 8DE3 CP $80 If the byte is less than 80 jump to PrintHandler_Dispatch.
8DE5 JR C,PrintHandler_Dispatch
8DE7 LD A,$21 Otherwise replace the byte with 21 ("!").
8DE9 JP PrintHandler_Render Jump to PrintHandler_Render to render the character.
Dispatch handler for printing.
PrintHandler_Dispatch 8DEC CP $20 If the byte is 20 or higher (printable ASCII), jump to PrintHandler_Render to render it.
8DEE JP NC,PrintHandler_Render
8DF1 CP $0D If the byte is a carriage return (0D), jump to PrintHandler_Newline.
8DF3 JR Z,PrintHandler_Newline
8DF5 CP $10 If the byte is less than 10 jump to PrintHandler_Invalid (unsupported code).
8DF7 JR C,PrintHandler_Invalid
8DF9 CP $1B If the byte is 1B or higher, jump to PrintHandler_Invalid (unsupported code).
8DFB JR NC,PrintHandler_Invalid
Look up the two-byte handler address from the control code dispatch table at ControlCode_DispatchTable. The code is zero-indexed from 10 and doubled since each table entry is two bytes wide.
8DFD LD HL,$8FD0 HL=ControlCode_DispatchTable (base of the control code dispatch table).
8E00 SUB $10 Zero-index the control code from 10.
8E02 LD D,$00 DE=zero-indexed control code.
8E04 LD E,A
8E05 ADD HL,DE Double the index (two bytes per table entry).
8E06 ADD HL,DE
8E07 LD E,(HL) Read the handler address from the dispatch table into DE.
8E08 INC HL
8E09 LD D,(HL)
8E0A LD ($800A),DE Write the handler address to PrintState_Handler.
8E0E RET Return.
Carriage return handler: resets the X position to the left margin, then advances the Y position by one font line height (wrapping at BC).
PrintHandler_Newline 8E0F LD HL,$8001 HL=PrintState_X (X position pointer).
8E12 LD A,($8005) A=*PrintState_LeftMargin (left margin X position).
8E15 LD (HL),A Write the left margin value to *HL, resetting X to the left margin.
8E16 DEC HL Decrement HL to point at PrintState_Y (Y position).
PrintHandler_AdvanceRow 8E17 LD A,(HL) A=*HL + font line height (*PrintState_LineHeight).
8E18 ADD A,(IX+$10)
8E1B CP $BC Wrap the Y position at BC if it has reached or exceeded that value.
8E1D JR C,PrintHandler_AdvanceRow_Store
8E1F SUB $BC Subtract BC to wrap Y.
PrintHandler_AdvanceRow_Store 8E21 LD (HL),A Write the new Y position back to *HL.
8E22 RET Return.
Parameter handler for unsupported control codes 14 and 15. Consumes the parameter byte by resetting PrintState_Handler to the default handler, then falls through to PrintHandler_Invalid to print a "?" (3F) placeholder.
PrintHandler_Unsupported 8E23 LD HL,$8DE3 Reset PrintState_Handler to PrintHandler (default handler).
8E26 LD ($800A),HL
PrintHandler_Invalid 8E29 LD A,$3F Replace the byte with 3F ("?").
8E2B JP PrintHandler_Render Jump to PrintHandler_Render to render the character.
Set INK colour parameter handler. Called on the byte immediately following a 10 (INK) control code. Masks the parameter to the lower three bits (colour 00–07) and writes it into the INK bits (0–2) of the attribute byte at PrintState_Attr.
PrintHandler_Ink 8E2E LD B,$08 B=08 (mask limit for INK colour range 00–07).
8E30 CALL PrintHandler_MaskParam Call PrintHandler_MaskParam to reset PrintState_Handler and mask B to the colour value.
8E33 LD A,($8004) A=*PrintState_Attr (current attribute byte).
8E36 AND %11111000 Clear the INK bits (F8 = keep PAPER, BRIGHT, FLASH).
8E38 OR B Write the new INK colour into bits 0–2.
8E39 LD ($8004),A Write the updated attribute byte back to *PrintState_Attr.
8E3C RET Return.
Set PAPER colour parameter handler. Called on the byte immediately following a 11 (PAPER) control code. Masks the parameter to the lower three bits (colour 00–07) and writes it into the PAPER bits (3–5) of the attribute byte at PrintState_Attr.
PrintHandler_Paper 8E3D LD B,$08 B=08 (mask limit for PAPER colour range 00–07).
8E3F CALL PrintHandler_MaskParam Call PrintHandler_MaskParam to reset PrintState_Handler and mask B to the colour value.
8E42 LD A,($8004) A=*PrintState_Attr (current attribute byte).
8E45 AND %11000111 Clear the PAPER bits (C7 = keep INK, BRIGHT, FLASH).
8E47 SLA B Shift B left three positions to move the colour into bits 3–5.
8E49 SLA B
8E4B SLA B
8E4D OR B Write the new PAPER colour into bits 3–5.
8E4E LD ($8004),A Write the updated attribute byte back to *PrintState_Attr.
8E51 RET Return.
Set FLASH parameter handler. Called on the byte immediately following a 12 (FLASH) control code. Sets or clears bit 7 of the attribute byte at PrintState_Attr.
PrintHandler_Flash 8E52 LD B,$02 B=02 (mask limit: parameter is 00 or 01).
8E54 CALL PrintHandler_MaskParam Call PrintHandler_MaskParam to reset PrintState_Handler and mask B to 00 or 01.
8E57 BIT 0,B Test bit 0 of the masked parameter.
8E59 JR Z,PrintHandler_Flash_Off If the parameter is 00 jump to PrintHandler_Flash_Off to clear FLASH.
8E5B SET 7,(IX+$04) Set the FLASH bit (7) of the attribute byte at PrintState_Attr.
8E5F RET Return.
PrintHandler_Flash_Off 8E60 RES 7,(IX+$04) Clear the FLASH bit (7) of the attribute byte at 8004.
8E64 RET Return.
Set BRIGHT parameter handler. Called on the byte immediately following a 13 (BRIGHT) control code. Sets or clears bit 6 of the attribute byte at 8004.
PrintHandler_Bright 8E65 LD B,$02 B=02 (mask limit: parameter is 00 or 01).
8E67 CALL PrintHandler_MaskParam Call PrintHandler_MaskParam to reset PrintState_Handler and mask B to 00 or 01.
8E6A BIT 0,B Test bit 0 of the masked parameter.
8E6C JR Z,PrintHandler_Bright_Off If the parameter is 00 jump to PrintHandler_Bright_Off to clear BRIGHT.
8E6E SET 6,(IX+$04) Set the BRIGHT bit (6) of the attribute byte at 8004.
8E72 RET Return.
PrintHandler_Bright_Off 8E73 RES 6,(IX+$04) Clear the BRIGHT bit (6) of the attribute byte at 8004.
8E77 RET Return.
PRINT AT first parameter handler. Called on the byte immediately following a 16 (PRINT AT) control code. Stores the X (column) parameter to 8001 and installs PrintHandler_PrintAt_Y into PrintState_Handler to handle the next byte (the Y position).
PrintHandler_PrintAt_X 8E78 LD ($8001),A Write the X column parameter to *PrintState_X.
8E7B LD HL,$8E82 HL=PrintHandler_PrintAt_Y (Y position parameter handler).
8E7E LD ($800A),HL Write PrintHandler_PrintAt_Y to PrintState_Handler to consume the next (Y) byte.
8E81 RET Return.
PRINT AT second parameter handler. Called on the byte immediately following the X parameter. Wraps the Y (row) parameter at BC and stores it to 8000 before restoring the default handler.
PrintHandler_PrintAt_Y 8E82 LD HL,$8DE3 Reset PrintState_Handler to PrintHandler (default handler).
8E85 LD ($800A),HL
8E88 CP $BC If the Y parameter is less than BC jump to PrintHandler_PrintAt_Y_Store.
8E8A JR C,PrintHandler_PrintAt_Y_Store
8E8C SUB $BC Subtract BC to wrap the Y position.
PrintHandler_PrintAt_Y_Store 8E8E LD ($8000),A Write the Y position to *PrintState_Y.
8E91 RET Return.
TAB parameter handler. Called on the byte immediately following a 17 (TAB) control code. Sets the X position (8001) to the parameter value. If the parameter is less than the current X position (i.e., the cursor would move left), the Y position advances to the next row.
PrintHandler_Tab 8E92 LD HL,$8DE3 Reset PrintState_Handler to PrintHandler (default handler).
8E95 LD ($800A),HL
8E98 LD C,A C=target X position (the TAB parameter).
8E99 LD A,($8001) B=*PrintState_X (current X position).
8E9C LD B,A
8E9D LD A,C A=target X; write target X to *PrintState_X.
8E9E LD ($8001),A
8EA1 SUB B A=target X − current X.
8EA2 RET NC Return if the cursor moved right or stayed (no row advance needed).
8EA3 LD HL,$8000 HL=8000 (Y position pointer).
8EA6 CALL PrintHandler_AdvanceRow Call PrintHandler_AdvanceRow to advance the Y position by one line.
8EA9 RET Return.
Left margin parameter handler. Called on the byte immediately following a 18 control code. Sets the left margin X position at 8005 to the lower six bits of the parameter.
PrintHandler_LeftMargin 8EAA LD B,$40 B=40 (mask limit: lower six bits, 00–3F).
8EAC CALL PrintHandler_MaskParam Call PrintHandler_MaskParam to reset PrintState_Handler and mask A to the lower six bits.
8EAF LD ($8005),A Write the masked parameter to *PrintState_LeftMargin (left margin X position).
8EB2 RET Return.
Right margin parameter handler. Called on the byte immediately following a 19 control code. Stores the right margin X position to 8006. If the parameter is less than 80 a wrap flag is set in 8007 and 80 is OR'd into the value before storing.
PrintHandler_RightMargin 8EB3 LD HL,$8DE3 Reset PrintState_Handler to PrintHandler (default handler).
8EB6 LD ($800A),HL
8EB9 CP $80 If the parameter is 80 or higher, jump to PrintHandler_RightMargin_Store to store it directly.
8EBB JR NC,PrintHandler_RightMargin_Store
8EBD SET 0,(IX+$07) Set the wrap flag (bit 0 of *8007).
8EC1 OR %10000000 OR 80 into the parameter.
PrintHandler_RightMargin_Store 8EC3 LD ($8006),A Write the parameter to *PrintState_RightMargin (right margin X position).
8EC6 RET Return.
Select font parameter handler. Called on the byte immediately following a 1A control code. Copies the six-byte font configuration for the selected font index (00–03) from the table at FontConfig_Table into the font state at 800C and loads the font bitmap pointer into 8008.
PrintHandler_SelectFont 8EC7 LD B,$04 B=04 (mask limit: font indices 00–03).
8EC9 CALL PrintHandler_MaskParam Call PrintHandler_MaskParam to reset PrintState_Handler and mask B to the font index.
8ECC LD H,$00 H=00.
8ECE LD L,B L=B (font index as a 16-bit value in HL).
8ECF LD DE,$8FE6 DE=FontConfig_Table (font configuration table base).
Multiply the font index by 08 (the size of each font table entry) to compute the byte offset into the font table.
8ED2 ADD HL,HL Multiply HL by 08 (three left shifts).
8ED3 ADD HL,HL
8ED4 ADD HL,HL
8ED5 ADD HL,DE HL=FontConfig_Table + (font index × 08) — pointer to the selected font entry.
8ED6 LD DE,$800C DE=800C (font state destination).
8ED9 LD BC,$0006 BC=06 (six bytes of font configuration to copy).
8EDC LDIR Copy six bytes of font configuration to 800C–8011.
8EDE LD E,(HL) Read the two-byte font bitmap pointer from bytes 07–08 of the entry.
8EDF INC HL
8EE0 LD D,(HL)
8EE1 LD ($8008),DE Write the font bitmap pointer to *PrintState_FontPtr.
8EE5 RET Return.
Parameter mask and validation utility. Called by control code parameter handlers before processing their byte. Resets PrintState_Handler to the default handler (PrintHandler), then masks A to the valid range defined by B (which must be a power of two). If the parameter is out of range, sets a flag in 8007.
PrintHandler_MaskParam 8EE6 LD HL,$8DE3 Reset PrintState_Handler to PrintHandler (default handler).
8EE9 LD ($800A),HL
8EEC CP B Test whether the parameter (A) is within the valid range (B).
8EED JR C,PrintHandler_MaskParam_Mask If the parameter is within range, jump to PrintHandler_MaskParam_Mask.
8EEF SET 0,(IX+$07) Otherwise set the out-of-range flag (bit 0 of *8007).
PrintHandler_MaskParam_Mask 8EF3 DEC B Decrement B to form a bitmask (e.g. 08 → 07 = %00000111).
8EF4 AND B Mask A to the valid range.
8EF5 LD B,A B=masked parameter value.
8EF6 RET Return.
Character renderer. Determines the pixel width of the character, checks whether it fits on the current line (inserting a carriage return if not), computes the screen address from the current X and Y pixel positions, bit-shifts the character bitmap from the font table, ORs it into screen memory row by row, writes the attribute byte to the attribute area, and finally advances the X position.
PrintHandler_Render 8EF7 LD ($8003),A Store the character code to *PrintState_Char.
Select the pixel width for the character. Space (20), "I" (49), "M" (4D) and "W" (57) each have their own width stored in the font state at 800C. All other printable characters use the normal width.
8EFA CP $20 If the character is a space (20), jump to PrintHandler_Render_SpaceWidth.
8EFC JR Z,PrintHandler_Render_SpaceWidth
8EFE CP $49 If the character is not "I" (49), jump to PrintHandler_Render_WideCheck.
8F00 JR NZ,PrintHandler_Render_WideCheck
8F02 LD C,(IX+$0D) C=*PrintState_NarrowWidth (narrow width for "I").
8F05 JR PrintHandler_Render_LineCheck Jump to PrintHandler_Render_LineCheck.
PrintHandler_Render_SpaceWidth 8F07 LD C,(IX+$0F) C=*PrintState_SpaceWidth (space width).
8F0A JR PrintHandler_Render_LineCheck Jump to PrintHandler_Render_LineCheck.
Check for wide characters: "M" (4D) and "W" (57) use the wide width.
PrintHandler_Render_WideCheck 8F0C CP $4D If the character is "M" (4D), jump to PrintHandler_Render_WideWidth.
8F0E JR Z,PrintHandler_Render_WideWidth
8F10 CP $57 If the character is not "W" (57), jump to PrintHandler_Render_NormalWidth (normal width).
8F12 JR NZ,PrintHandler_Render_NormalWidth
PrintHandler_Render_WideWidth 8F14 LD C,(IX+$0E) C=*PrintState_WideWidth (wide width for "M" and "W").
8F17 JR PrintHandler_Render_LineCheck Jump to PrintHandler_Render_LineCheck.
All other printable characters use the standard (IX+0C) width.
PrintHandler_Render_NormalWidth 8F19 LD C,(IX+$0C) C=*PrintState_Width (normal character width).
Check whether the character fits within the right margin. If adding the character width to the current X position would exceed the right margin stored at 8006 a carriage return is inserted automatically before rendering.
PrintHandler_Render_LineCheck 8F1C LD A,($8001) B=*PrintState_X (current X position).
8F1F LD B,A
8F20 LD A,($8006) A=*PrintState_RightMargin (right margin X position).
8F23 SUB B A=right margin − current X − character width.
8F24 SUB C
8F25 CALL C,PrintHandler_Newline Call PrintHandler_Newline if the result is negative (character exceeds the right margin).
Calculate the screen address and sub-byte bit-shift from the current X and Y pixel positions. The screen row address LUT (indexed by Y) provides the base pixel row address; three right-shifts of X derive the column byte offset and the within-byte pixel shift (0–7 bits).
8F28 LD A,C A=character width.
8F29 EX AF,AF' Stash character width in A'.
8F2A LD A,($8000) A=*PrintState_Y (Y pixel position).
8F2D LD H,$46 HL=screen row address LUT entry for pixel row Y (8C00 + Y × 02).
8F2F LD L,A
8F30 SLA L
8F32 RL H
8F34 LD A,($8001) A=*PrintState_X (X pixel position).
8F37 AND A Clear carry; B=00; shift A right three positions with carry into B, deriving the column byte offset (A=X÷8) and sub-byte pixel bits (low 03 bits of X → B).
8F38 LD B,$00
8F3A RRA
8F3B RR B
8F3D RRA
8F3E RR B
8F40 RRA
8F41 RR B
8F43 RLC B Rotate B left three positions to place the sub-byte offset in bits 0–2.
8F45 RLC B
8F47 RLC B
8F49 LD C,A C=column byte offset (X÷8).
8F4A LD A,B Store the sub-byte pixel shift (X mod 8) to *PrintState_BitShift.
8F4B LD ($8002),A
8F4E LD DE,$8012 DE=8012 (screen address workspace).
8F51 LD B,(IX+$11) B=*PrintState_RowCount (number of character pixel rows).
PrintHandler_Render_AddrLoop 8F54 LD A,(HL) Read each two-byte screen row address from the LUT into the workspace at 8012 adding the column byte offset (C) to the first byte of each pair.
8F55 ADD A,C
8F56 LD (DE),A
8F57 INC DE
8F58 INC HL
8F59 LD A,(HL)
8F5A LD (DE),A
8F5B INC DE
8F5C INC HL
8F5D DJNZ PrintHandler_Render_AddrLoop Decrease the row counter and loop back to PrintHandler_Render_AddrLoop until all rows are done.
Look up the character bitmap in the font table. Each character occupies 08 bytes at font base pointer + (character code × 08).
8F5F LD A,($8003) A=*PrintState_Char (character code).
8F62 LD H,$00 HL=character code as a 16-bit value.
8F64 LD L,A
8F65 LD DE,($8008) DE=*PrintState_FontPtr (font bitmap base pointer).
8F69 ADD HL,HL HL=font base + (character code × 08).
8F6A ADD HL,HL
8F6B ADD HL,HL
8F6C ADD HL,DE
8F6D EX DE,HL DE=pointer to the character bitmap data.
8F6E LD HL,$8022 HL=8022 (bit-shift workspace).
8F71 LD C,(IX+$11) C=*PrintState_RowCount (number of character pixel rows).
PrintHandler_Render_ShiftLoop 8F74 LD A,($8002) B=*PrintState_BitShift (sub-byte pixel shift count); A=shift count.
8F77 LD B,A B=pixel shift count.
8F78 LD A,(DE) Copy one row of font bitmap data from *DE to *HL.
8F79 LD (HL),A
8F7A XOR A If the shift count is 00 jump to PrintHandler_Render_ShiftNext (no shift needed).
8F7B CP B
8F7C JR Z,PrintHandler_Render_ShiftNext
8F7E AND A Clear A (right-hand overflow byte).
PrintHandler_Render_ShiftStep 8F7F RR (HL) Shift *HL right through carry into A, repeating for each shift step.
8F81 RRA
8F82 DJNZ PrintHandler_Render_ShiftStep
PrintHandler_Render_ShiftNext 8F84 INC HL Advance HL to the second byte of the workspace pair.
8F85 LD (HL),A Store the shifted overflow byte (right-hand spill) to *HL.
8F86 INC HL Advance HL to the next row pair in the workspace.
8F87 INC DE Advance DE to the next row of font bitmap data.
8F88 DEC C Decrease the row counter.
8F89 JR NZ,PrintHandler_Render_ShiftLoop Loop back to PrintHandler_Render_ShiftLoop until all rows have been bit-shifted.
Write the attribute byte to the four attribute cells covering the character. Derives the attribute address from the screen pixel address high byte by rotating right three times, masking to two bits, and OR-ing with 58 ($5800 base).
8F8B LD BC,$8022 BC=8022 (bit-shifted bitmap workspace pointer).
8F8E LD HL,$8012 HL=8012 (screen address workspace pointer).
8F91 PUSH HL Stash HL; read the first screen address pair into DE.
8F92 LD E,(HL)
8F93 INC HL
8F94 LD D,(HL)
8F95 DEC HL Restore HL from the pair.
8F96 EX DE,HL DE=screen pixel row address.
8F97 LD A,H Derive the attribute memory high byte from the pixel address high byte.
8F98 RRCA
8F99 RRCA
8F9A RRCA
8F9B AND $03
8F9D OR $58 H=58 | column third → attribute address high byte.
8F9F LD H,A H=attribute address high byte.
8FA0 LD A,($8004) A=*PrintState_Attr (attribute byte: INK/PAPER/BRIGHT/FLASH).
8FA3 LD (HL),A Write the attribute byte to the two cells at *HL and *(HL+01).
8FA4 INC HL
8FA5 LD (HL),A
8FA6 LD DE,$001F DE=1F (offset to next attribute row).
8FA9 ADD HL,DE Write the attribute byte to the two cells in the attribute row below.
8FAA LD (HL),A
8FAB INC HL
8FAC LD (HL),A
8FAD POP HL Restore the screen address workspace pointer from the stack.
8FAE EXX Switch to shadow registers; B=*PrintState_RowCount (pixel row count).
8FAF LD B,(IX+$11)
PrintHandler_Render_BlitLoop 8FB2 EXX Switch back; DE=next two-byte screen address from 8012+.
8FB3 LD E,(HL)
8FB4 INC HL
8FB5 LD D,(HL)
8FB6 INC HL
8FB7 EX DE,HL DE=screen pixel row address.
8FB8 LD A,(BC) OR the left bitmap byte from *BC into *DE (left screen byte).
8FB9 OR (HL)
8FBA LD (HL),A
8FBB INC BC
8FBC INC HL Advance HL; OR the right bitmap byte from *BC into *(HL); advance BC.
8FBD LD A,(BC)
8FBE OR (HL)
8FBF LD (HL),A
8FC0 INC BC
8FC1 EX DE,HL DE=screen address workspace pointer (restore via EX DE,HL swap).
8FC2 EXX Switch to shadow registers and loop back to PrintHandler_Render_BlitLoop until all pixel rows are blitted to screen memory.
8FC3 DJNZ PrintHandler_Render_BlitLoop
Advance the X position by the character's pixel width and return.
8FC5 EXX Switch back to main registers; restore character width from A'.
8FC6 EX AF,AF'
8FC7 LD C,A C=character width.
8FC8 LD A,($8001) A=*PrintState_X (current X position).
8FCB ADD A,C A+=character width.
8FCC LD ($8001),A Write the new X position to *PrintState_X.
8FCF RET Return.
Prev: 8DCC Up: Map Next: 8FD0