From a90a4f0a7214aa6784f2da9240be58467df5a2b9 Mon Sep 17 00:00:00 2001 From: Michaelangel007 Date: Wed, 27 Jan 2016 12:07:54 -0800 Subject: [PATCH] Align up assembly source columns --- README.md | 515 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 270 insertions(+), 245 deletions(-) diff --git a/README.md b/README.md index 256766d..a0680a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ #Apple ]\[ //e HGR Font 6502 Assembly Language Tutorial -Revision: 49, Jan 27, 2016. +Revision: 50, Jan 27, 2016. # Table of Contents @@ -23,6 +23,7 @@ Revision: 49, Jan 27, 2016. * X Cursor Position * CursorCol() * Introduction to Optimization + * Recap - Listing 5 * DrawChar() version 2 * DrawChar() version 3 * Character Inspector @@ -35,7 +36,7 @@ Revision: 49, Jan 27, 2016. * Exercises * Exercise 1: ScrollHgrUpLine() * Exercise 2: ScrollHgrUpPixel() -* Recap +* Recap - Font Draw * Other Fonts * Fat Stroke Fonts * Beautiful Boot @@ -705,23 +706,25 @@ Before we can start a simple `DrawChar(char c)` function, we also first need to Here's the disassembly of our (hard-coded) DrawChar() program: +Listing Demo 1: + ```assembly ; FUNC: PrintChar() ; NOTES: A, X, Y is destroyed - ORG $0900 - 0900: PrintChar - 0900:20 0A 09 JSR HgrToTmpPtr - 0903:A9 00 LDA #00 ; glyph 'c' to draw (not used yet) - 0905:A0 00 LDY #00 ; Y = column to draw at (hard-coded) - 0907:4C 10 03 JMP DrawChar + ORG $0900 + 0900: PrintChar + 0900:20 0A 09 JSR HgrToTmpPtr + 0903:A9 00 LDA #00 ; glyph 'c' to draw (not used yet) + 0905:A0 00 LDY #00 ; Y = column to draw at (hard-coded) + 0907:4C 10 03 JMP DrawChar ; FUNC: HgrToTmpPtr() - 090A: HgrToTmpPtr - 090A:A5 E5 LDA HgrLo ; Copy initial screen - 090C:85 F5 STA TmpLo ; destination pointer - 090E:A5 E6 LDA HgrHi ; to working pointer - 0910:85 F6 STA TmpHi - 0912:60 RTS + 090A: HgrToTmpPtr + 090A:A5 E5 LDA HgrLo ; Copy initial screen + 090C:85 F5 STA TmpLo ; destination pointer + 090E:A5 E6 LDA HgrHi ; to working pointer + 0910:85 F6 STA TmpHi + 0912:60 RTS ``` Listing 1: @@ -733,14 +736,14 @@ Listing 1: ; INPUT : $F5,$F6 pointer to the destination screen scanline ; Must start at every 8 scanlines. ; OUTPUT: The Y-Register (cursor column) is automatically incremented. - ORG $0310 - 0310: DrawChar - 0310:4C 50 03 JMP _DrawChar + ORG $0310 + 0310: DrawChar + 0310:4C 50 03 JMP _DrawChar ORG $0350 - 0350: _DrawChar + 0350: _DrawChar 0350:A2 00 LDX #0 - 0352: _LoadFont ; A = font[ offset ] + 0352: _LoadFont ; A = font[ offset ] 0352:BD 00 62 LDA Font+$200,X 0355:91 F5 STA (TmpLo),Y ; screen[col] = A 0357:18 CLC @@ -832,7 +835,7 @@ Here's the C pseudo-code of the assembly code: Since the Y-register controls the column we can inline this function and have the caller take care of setting the Y-Register before calling DrawChar(). -```assmebly +```assembly LDY #column ``` @@ -851,14 +854,14 @@ Listing 2a: ; Increment the cursor column and move the destination screen pointer back ; up 8 scan lines previously to what it was when DrawChar() was called. ; Version 1 - ORG $0364 - 0364: IncCursorCol1 - 0364:C8 INY - 0365:18 CLC ; Note: - 0366:A5 F6 LDA TmpHi ; (To the astute reader) - 0368:E9 1F SBC #$1F ; <-- ??? Shouldn't this be #$20 ?! - 036A:85 F6 STA TmpHi - 036C:60 RTS + ORG $0364 + 0364: IncCursorCol1 + 0364:C8 INY + 0365:18 CLC ; Note: + 0366:A5 F6 LDA TmpHi ; (To the astute reader) + 0368:E9 1F SBC #$1F ; <-- ??? Shouldn't this be #$20 ?! + 036A:85 F6 STA TmpHi + 036C:60 RTS ``` ### Introduction to Optimization @@ -881,13 +884,13 @@ Listing 2b: ; up 8 scan lines previously to what it was when DrawChar() was called. ; Version 2 ORG $0364 - 0364: IncCursorCol2 - 0364:C8 INY - 0365:38 SEC ; CLC SBC #1F - 0366:A5 F6 LDA TmpHi ; was not obvious that we really - 0368:E9 20 SBC #$20 ; meant: TmpHi = A - #$20 !! - 036A:85 F6 STA TmpHi - 036C:60 RTS + 0364: IncCursorCol2 + 0364:C8 INY + 0365:38 SEC ; CLC SBC #1F + 0366:A5 F6 LDA TmpHi ; was not obvious that we really + 0368:E9 20 SBC #$20 ; meant: TmpHi = A - #$20 !! + 036A:85 F6 STA TmpHi + 036C:60 RTS ``` One thing when writing 6502 assembly is to pay attention to _all_ optimization opportunities due to the slow ~1 MHz of the 6502. Since we only need to modify the upper few bits instead of doing a bulky subtraction `SEC SBC` we might be tempted to see if there is a faster and/or smaller alternative. We just need to be careful that our optimization is "shuffling" the bits around _behaves_ in the _exact_ same way at the end of the day. i.e. "The Right Place at the Right Time." @@ -944,13 +947,13 @@ Listing 3a: ; up 8 scan lines previously to what it was when DrawChar() was called. ; Version 3a ORG $0364 - 0364: IncCursorCol3 - 0364:C8 INY - 0365:A5 F6 LDA TmpHi - 0367:29 1F AND #%00011111 ; Requires an extra OR - 0369:09 20 ORA #$20 ; Hard-code to HGR page 1 (high byte) - 036B:85 F6 STA TmpHi - 036D:60 RTS + 0364: IncCursorCol3 + 0364:C8 INY + 0365:A5 F6 LDA TmpHi + 0367:29 1F AND #%00011111 ; Requires an extra OR + 0369:09 20 ORA #$20 ; Hard-code to HGR page 1 (high byte) + 036B:85 F6 STA TmpHi + 036D:60 RTS ``` @@ -982,13 +985,13 @@ Listing 3b: ; up 8 scan lines previously to what it was when DrawChar() was called. ; Version 3b ORG $0364 - 0364: IncCursorCol3 - 0364:C8 INY - 0365:A5 F6 LDA TmpHi - 0367:29 1F AND #%00011111 ; Requires an extra OR - 0369:05 E6 ORA HgrHi ; user specified Page 1 or Page 2 - 036B:85 F6 STA TmpHi - 036D:60 RTS + 0364: IncCursorCol3 + 0364:C8 INY + 0365:A5 F6 LDA TmpHi + 0367:29 1F AND #%00011111 ; Requires an extra OR + 0369:05 E6 ORA HgrHi ; user specified Page 1 or Page 2 + 036B:85 F6 STA TmpHi + 036D:60 RTS ``` At least the timing for `ORA HgrHi` is still 2 clock cycles. :-) @@ -1019,11 +1022,11 @@ Listing 4a: ;35F:E0 08 CPX #8 ;361:D0 EF BNE _LoadFont ;363:60 RTS - ; ; === DrawChar end === + ; === DrawChar end === ; FUNC: IncCursorCol() ORG $0363 ; intentional extend _DrawChar by - 0363: IncCursorCol ; over-writing RTS + 0363: IncCursorCol ; over-writing RTS 0363:C8 INY 0364:A6 FD LDX TopHi ; Move cursor back to top of scanline 0366:86 F6 STX TmpHi @@ -1035,20 +1038,20 @@ We just need to touch up our entry point `PrintChar` at $0310 instead of calling Listing 4b: ```assembly - ORG $0310 - 0310: DrawChar - 0310:4C 4C 03 JMP _DrawChar1 ; NEW entry point + ORG $0310 + 0310: DrawChar + 0310:4C 4C 03 JMP _DrawChar1 ; NEW entry point ``` -Listing 5: +Listing Demo 2: ```assembly - ORG $0A00 - 0A00: DemoDraw3Char - 0A00:20 00 09 JSR PrintChar - 0A03:20 10 03 JSR DrawChar - 0A06:20 10 03 JMP DrawChar - 0A09:60 RTS + ORG $0A00 + 0A00: DemoDraw3Char + 0A00:20 00 09 JSR PrintChar + 0A03:20 10 03 JSR DrawChar + 0A06:20 10 03 JMP DrawChar + 0A09:60 RTS ``` Enter in: @@ -1078,7 +1081,7 @@ We are one step closer to printing a string. We have a total of 5 `@` because w
-# Recap - Listing 4 +## Recap - Listing 5 Here is what our render glyph code looks like so far: @@ -1238,77 +1241,79 @@ IF this is confusing, remember, we are calculating a 16-bit offset: A naive 6502 glyph/32 calculation would be to use 5 shift right bit-shifts: ```assembly - 48 PHA ; save c - -- -- ; calc low byte offset - 68 PLA ; pop c = %PQRstuvw to draw - 4A LSR ; c / 2 = %0PQRstuv C=w - 4A LSR ; c / 4 = %w0PQRstu C=V - 4A LSR ; c / 8 = %wv0PQRst C=u - 4A LSR ; c / 16 = %uvw0PQRs C=t - 4A LSR ; c / 32 = %tUvw0PQR C=s - 29 07 AND #07 ; = %00000PQR - 18 CLC ; + 48 PHA ; save c + -- -- ; calc low byte offset + 68 PLA ; pop c = %PQRstuvw to draw + 4A LSR ; c / 2 = %0PQRstuv C=w + 4A LSR ; c / 4 = %w0PQRstu C=V + 4A LSR ; c / 8 = %wv0PQRst C=u + 4A LSR ; c / 16 = %uvw0PQRs C=t + 4A LSR ; c / 32 = %tUvw0PQR C=s + 29 07 AND #07 ; = %00000PQR + 18 CLC ; ``` We can optimize the `CLC` out by clearing the bottom bits and _then_ doing the shift: ```assembly - 48 PHA ; save c - -- -- ; calc low byte offset - 68 PLA ; pop c = %PQRstuvw to draw - 29 E0 AND #E0 ; = %PQR00000 s=0, Optimization: implicit CLC - 4A LSR ; c / 2 = %0PQR0000 - 4A LSR ; c / 4 = %00PQR000 - 4A LSR ; c / 8 = %000PQR00 - 4A LSR ; c / 16 = %0000PQR0 - 4A LSR ; c / 32 = %00000PQR + 48 PHA ; save c + -- -- ; calc low byte offset + 68 PLA ; pop c = %PQRstuvw to draw + 29 E0 AND #E0 ; = %PQR00000 s=0, Optimization: implicit CLC + 4A LSR ; c / 2 = %0PQR0000 + 4A LSR ; c / 4 = %00PQR000 + 4A LSR ; c / 8 = %000PQR00 + 4A LSR ; c / 16 = %0000PQR0 + 4A LSR ; c / 32 = %00000PQR ``` However we can save one instruction (and 2 cycles) if we optimize `c/32` to use the counter-intuitive 6502's `ROL` instruction -- which only requires 4 instructions instead: ```assembly - 48 PHA ; save c - -- -- ; calc low byte offset - 68 PLA ; pop c = %PQRstuvw to draw - 29 E0 AND #E0 ; = %PQR00000 s=0, Optimization: implicit CLC - 2A ROL ; = %QR000000 C=P - 2A ROL ; = %R000000P C=Q - 2A ROL ; = %000000PQ C=R - 2A ROL ; c / 32 = %00000PQR C=0 + 48 PHA ; save c + -- -- ; calc low byte offset + 68 PLA ; pop c = %PQRstuvw to draw + 29 E0 AND #E0 ; = %PQR00000 s=0, Optimization: implicit CLC + 2A ROL ; = %QR000000 C=P + 2A ROL ; = %R000000P C=Q + 2A ROL ; = %000000PQ C=R + 2A ROL ; c / 32 = %00000PQR C=0 ``` Our prefix code to setup the source address becomes: +Listing 6: + ```assembly ; FUNC: _DrawChar2a( c, col ) ; PARAM: A = glyph to draw ; PARAM: Y = column to draw at; $0 .. $27 (Columns 0 .. 39) (not modified) ; NOTES: X is destroyed - ORG $0335 - 0335: _DrawChar2a - 0335:48 PHA ; push c = %PQRstuvw to draw - 0336:29 1F AND #1F ; = %000stuvw R=0, implicit CLC - 0338:0A ASL ; c * 2 %00stuvw0 - 0339:0A ASL ; c * 4 %0stuvw00 - 033A:0A ASL ; c * 8 %stuvw000 - 033B:69 00 ADC #Font ; += FontHi; Carry = 0 since S=0 from above - 0349:8D 54 03 STA _LoadFont+2; AddressHi = FontHi + (c/32) - ; intentional fall into _DrawChar1 - 034C: _DrawChar1 - 034C:A6 F6 LDX TmpHi - 034E:86 FD STX TopHi - 0350: _DrawChar - 0350:A2 00 LDX #0 ; Note: next instruction is self-modified ! - 0352: _LoadFont ; A = font[ offset ] - 0352:BD 00 00 LDA $0000,X + ORG $0335 + 0335: _DrawChar2a + 0335:48 PHA ; push c = %PQRstuvw to draw + 0336:29 1F AND #1F ; = %000stuvw R=0, implicit CLC + 0338:0A ASL ; c * 2 %00stuvw0 + 0339:0A ASL ; c * 4 %0stuvw00 + 033A:0A ASL ; c * 8 %stuvw000 + 033B:69 00 ADC #Font ; += FontHi; Carry = 0 since S=0 from above + 0349:8D 54 03 STA _LoadFont+2; AddressHi = FontHi + (c/32) + ; intentional fall into _DrawChar1 + 034C: _DrawChar1 + 034C:A6 F6 LDX TmpHi + 034E:86 FD STX TopHi + 0350: _DrawChar + 0350:A2 00 LDX #0 ; Note: next instruction is self-modified ! + 0352: _LoadFont ; A = font[ offset ] + 0352:BD 00 60 LDA Font,X ``` Did you catch that **note** ? One popular trick on the 6502 was `self-modifying code`. Instead of wasting memory with yet-another-variable we directly change the load/store instructions themselves! This actually has 2 advantages: @@ -1368,21 +1373,21 @@ We would need to start with the carry **pre-loaded** with P, and the QR already That might look like something like this: ```assembly - PHA ; push c + PHA ; push c AND #$E0 - TAX ; save %PQR00000 - PLA ; pop c + TAX ; save %PQR00000 + PLA ; pop c AND #$1F - STA Temp ; save %000stuvw - TXA ; A=PQR00000 - ASL ; C=P A=QR000000 <- stuvw not taking advantage of shift :-( - OR Temp ; C=P A=QR0stuvw - ROL ; C=Q A=R0stuvwP - ROL ; C=R A=0stuvwPQ - ROL ; C=0 A=stuvwPQR + STA Temp ; save %000stuvw + TXA ; A=PQR00000 + ASL ; C=P A=QR000000 <- stuvw not taking advantage of shift :-( + OR Temp ; C=P A=QR0stuvw + ROL ; C=Q A=R0stuvwP + ROL ; C=R A=0stuvwPQ + ROL ; C=0 A=stuvwPQR PHA - AND #1F ; = %000stuvw - STA _LoadFont+1; AddressLo = FontLo + (c*8) + AND #1F ; = %000stuvw + STA _LoadFont+1 ; AddressLo = FontLo + (c*8) PLA AND #E0 CLC @@ -1411,26 +1416,26 @@ The **lateral** thinking is to _use partial results_. Let's code this up: -Listing 6: +Listing 7: ```Assembly ; FUNC: DrawCharCol( c, col ) alias _DrawChar2 ; PARAM: A = glyph to draw ; PARAM: Y = column to draw at; $0 .. $27 (Columns 0 .. 39) (not modified) ; NOTES: X is destroyed - ORG $033A - 033A: DrawCharCol ; A=%PQRstuvw - 033A:2A ROL ; C=P A=%QRstuvw? - 033B:2A ROL ; C=Q A=%Rstuvw?P - 033C:2A ROL ; C=R A=%stuvw?PQ - 033D:AA TAX ; X=%stuvw?PQ push glyph - 033E:29 F8 AND #F8 ; A=%stuvw000 - 0340:8D 53 03 STA _LoadFont+1; AddressLo = (c*8) - 0343:8A TXA ; A=%stuvw?PQ pop glyph - 0344:29 03 AND #3 ; Optimization: s=0 implicit CLC ! - 0346:2A ROL ; C=s A=%00000PQR and 1 last ROL to get R - 0347:69 60 ADC #>Font ; += FontHi; Carry=0 since s=0 from above - 0349:8D 54 03 STA _LoadFont+2; AddressHi = FontHi + (c/32) + ORG $033A + 033A: DrawCharCol ; A=%PQRstuvw + 033A:2A ROL ; C=P A=%QRstuvw? + 033B:2A ROL ; C=Q A=%Rstuvw?P + 033C:2A ROL ; C=R A=%stuvw?PQ + 033D:AA TAX ; X=%stuvw?PQ push glyph + 033E:29 F8 AND #F8 ; A=%stuvw000 + 0340:8D 53 03 STA _LoadFont+1 ; AddressLo = (c*8) + 0343:8A TXA ; A=%stuvw?PQ pop glyph + 0344:29 03 AND #3 ; Optimization: s=0 implicit CLC ! + 0346:2A ROL ; C=s A=%00000PQR and 1 last ROL to get R + 0347:69 60 ADC #>Font ; += FontHi; Carry=0 since s=0 from above + 0349:8D 54 03 STA _LoadFont+2 ; AddressHi = FontHi + (c/32) ; intentional fall into _DrawChar1 @ $034C ``` @@ -1509,13 +1514,16 @@ We now have the ability to print any of the 128 ASCII characters! Let's verify this by writing a character inspector. We'll use the arrow keys to select the glyph and ESC to exit. -Listing Demo2a: +Listing Demo 3a: ```assembly ; FUNC: DemoCharInspect() - KEYBOARD EQU $C000 - KEYSTROBE EQU $C010 - glyph EQU $FE + HgrLo EQU $F5 + HgrHi EQU $F6 + glyph EQU $FE + + KEYBOARD EQU $C000 + KEYSTROBE EQU $C010 ORG $1000 1000: DemoCharInspect @@ -1578,46 +1586,52 @@ We now have an ASCII char inspector! Let's fix it up to print the hex value of the current character we are inspecting: -Listing Demo2b: +Listing Demo 3b: ```assembly - ORG $1010 - 1010:20 3C 10 JSR Patch1 + ORG $1010 + 1010:20 3C 10 JSR Patch1 - ORG $1037 - 103C: Patch1 - 103C:48 PHA ; save c - 103D:20 10 03 JSR DrawChar - 1040:68 PLA ; restore c so we can print it in hex - 1041:4C 01 03 JMP DrawHexByte + ORG $1037 + 103C: Patch1 + 103C:48 PHA ; save c + 103D:20 10 03 JSR DrawChar + 1040:68 PLA ; restore c so we can print it in hex + 1041:4C 01 03 JMP DrawHexByte +``` - ORG $0303 +Listing 8: + +```assembly + ORG $0303 ; FUNC: DrawHexByte( c ) = $0301 ; PARAM: A = byte to print in hex - 0301: DrawHexByte - 0301:48 PHA ; save low nibble - 0302:6A ROR ; shift high nibble - 0303:6A ROR ; to low nibble - 0304:6A ROR - 0305:6A ROR - 0306:20 0A 03 JSR DrawHexNib ; print high nib in hex - 0309:68 PLA ; pritn low nib in hex + 0301: DrawHexByte + 0301:48 PHA ; save low nibble + 0302:6A ROR ; shift high nibble + 0303:6A ROR ; to low nibble + 0304:6A ROR ; + 0305:6A ROR ; + 0306:20 0A 03 JSR DrawHexNib ; print high nib in hex + 0309:68 PLA ; pritn low nib in hex ; FUNC: DrawHexNib() = $030C ; PARAM: A = nibble to print as hex char - 030A: DrawHexNib - 030A:29 0F AND #F ; base 16 - 030C:AA TAX ; - 030D:BD 90 03 LDA NIB2HEX,X ; nibble to ASCII - ; intentional fall into PrintChar - - ORG $0390 - 0390:30 31 32 33 NIB2HEX ASC "0123456789ABCDEF" + 030A: DrawHexNib + 030A:29 0F AND #F ; base 16 + 030C:AA TAX ; + 030D:BD 90 03 LDA NIB2HEX,X ; nibble to ASCII + ; intentional fall into PrintChar + ORG $0390 + 0390:30 31 32 33 NIB2HEX ASC "0123456789ABCDEF" 0394:34 35 36 37 0398:38 39 41 42 039C:43 44 45 46 ``` +Q. Can you see a way to make DrawHexNib smaller? + + Enter in the changes: 1010:20 3C 10 @@ -1648,17 +1662,17 @@ And now we have our own DrawHexByte() function. Let's add a space after the character but before the hex value to improve readability of the output. The new code is: -Listing Demo2c: +Listing Demo 3c: ```assembly - ORG $1010 - 1010:20 37 10 JSR Patch2 + ORG $1010 + 1010:20 37 10 JSR Patch2 - ORG $1037 - 1037: Patch2 - 1037:48 PHA ; save c - 1038:20 10 03 JSR PrintChar - 103B:A9 20 LDA ' ' ; Draw whitespace + ORG $1037 + 1037: Patch2 + 1037:48 PHA ; save c + 1038:20 10 03 JSR PrintChar + 103B:A9 20 LDA ' ' ; Draw whitespace ``` Enter in these changes: @@ -1754,6 +1768,7 @@ Our `HgrHiY` table: 03C0:00 00 01 01 02 02 03 03 03C8:00 00 01 01 02 02 03 03 +
**AppleWin** users: To save this press `F7`, at the debugger console `bsave "hgrtable.bin",3A0:3CF`, press `F7`. @@ -1764,7 +1779,7 @@ Our `HgrHiY` table: To select which row to draw at we'll pass that in the X register to our DrawCharColRow() routine: -Listing 7: +Listing 9b: ```assembly ; FUNC: SetCursorRow( row ) @@ -1772,25 +1787,25 @@ Listing 7: ; INPUT : $E5,$E6 initial pointer to the destination screen scanline ; Note: Must start at every 8 scanlines. ; OUTPUT: $F5,$F5 working pointer to the destination screen scanline - ORG $0313 - 0313: SetCursorRow - 0313:BD A0 03 LDA HgrLoY,X ; HgrLoY[ row ] - 0316:85 F5 STA TmpLo - 0318:BD B8 03 LDA HgrHiY,X ; HgrHiY[ row ] - 031B:18 CLC - 031C:65 E6 ADC HgrHi - 031E:85 F6 STA TmpHi - 0320:60 RTS + ORG $0313 + 0313: SetCursorRow + 0313:BD A0 03 LDA HgrLoY,X ; HgrLoY[ row ] + 0316:85 F5 STA TmpLo + 0318:BD B8 03 LDA HgrHiY,X ; HgrHiY[ row ] + 031B:18 CLC + 031C:65 E6 ADC HgrHi + 031E:85 F6 STA TmpHi + 0320:60 RTS ; FUNC: DrawCharColRow() ; PARAM: A = glyph to draw ; PARAM: Y = column to draw at ; $0 .. $27 (Columns 0 .. 39) (not modified) ; PARAM: X = row to draw at ; $0 .. $17 (Rows 0 .. 23) (destroyed) - ORG $0335 - 0335: DrawCharColRow - 0335:48 PHA - 0336:20 13 03 JSR SetCursorRow - 0339:68 PLA + ORG $0335 + 0335: DrawCharColRow + 0335:48 PHA + 0336:20 13 03 JSR SetCursorRow + 0339:68 PLA ; intentional fall into _DrawChar2 ``` @@ -1803,13 +1818,15 @@ Enter in: Now we can print a char at any location: +Listing Demo 4: + ```assembly ORG $1100 - 1100: PrintAYX - 1100:A9 41 LDA #41 ; A-register = char - 1102:A0 01 LDY #1 ; Y-register = col 1 (2nd column) - 1104:A2 02 LDX #2 ; X-register = row 2 (3rd row) - 1106:4C 35 03 JMP DrawCharColRow + 1100: PrintAYX + 1100:A9 41 LDA #41 ; A-register = char + 1102:A0 01 LDY #1 ; Y-register = col 1 (2nd column) + 1104:A2 02 LDX #2 ; X-register = row 2 (3rd row) + 1106:4C 35 03 JMP DrawCharColRow ``` Enter in: @@ -1837,18 +1854,20 @@ Unfortunately, our usage of the X and Y registers are not intuitive. This is due We could map the X-register to the natural column (x-axis), and the Y-register to the natural row (y-axis). Alas, we're stuck with the X=row and Y=col unless we wanted to add extra code to "swap" the two. +Listing 10: + ```assembly ; FUNC: SetCursorColRowYX() ; PARAM: Y = col ; PARAM: X = row - ORG $0369 - 369: SetCursorColRowYX - 369:20 13 03 JSR SetCursorRow - 36C:18 CLC - 36D:98 TYA - 36E:65 F5 ADC $F5 - 371:85 F5 STA $F5 - 373:60 RTS + ORG $0369 + 369: SetCursorColRowYX + 369:20 13 03 JSR SetCursorRow + 36C:18 CLC + 36D:98 TYA + 36E:65 F5 ADC $F5 + 371:85 F5 STA $F5 + 373:60 RTS ``` Or are we stuck? Since we're using a function to calculate the destination address let's fix the order. @@ -1858,17 +1877,17 @@ We'll need to change the `X` offset in SetCursorColRowXY() to `Y`; ; FUNC: SetCursorColRow2a( row ) ; PARAM: Y = row ; NOTES: Version 2a ! - 0928: ORG $0928 - 0928: SetCursorColRow2a - 0928:B9 A0 03 LDA HgrLoY,Y ; changed from: ,X - 092B:18 CLC - 092C:65 E5 ADC HgrLo - 092E:85 F5 STA TmpLo - 0930:B9 B8 03 LDA HgrHiY,Y ; changed from: ,X - 0933:18 CLC - 0934:65 E6 ADC HgrHi - 0936:85 F6 STA TmpHi - 0938:60 RTS + 0928: ORG $0928 + 0928: SetCursorColRow2a + 0928:B9 A0 03 LDA HgrLoY,Y ; changed from: ,X + 092B:18 CLC + 092C:65 E5 ADC HgrLo + 092E:85 F5 STA TmpLo + 0930:B9 B8 03 LDA HgrHiY,Y ; changed from: ,X + 0933:18 CLC + 0934:65 E6 ADC HgrHi + 0936:85 F6 STA TmpHi + 0938:60 RTS ``` And change the low byte to add `X` instead: @@ -1878,37 +1897,39 @@ And change the low byte to add `X` instead: ; PARAM: X = col ; PARAM: Y = row ; NOTES: Version 2b ! - ORG $0979 - 979: SetCursorColRow2b - 979:20 13 03 JSR SetCursorRow - 97C:18 CLC - 37D:88 TXA ; changed from: TYA - 97E:65 F5 ADC $F5 - 981:85 F5 STA $F5 + ORG $0979 + 979: SetCursorColRow2b + 979:20 13 03 JSR SetCursorRow + 97C:18 CLC + 37D:88 TXA ; changed from: TYA + 97E:65 F5 ADC $F5 + 981:85 F5 STA $F5 983:60 ``` This is a little clunky but it is progress. Let's write the new SetCursorColRow() version with the SetCursorRow() inlined so we don't have to use a JSR. +Listing 11: + ```assembly ; FUNC: SetCursorColRow( col, row ) ; PARAM: X = column to draw at; $0 .. $27 (Columns 0 .. 39) (not modified) ; PARAM: Y = row to draw at; $0 .. $17 (Rows 0 .. 23) (not modified) ; NOTES: Version 3! X and Y is swapped from earlier version! ; [$F5] = HgrLoY[ Y ] + ScreenLo + X - ORG $0321 - 0321: SetCursorColRow - 0321:86 F5 STX TmpLo - 0323:B9 A0 03 LDA HgrLoY,Y ; HgrLoY[ row ] - 0326:18 CLC - 0327:65 F5 ADC TmpLo ; add column - 0329:85 F5 STA TmpLo - 032B:B9 B8 03 LDA HgrHiY,Y ; HgrHiY[ row ] - 032E:18 CLC ; \ could optimize this into - 032F:65 E6 ADC HgrHi ; / single ORA HgrHi - 0331:85 F6 STA TmpHi - 0333:60 RTS - 0334:EA NOP ; pad + ORG $0321 + 0321: SetCursorColRow + 0321:86 F5 STX TmpLo + 0323:B9 A0 03 LDA HgrLoY,Y ; HgrLoY[ row ] + 0326:18 CLC + 0327:65 F5 ADC TmpLo ; add column + 0329:85 F5 STA TmpLo + 032B:B9 B8 03 LDA HgrHiY,Y ; HgrHiY[ row ] + 032E:18 CLC ; \ could optimize this into + 032F:65 E6 ADC HgrHi ; / single ORA HgrHi + 0331:85 F6 STA TmpHi + 0333:60 RTS + 0334:EA NOP ; pad ``` Enter in: @@ -1923,23 +1944,25 @@ Enter in: Now that we have the basic print char working lets extend it to print a C-style string (one that is zero terminated.) +Listing 12: + ```assembly String EQU $F0 ; FUNC: DrawString( *text ) ; PARAM: X = High byte of string address ; PARAM: Y = Low byte of string address - 037E: ORG $037E - 037E: DrawString + 037E: ORG $037E + 037E: DrawString 037E:84 F0 STY String+0 0380:86 F1 STX String+1 0382:A0 00 LDY #0 - 0384:B1 F0 .1 LDA (String),Y + 0384:B1 F0 .1 LDA (String),Y 0386:F0 07 BEQ .2 ; null byte? Done 0388:20 10 03 JSR DrawChar ; or DrawCharCol for speed 038B:C0 28 CPY #40 ; col < 40? 038D:90 F5 BCC .1 - 038F:60 .2 RTS + 038F:60 .2 RTS ```
**AppleWin**: @@ -1952,6 +1975,8 @@ Now that we have the basic print char working lets extend it to print a C-style And our example to verify that it works: +Listing Demo 5: + ```assembly ; FUNC: DemoDrawString() ORG $1200 @@ -2211,9 +2236,9 @@ Hey! Homework? Yes, the only (true) way to demonstrate you understand the theo very bottom scanline should be "blank." -# Recap +# Recap - Font Draw -Here are all the (core) routines we've entered in so far: +Here are all the (core) font rendering routines we've entered in so far: ``` 0301: 48 6A 6A 6A 6A 20 0A @@ -2240,7 +2265,7 @@ Here are all the (core) routines we've entered in so far: 03C8:00 00 01 01 02 02 03 03 ``` -(To save this: `BSAVE CODE_0300.BIN,A$300,L$D0`) +(To save this: `BSAVE FONTDRAW.BIN,A$300,L$D0`) # Other Fonts @@ -2405,7 +2430,7 @@ Hmm, some of those glyphs are badly designed (inconsistent.) :-/ That's the bigg Let's write a program to view all the ASCII characters. ```Assembly - .ORG $1050 + ORG $1050 ; <> ```