OSBYTE 20; Cursor editing mode; Software scroll up/downwards; Exchange four VDU variables; Plot character at graphics cursor; Graphics cursor handling; MODE 7 character conversion; Setup soft character definitions - 872 bytes (5.3%)
- §1. Subtract the number of bytes in a row from AX
- §2. OSBYTE 20 - 'Explode' soft character definitions
- §3. moveTextCursorToNextLine
- §4. moveTextCursorToNextLineCursorEditing
- §5. incYCoordinate
- §6. Set up a write cursor
- §7. Restore a normal cursor
- §8. restoreWriteCursorNonMODE7
- §9. Software scroll text window downwards
- §10. exchangeTwoVDUBytes
- §11. exchangeGraphicsCursorWithOldPosition
- §12. exchangeFourBytes
- §13. exchangeABytes
- §14. Software scroll text window upwards
- §15. Copy bytes of one character row of the text window
- §16. checkVerticalTextWindowBoundsAndMoveToLeftColumn
- §17. setTextCursorToLeftHandColumn
- §18. copyCharacterLineOfTextWindow
- §19. clearOneLine
- §20. validatePositionAndSetupScreenAddress
- §21. Set text cursor screen addresses from X,Y position
- §22. Display a character at the current graphics cursor
- §23. graphicsCursorHome
- §24. setGraphicsCursorToLeftHandColumn
- §25. displayACharacter
- §26. displayACharacterAtAddress
- §27. displayCharacterMODE7
- §28. convertMODE7Character
- §29. displayACharacter4ColourMODE
- §30. nextPatternByte
- §31. displayACharacter16ColourMODE
- §32. Get character definition address
§1. Subtract the number of bytes in a row from AX.
On Entry: A = High byte of 16 bit value X = Low byte of 16 bit value
.subtractNumberOfBytesInARowFromAX = $ccf8 PHA store A TXA A=X SEC set carry for subtraction SBC .vduBytesPerCharacterRowLow bytes per character row TAX result goes into X PLA recall A SBC .vduBytesPerCharacterRowHigh bytes per character row CMP .vduStartScreenAddressHighByte high byte of screen RAM address .exit6 = $cd06 RTS
§2. OSBYTE 20 - 'Explode' soft character definitions.
This sets how much RAM is reserved for custom ('soft') character definitions. These areas of memory are sometimes known as 'font zones'. On Entry: X memory assigned character range notes 0 $0C00->$0CFF $80-$8F minimum memory assigned ('imploded') 1 OSHWM->OSHWM+$FF $A0-$BF includes allocations above 2 OSHWM+$100->OSHWM+$1FF $C0-$DF includes allocations above 3 OSHWM+$200->OSHWM+$2FF $E0-$FF includes allocations above 4 OSHWM+$300->OSHWM+$3FF $20-$3F includes allocations above 5 OSHWM+$400->OSHWM+$4FF $40-$5F includes allocations above 6 OSHWM+$500->OSHWM+$5FF $60-$7F includes allocations above Here OSHWM refers to the value of .defaultOSHWM, which holds the value of OSHWM before any font explosions.
.osbyte20EntryPoint = $cd07 LDA #%00001111 STA .vduFontFlags characters 160-255 have soft character definitions LDA #>.softCharacterDefinitions page for software character definitions LDY #.vduFontZoneAddressesHigh7 - .vduFontZoneAddressesHigh1 set loop counter - STA .vduFontZoneAddressesHigh1,Y set all font zone addresses (high byte) to $0C DEY to indicate the page available BPL - for user character definitions CPX #7 BCC + if (X < 7, i.e. parameter is in range) then branch LDX #6 X=6 + STX .softCharacterDefinitionsSwitch character definition explosion switch LDA .defaultOSHWM A = initial OSHWM value, before font explosions. LDX #0 X = 0, loop counter - CPX .softCharacterDefinitionsSwitch character definition explosion switch BCS + LDY .softCharacterRamAllocationTable,X Y = RAM allocation offset STA .vduFontZoneAddressesHigh1,Y store in relevant font zone address ADC #1 add 1 page (carry clear) INX X=X+1 BNE - if (X is not zero) then branch (loop back) + STA .currentOSHWM store new value of PAGE (OSHWM) TAY Y=A BEQ .exit6 if (zero) then branch (return) LDX #.romServiceCallFontImplosionExplosionWarning } issue ROM service call to let ROMs } know of the font explosion and JMP .osbyte143EntryPoint } to let languages know OSHWM } is changing. Y is new PAGE number
.moveTextCursorToNextLine = $cd3f LDA #2 A=2 to check if scrolling disabled BIT .vduStatusByte test VDU status byte BNE + if (scrolling is disabled) then branch BVC .exit8 if (cursor editing mode is disabled) then return + LDA .vduTextWindowBottom bottom edge of text window BCC + if (carry clear on entry) then branch LDA .vduTextWindowTop get top of text window + BVS .moveTextCursorToNextLineCursorEditing if (cursor editing mode enabled) then branch STA .vduTextCursorYPosition set current text line PLA pull return link from stack PLA JMP .setCursorSoftwareAndHardwarePosition set cursor position
§4. moveTextCursorToNextLineCursorEditing.
.moveTextCursorToNextLineCursorEditing = $cd59 PHP push flags CMP .vduTextInputCursorYCoordinate Y coordinate of text input cursor BEQ .pullAndExit if (A = line count) then branch (exit) PLP get back flags BCC .incYCoordinate DEC .vduTextInputCursorYCoordinate Y coordinate of text input cursor .exit7 = $cd65 RTS
.incYCoordinate = $cd66 INC .vduTextInputCursorYCoordinate Y coordinate of text input cursor RTS
When entering a line of text, if the user presses a cursor key then two cursors are shown: The WRITE cursor is shown at the point of text entry (looks like a solid block character), and is the position at which new characters will be input. The READ cursor (shown as a flashing underline) is positioned by the cursor keys. The COPY key reads the character under the READ cursor and enters it at WRITE cursor. Editing finishes when RETURN is pressed.
.setUpWriteCursor = $cd6a PHP save flags PHA save A LDY .vduBytesPerCharacter DEY Y = bytes per character - 1 BNE .restoreWriteCursorNonMODE7 if (not MODE 7) then branch LDA .vduMODE7CursorCharacter get MODE 7 write character cursor character $7F STA (.vduWriteCursorScreenAddressLow),Y store it at top scan line of current character .pullTwiceAndExit = $cd77 PLA pull A .pullAndExit = $cd78 PLP pull flags .exit8 = $cd79 RTS
.restoreWriteCursor = $cd7a PHP push flags PHA push A LDY .vduBytesPerCharacter DEY Y = bytes per character - 1 BNE .restoreWriteCursorNonMODE7 if (not MODE 7) then branch LDA (.vduWriteCursorScreenAddressLow),Y read from cursor screen address STA .vduMODE7CursorCharacter store it LDA .vduTeletextCharacterForCursor MODE 7 write cursor character STA (.vduWriteCursorScreenAddressLow),Y store it in MODE 7 screen address JMP .pullTwiceAndExit and exit
§8. restoreWriteCursorNonMODE7.
.restoreWriteCursorNonMODE7 = $cd8f LDA #$FF A=$FF (cursor byte mask) CPY #31 check bytes per character BNE + if (not MODE 2) then branch LDA #$3F A=$3F (cursor byte mask) + STA .vduTempStoreDA store it - LDA (.vduWriteCursorScreenAddressLow),Y get scan line byte EOR .vduTempStoreDA invert it STA (.vduWriteCursorScreenAddressLow),Y store it on scan line DEY decrement scan line counter BPL - do it again BMI .pullTwiceAndExit ALWAYS branch (pull and exit)
§9. Software scroll text window downwards.
.scrollTextWindowDownwards = $cda4 JSR .checkVerticalTextWindowBoundsAndMoveToLeftColumn LDA .vduTextWindowBottom bottom edge STA .vduTextCursorYPosition current text line JSR .setTextCursorScreenAddresses set cursor screen addresses .loopBackScrollDown = $cdb0 JSR .subtractNumberOfBytesInARowFromAX subtract bytes per character row BCS + ADC .vduScreenSizeHighByte screen RAM size high byte + STA .vduTempStoreDB store A STX .vduTempStoreDA X STA .vduTempStoreDC A again BCS .noWraparound if (C set; there was no wraparound) then branch - JSR .copyCharacterLineOfTextWindow copy line to new position using (.vduTempStoreDA) for read and (.vduWriteCursorScreenAddressLow) for write JMP + .noWraparound = $cdc6 JSR .subtractNumberOfBytesInARowFromAX subtract bytes per character row BCC - if (outside screen RAM) then branch JSR .copyCharacterRow copy a character row of the text window + LDA .vduTempStoreDC set write pointer from read pointer LDX .vduTempStoreDA STA .vduWriteCursorScreenAddressHigh STX .vduWriteCursorScreenAddressLow DEC .vduTempStoreDE decrement window height BNE .loopBackScrollDown if (not zero) then branch (loop back) .exchangeTextCursorPositionWithWorkspaceAB = $cdda LDX #.vduWorkspaceA - .vduVariablesStart point to workspace LDY #.vduTextCursorXPosition - .vduVariablesStart point to text column/line fall through...
.exchangeTwoVDUBytes = $cdde LDA #2 number of bytes to swap BNE .exchangeABytes ALWAYS branch. Exchange (.vduWorkspaceA/B)+Y with (.workspaceA/B)+X
§11. exchangeGraphicsCursorWithOldPosition.
.exchangeGraphicsCursorWithOldPosition = $cde2 LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart point to graphics cursor .exchangeOldGraphicsCursorPositionWithVariableX = $cde4 LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart point to last graphics cursor fall through...
.exchangeFourBytes = $cde6 LDA #4 A = 4 fall through...
.exchangeABytes = $cde8 STA .vduTempStoreDA store it as loop counter - LDA .vduVariablesStart,X get byte PHA store it LDA .vduVariablesStart,Y get byte pointed to by Y STA .vduVariablesStart,X put it in 300+X PLA get back A STA .vduVariablesStart,Y put it in 300+Y INX increment pointers INY DEC .vduTempStoreDA decrement loop counter BNE - if (not zero) then branch (loop back and do it again) RTS
§14. Software scroll text window upwards.
.scrollTextWindowUpwards = $cdff JSR .checkVerticalTextWindowBoundsAndMoveToLeftColumn LDY .vduTextWindowTop top of text window STY .vduTextCursorYPosition current text line JSR .setTextCursorScreenAddresses set cursor screen addresses .loopBackScrollUp = $ce0b JSR .addNumberOfBytesInACharacterRowToAX add bytes per character row BPL + SEC SBC .vduScreenSizeHighByte screen RAM size high byte + STA .vduTempStoreDB (.vduTempStoreDA)=X/A STX .vduTempStoreDA STA .vduTempStoreDC .vduTempStoreDC=A BCC + - JSR .copyCharacterLineOfTextWindow copy line to new position using (.vduTempStoreDA) for read and (.vduWriteCursorScreenAddressLow) for write JMP .finishScroll + JSR .addNumberOfBytesInACharacterRowToAX add bytes per char. row BMI - if (outside screen RAM) then branch JSR .copyCharacterRow copy a character row of the text window .finishScroll = $ce2a LDA .vduTempStoreDC LDX .vduTempStoreDA STA .vduWriteCursorScreenAddressHigh STX .vduWriteCursorScreenAddressLow DEC .vduTempStoreDE decrement window height BNE .loopBackScrollUp if (not zero) then branch (loop back) BEQ .exchangeTextCursorPositionWithWorkspaceAB ALWAYS branch - swap text cursor position with workspace
§15. Copy bytes of one character row of the text window.
On Entry: .vduTempStoreDA/DB is address to copy from .vduWriteCursorScreenAddressLow/High is the destination address .vduTextWindowWidthInBytesLow/High is number of bytes to copy
.copyCharacterRow = $ce38 LDX .vduTextWindowWidthInBytesHigh text window width high (bytes) BEQ + if (no more than 256 bytes to copy) then branch LDY #0 Y=0 to set loop counter - LDA (.vduTempStoreDA),Y } copy 256 bytes STA (.vduWriteCursorScreenAddressLow),Y } INY } BNE - } loop till Y=0 again INC .vduWriteCursorScreenAddressHigh increment high bytes INC .vduTempStoreDB DEX decrement window width BNE - if (not done yet) then branch (loop back) + LDY .vduTextWindowWidthInBytesLow text window width low (bytes) BEQ + if (text window is zero bytes wide) then branch (return) - DEY Y=Y-1 LDA (.vduTempStoreDA),Y copy Y bytes STA (.vduWriteCursorScreenAddressLow),Y TYA A=Y BNE - if (not done yet) then branch (loop back) + RTS
§16. checkVerticalTextWindowBoundsAndMoveToLeftColumn.
.checkVerticalTextWindowBoundsAndMoveToLeftColumn = $ce5b JSR .exchangeTextCursorPositionWithWorkspaceAB exchange text cursor position with workspaceAB SEC set carry LDA .vduTextWindowBottom bottom edge SBC .vduTextWindowTop top of text window STA .vduTempStoreDE store height of text area BNE .setTextCursorToLeftHandColumn set text column to left hand column PLA get back return address (to exit caller routine early) PLA JMP .exchangeTextCursorPositionWithWorkspaceAB exchange text cursor position with workspaceAB
§17. setTextCursorToLeftHandColumn.
.setTextCursorToLeftHandColumn = $ce6e LDA .vduTextWindowLeft text window left BPL .storeTextCursorXSetCarryAndReturn ALWAYS branch (set X window position)
§18. copyCharacterLineOfTextWindow.
.copyCharacterLineOfTextWindow = $ce73 LDA .vduTempStoreDA get back A PHA push A SEC set carry LDA .vduTextWindowRight text window right SBC .vduTextWindowLeft text window left STA .vduTempStoreDF store text window width -- LDY .vduBytesPerCharacter bytes per character to set loop counter DEY copy loop - LDA (.vduTempStoreDA),Y source: copy from .vduTempStoreDA/DB STA (.vduWriteCursorScreenAddressLow),Y destination: store to screen DEY BPL - keep copying for one character LDX #2 X=2 loop counter - CLC clear carry LDA .vduWriteCursorScreenAddressLow,X ADC .vduBytesPerCharacter move screen pointer on by bytes per character STA .vduWriteCursorScreenAddressLow,X and (when X=0) do the same with .vduTempStoreDA/DB LDA .vduWriteCursorScreenAddressHigh,X ADC #0 BPL + if (this remains in screen RAM OK) then branch SEC wrap around screen SBC .vduScreenSizeHighByte take off screen RAM size high byte + STA .vduWriteCursorScreenAddressHigh,X store high byte DEX X = X - 2 DEX BEQ - if (X = 0) then branch (loop back to adjust second set of pointers) DEC .vduTempStoreDF decrement text window width counter BPL -- if (still +ve) then branch (loop back and do it all again) PLA get back A STA .vduTempStoreDA and store it RTS
.clearOneLine = $ceac LDA .vduTextCursorXPosition text column PHA save it JSR .setTextCursorToLeftHandColumn set text column to left hand column JSR .setTextCursorScreenAddresses set cursor screen addresses SEC set carry LDA .vduTextWindowRight text window right SBC .vduTextWindowLeft text window left STA .vduTempStoreDC as window width -- LDA .vduBackgroundTextColour background text colour LDY .vduBytesPerCharacter bytes per character - DEY Y=Y-1 decrementing loop counter STA (.vduWriteCursorScreenAddressLow),Y store background colour at this point on screen BNE - if (Y is not zero) then branch (loop back) TXA A=X CLC clear carry to add ADC .vduBytesPerCharacter bytes per character TAX X=A restoring it LDA .vduWriteCursorScreenAddressHigh get high byte ADC #0 add carry if any BPL + if (+ve) then branch SEC wrap around SBC .vduScreenSizeHighByte screen RAM size high byte + STX .vduWriteCursorScreenAddressLow restore values STA .vduWriteCursorScreenAddressHigh DEC .vduTempStoreDC decrement window width BPL -- and if not 0 do it all again PLA get back A .storeTextCursorXSetCarryAndReturn = $cee3 STA .vduTextCursorXPosition restore text column .setCarryAndReturn = $cee6 SEC set carry RTS
§20. validatePositionAndSetupScreenAddress.
.validatePositionAndSetupScreenAddress = $cee8 LDX .vduTextCursorXPosition get text cursor X position CPX .vduTextWindowLeft test against left edge of text window BMI .setCarryAndReturn if (less than left edge) then branch (return with carry set) CPX .vduTextWindowRight test against right edge of text window BEQ + if (equal to right edge) then branch (thats OK) BPL .setCarryAndReturn if (greater than right edge) then branch (return with carry set) + LDX .vduTextCursorYPosition current text line CPX .vduTextWindowTop test against top edge of text window BMI .setCarryAndReturn if (less than top edge) then branch (return with carry set) CPX .vduTextWindowBottom test against bottom edge of text window BEQ .setTextCursorScreenAddresses if (equal to bottom edge) then branch (ok to set cursor screen addresses) BPL .setCarryAndReturn if (greater than bottom edge) then branch (return with carry set) fall through...
§21. Set text cursor screen addresses from X,Y position.
Let X,Y be the text cursor position (in absolute character cells from top left corner) MODE 0: address = screen_start + Y*640 + X* 8 MODE 1: address = screen_start + Y*640 + X*16 MODE 2: address = screen_start + Y*640 + X*32 MODE 3: address = screen_start + Y*640 + X* 8 MODE 4: address = screen_start + Y*320 + X* 8 MODE 5: address = screen_start + Y*320 + X*16 MODE 6: address = screen_start + Y*320 + X* 8 MODE 7: address = screen_start + Y* 40 + X Given the text cursor X,Y position, use the multiplication table and other characteristic values for the current MODE to calculate the address on screen. On Entry: .vduTextCursorX/YPosition stores the X,Y coordinates of the text cursor On Exit: Carry clear Stores the result in .vduTextCursorCRTCAddressLow/High, then wraps the address back on screen if beyond the bottom of the screen. Store the new wrapped result in .vduWriteCursorScreenAddressLow/High.
.setTextCursorScreenAddresses = $cf06 LDA .vduTextCursorYPosition current text line ASL multiply by two to get table offset TAY Y=A LDA (.vduMultiplicationTableLow),Y get CRTC multiplication table pointer STA .vduWriteCursorScreenAddressHigh .vduWriteCursorScreenAddressHigh=A INY Y=Y+1 LDA #2 A=2 AND .vduCurrentScreenMODEGroup AND with MODE group: 0 = 20k (MODE 0,1,2) 1 = 16k (MODE 3) 2 = 10k (MODE 4,5) 3 = 8k (MODE 6) 4 = 1k (MODE 7) PHP save flags LDA (.vduMultiplicationTableLow),Y get CRTC multiplication table pointer PLP pull flags BEQ + branch if MODE 0,1,2,3 or 7 LSR .vduWriteCursorScreenAddressHigh MODE 4,5,6: Halve value from multiplication table (high and low bytes) ROR A = A / 2 + (128*carry) + ADC .vduScreenTopLeftAddressLow add start of screen (low) STA .vduWriteCursorScreenAddressLow store LDA .vduWriteCursorScreenAddressHigh get offset from start of screen (high) ADC .vduScreenTopLeftAddressHigh add start of screen (high) TAY store in Y LDA .vduTextCursorXPosition text column LDX .vduBytesPerCharacter bytes per character DEX X=X-1 BEQ .mode7Cursor if (in MODE 7) then branch CPX #15 is it mode 1 or mode 5? (four colour modes = 16 bytes per character) BEQ .mode1or5Cursor if (mode 1 or 5) then branch (with carry set) BCC .mode0346Cursor if (mode 0,3,4, or 6) then branch (with carry clear) ASL A=A*16 if entered here (MODE 2) .mode1or5Cursor = $cf39 ASL A=A*8 if entered here .mode0346Cursor = $cf3a ASL A=A*4 if entered here ASL BCC .skipIncs if (carry clear) then branch INY Y=Y+2 INY Y is the high byte of the address .skipIncs = $cf40 ASL A=A*2 BCC .skipInc if (carry clear) branch (to add to .vduWriteCursorScreenAddressLow) INY Y=Y+1 .mode7Cursor = $cf44 CLC clear carry .skipInc = $cf45 ADC .vduWriteCursorScreenAddressLow add to .vduWriteCursorScreenAddressLow STA .vduWriteCursorScreenAddressLow and store it STA .vduTextCursorCRTCAddressLow text cursor CRTC address TAX X=A TYA A=Y ADC #0 add carry if set STA .vduTextCursorCRTCAddressHigh store the text cursor CRTC address (before any wraparound) BPL + if (not negative) then branch SEC wrap around... SBC .vduScreenSizeHighByte ...subtract the screen size (high byte) + STA .vduWriteCursorScreenAddressHigh store in high byte CLC clear carry RTS
§22. Display a character at the current graphics cursor.
.plotACharacterAtGraphicsCursor = $cf5d LDX .vduForegroundGraphicsColour foreground graphics colour LDY .vduForegroundGCOLMode foreground graphics GCOL mode .plotACharacterWithXYAsGraphicsColourAndGCOLMode = $cf63 JSR .setGraphicsColourMaskXY set graphics byte mask in .vduGraphicsColourByteOR/EOR JSR .copyGraphicsCursorPixelPositionToWorkspaceABCD copy graphics cursor in pixels to workspace (.vduWorkspaceA-D) LDY #0 Y=0 .displayNextRowOfCharacter = $cf6b STY .vduTempStoreDC .vduTempStoreDC=Y LDY .vduTempStoreDC Y=.vduTempStoreDC [redundant instruction] LDA (.vduTempStoreDE),Y get pattern byte BEQ .characterPatternZero if (A=0) then branch STA .vduTempStoreDD .vduTempStoreDD = 1 bit character pattern byte - BPL + if (pattern's top bit is clear) then branch (nothing to draw) JSR .plotAPixelInACharacter display a pixel + INC .vduGraphicsCursorPixelsXLow current horizontal graphics cursor BNE + INC .vduGraphicsCursorPixelsXHigh current horizontal graphics cursor + ASL .vduTempStoreDD shift the bit pattern left to draw next pixel BNE - if (there's still something left to draw) then branch (loop back) .characterPatternZero = $cf86 LDX #.vduWorkspaceA - .vduVariablesStart source is workspace LDY #.vduGraphicsCursorPixelsXLow - .vduVariablesStart destination is horizontal graphics cursor pixel position JSR .copyTwoBytesWithinVDUVariables copy two bytes LDY .vduGraphicsCursorPixelsYLow } BNE + } DEC .vduGraphicsCursorPixelsYHigh } decrement graphics cursor Y pixel } position + } DEC .vduGraphicsCursorPixelsYLow } LDY .vduTempStoreDC loop counter INY CPY #8 BNE .displayNextRowOfCharacter if (Y<8) then branch (loop back) LDX #.vduWorkspaceA - .vduVariablesStart source: workspaceA-D LDY #.vduGraphicsCursorPixelsXLow - .vduVariablesStart destination: graphics cursor position JMP .copyFourBytesWithinVDUVariables copy to graphics cursor position
.graphicsCursorHome = $cfa6 LDX #.vduGraphicsWindowPixelsTopLow - .vduVariablesStart source bytes (graphics window top) LDY #.vduGraphicsCursorPixelsYLow - .vduVariablesStart destination bytes (graphics cursor Y) JSR .copyTwoBytesWithinVDUVariables copy two bytes fall through...
§24. setGraphicsCursorToLeftHandColumn.
.setGraphicsCursorToLeftHandColumn = $cfad LDX #.vduGraphicsWindowPixelsLeftLow - .vduVariablesStart source: left edge of graphics window LDY #.vduGraphicsCursorPixelsXLow - .vduVariablesStart destination: graphics cursor X coordinate JSR .copyTwoBytesWithinVDUVariables copy two bytes JMP .convertPixelGraphicsCoordinatesToExternal set up external coordinates for graphics
.displayACharacter = $cfb7 LDX .vduNumberOfLogicalColoursMinusOne number of logical colours less 1 BEQ .displayCharacterMODE7 if (MODE 7) then branch JSR .getCharacterDefinitionAddress set up character definition pointers fall through...
§26. displayACharacterAtAddress.
.displayACharacterAtAddress = $cfbf LDX .vduNumberOfLogicalColoursMinusOne number of logical colours less 1 LDA .vduStatusByte VDU status byte AND #$20 and check bit 5 (printing at graphics cursor) BNE .plotACharacterAtGraphicsCursor if (set) then branch LDY #7 Y=7 CPX #3 BEQ .displayACharacter4ColourMODE if (X = 3) then branch to handle 4 colour MODEs BCS .displayACharacter16ColourMODE if (X > 3) then branch to deal with 16 colours display a character in a 2 colour MODE - LDA (.vduTempStoreDE),Y get pattern byte ORA .vduTextColourByteOR adjust for current foreground and background colour EOR .vduTextColourByteEOR adjust for current foreground and background colour STA (.vduWriteCursorScreenAddressLow),Y write to screen DEY Y=Y-1 BPL - if (still +ve) then branch (loop back) RTS
.displayCharacterMODE7 = $cfdc LDY #2 Y=2, loop counter/index into the teletext conversion table - CMP .teletextCharacterConversionTable,Y compare with teletext conversion table BEQ .convertMODE7Character if (found character to convert) then branch DEY Y=Y-1 BPL - loop back until done .writeByteToMODE7Screen = $cfe6 STA (.vduWriteCursorScreenAddressLow,X) write byte to screen RTS
.convertMODE7Character = $cfe9 LDA .teletextCharacterConversionTable + 1,Y convert with teletext conversion table BNE .writeByteToMODE7Screen ALWAYS branch back to write it
§29. displayACharacter4ColourMODE.
.displayACharacter4ColourMODE = $cfee LDA (.vduTempStoreDE),Y get pattern byte PHA save it LSR move high nybble to low LSR LSR LSR TAX X=A LDA .fourColourMODEByteMaskTable,X convert 4 bits of the character definition into bytes to write to the screen ORA .vduTextColourByteOR adjust for current foreground and background colour EOR .vduTextColourByteEOR adjust for current foreground and background colour STA (.vduWriteCursorScreenAddressLow),Y write to screen TYA A=Y CLC clear carry ADC #8 add 8 to move screen RAM pointer 8 bytes TAY Y=A PLA get back A AND #%00001111 clear high nybble TAX X=A LDA .fourColourMODEByteMaskTable,X 4 colour MODE byte mask look up table ORA .vduTextColourByteOR adjust for current foreground and background colour EOR .vduTextColourByteEOR adjust for current foreground and background colour STA (.vduWriteCursorScreenAddressLow),Y write to screen TYA A=Y SBC #8 A=A-9 TAY Y=A BPL .displayACharacter4ColourMODE if (not negative) then branch (loop back) .exit9 = $d017 RTS
.nextPatternByte = $d018 TYA Y=Y-$21 SBC #$21 BMI .exit9 if (Y is negative) then branch (return) TAY A=Y fall through...
§31. displayACharacter16ColourMODE.
.displayACharacter16ColourMODE = $d01e LDA (.vduTempStoreDE),Y get pattern byte STA .vduTempStoreDC store it SEC set carry .iloop = $d023 LDA #0 A=0 ROL .vduTempStoreDC carry now occupies bit 0 of DC BEQ .nextPatternByte when DC=0 again branch to deal with next pattern byte ROL get bit 7 from .vduTempStoreDC into A bit 0 ASL .vduTempStoreDC rotate again to get second ROL bit into A TAX and store result in X LDA .sixteenColourMODEByteMaskTable,X convert two bits of the character definition into bytes to write to the screen ORA .vduTextColourByteOR adjust for current foreground and background colour EOR .vduTextColourByteEOR adjust for current foreground and background colour STA (.vduWriteCursorScreenAddressLow),Y and store result CLC } TYA } ADC #8 } Y=Y+8 moving screen RAM pointer on } 8 bytes TAY } BCC .iloop branch back to deal with next bit pair fall through...
§32. Get character definition address.
On Entry: A is the ascii code for a printable character 32-255 (bit pattern abcdefgh) On Exit: .vduTempStoreDE/F is the address of the character definition either from the default ROM characters or the soft character definitions
.getCharacterDefinitionAddress = $d03e ASL bcdefgh0 C=a ROL cdefgh0a C=b ROL defgh0ab C=c STA .vduTempStoreDE save this pattern (defgh0ab) AND #%00000011 000000ab ROL 00000abc C=0 TAX X = soft font zone (1 - 7) AND #%00000011 A = 000000bc (1 - 3) ADC #>.characterDefinitions - 1 A = high byte of character definitions ($C0, $C1, $C2) TAY Y = high byte of ROM address of character LDA .fontMaskTable,X get single bit set depending on X (1-7) BIT .vduFontFlags test font flags to see if there are soft character definitions BEQ + if (hard character definitions) then branch LDY .vduFontZoneAddressesHigh1 - 1,X get high byte from table for soft character definitions + STY .vduTempStoreDF store Y in high byte of address LDA .vduTempStoreDE get back pattern (defgh0ab) AND #%11111000 defgh000 STA .vduTempStoreDE and store it. This is 8 times the ASCII character giving the low byte of the address RTS