First of all, if you don’t know how to make a 6502 Assembled project from scratch and run it on the Commander X16, check out the Commander X16 hello world 6502 Assembly page I made on how to do that.
The BASIC idea
Now that I have a program running within the emulator, I was interested in how I can do something small with the video chip. What I was finally able to do was set a character on the screen and pick it’s color. My research materials were the VERA documentation and a helpful document created by another member of the Facebook group.
I was watching a video posted by David Murry in the Facebook group that showed him using the command
VPOKE with 3 arguments. So I got it in my head that if I could figure out how those 3 arguments mapped to 6502 Assembly (what addresses they were) I would be able to do the same thing. Needless to say, after looking at the VERA documentation on the addresses for the chip, I was able to test enough to get the same thing working.
VPOKE to 6502 Assembly
So first we should describe the anatomy of VPOKE. This command takes 3 arguments bank, address, and value respectively. These directly translate over to assembly instructions as you can see in the following table.
|arg 1||$9F22||Bank / stride|
|arg 2||$9f20||Low address for video memory|
|arg 3||$9f23||Data address for video memory|
Check out the comments in the following code, you might also want to look back and forth between the code and the above table to get the full picture.
*=$0801 !byte $01,$08,$0b,$08,$01,$00,$9e,$32,$30,$36,$31,$00,$00,$00 LDA #0 STA $9F25 ; Select primary VRAM address LDA #$20 ; VPOKE 1st argument (The 0x00 in this is the 0 bank) STA $9F22 ; Set primary address bank to 0, stride to 2 ; VPOKE 0,0,2 ; VPOKE 0,1,8 ; The following is the same as the 2 above VPOKE statements LDA #0 ; VPOKE 2nd argument STA $9F20 ; Set Primary address low byte to 0 LDA #0 ; Not using the high byte, just want to stay on <0,0> STA $9F21 ; Set primary address high byte to 0 LDA #2 ; VPOKE 3rd argument (set the character to "B") STA $9F23 ; Writing $73 to primary address ($00:$0000) ; Set the color to orange LDA #1 ; VPOKE 2nd argument (next byte over) STA $9f20 ; Next byte over LDA #8 ; VPOKE 3rd argument (orange color code) STA $9f23 ; Write the color BRK
Drawing 5 green hearts
Now that we have a basic understanding of how we can draw something to the screen. Let’s try and draw 5 green hearts to the screen. The 2 things to know is that a heart character in PETSCII is $53 (see bottom left corner of PETSCII square here), and the second is that the code for green is
*=$0801 !byte $01,$08,$0b,$08,$01,$00,$9e,$32,$30,$36,$31,$00,$00,$00 LDA #0 STA $9F25 ; Select primary VRAM address LDA #$20 ; VPOKE 1st argument (The 0x00 in this is the 0 bank) STA $9F22 ; Set primary address bank to 0, stride to 2 LDA #0 STA $9F21 ; Set primary address high byte to 0 LDX #0 ; Loop counter LDY #0 ; Address offset next_heart: TYA STA $9F20 ; Set Primary address low byte to 0 LDA #$53 ; <3 STA $9F23 ; Data line INY TYA ; Next byte over is color STA $9f20 LDA #5 ; Green STA $9f23 ; Write the color INX INY CPX #5 BNE next_heart BRK
Looking at the code above, you may notice that we are incrementing the byte value we put into address
$9F20 2 times each iteration of the loop. This is because the first byte is the character we want to write, and the next byte over is the color we want to pick. So you can think of it as the following:
|$9F20 Value||Usage <x,y>|
|0||The character for top left corner <0,0>|
|1||Color for previous <0,0>|
|2||The character for next space <1,0>|
|3||Color for previous <1,0>|
|4||The character for next space <2,0>|
|5||Color for previous <2,0>|