TLDR; Head to the bottom of this post for a cut-and-paste character mode (x,y) offset table + example code.
While learning 6502 assembly I’ve gotten good mileage up to this point by working in the character mode. For me, plotting and animating characters is a great way to learn the basics of assembly without heaping on the complexities of bitmaps and sprites. Don’t get me wrong, I’m looking forward to learning all of that too but in the spirit of KISS – character mode it is!
Each of the following examples will draw the @ symbol into the screen corners:
A basic of working in this mode is placing a character at some position x and y on the screen. The C64 screen consists of a 40×25 grid of 8×8 characters. Characters can be written to the screen by setting a 8-bit value into any of the addresses ranging from $0400 to $07e8.
Write characters into the corners of the screen
Since the character addresses are just contiguous memory locations, typically you could write any (x,y) position by applying a formula similar to this:
Where (y*40)+x is the offset from the initial address. But of course this is an 8-bit machine and not all values of (x,y) will fit into an 8-bit number. For instance position (6, 16) yields an offset of (16*40)+16 = 256 which exceeds the max 8-bit value of 255.
Let’s try extending this code to support 16-bit linear offsets to support character offsets in the range of $0000-$03e7. I’d consider this approach to be ‘the hard way’ of drawing characters to x and y position of the screen but it’s a useful exercise.
Write characters to the screen with 16-bit multiply and addition
There’s quite a bit more code now to accomplish the offset. 6502 doesn’t have native multiply operations so we have to implement it using jump, shifts and adds. Also, we’re multiplying and adding numbers that require extra work to produce 16-bit results.
The number of operations adds code complexity and extra time to calculate the positions. I’m going to elide the details and fussing with further optimization of this code but suffice it to say that there are many variations on this that can improve the efficiency.
Writing characters to the screen using tabled addresses
The same task can be performed with a tabled address scheme. This accomplishes character plotting by tabling the address of each line’s starting address. This address is looked up with the y position and then the x value (in the range of 0-39) is added to that to produce an offset to the character we want to draw.
I created a Kotlin script to generate the look up. The names and comments should document how it works.
The output of the script:
screenAddressHi byte $04,$04,$04,$04,$04,$04,$04,$05,$05,$05,$05,$05,$05,$06,$06,$06,$06,$06,$06,$06,$07,$07,$07,$07,$07 screenAddressLo byte $00,$28,$50,$78,$a0,$c8,$f0,$18,$40,$68,$90,$b8,$e0,$08,$30,$58,$80,$a8,$d0,$f8,$20,$48,$70,$98,$c0
The final assembly
The final code is fast and compact. It works by first looking up the screen address of the character to be drawn. The low and high bytes of that address are placed into consecutive address in the 6502 zero page (known as a vector – more on that in future posts.) Once the vectors are set, we store the ‘@’ symbol into the zero page low byte to show it on the screen.
Lots of functionality can be implemented using lookup tables. I’ll provide more examples in upcoming posts. Enjoy!