juef wrote:Code: Select all
; Set the background color to green.
sep #$20 ; Set the A register to 8-bit.
lda #%10000000 ; Force VBlank by turning off the screen.
sta $2100
lda #%11100000 ; Load the low byte of the green color.
sta $2122
lda #%00000000 ; Load the high byte of the green color.
sta $2122
lda #%00001111 ; End VBlank, setting brightness to 15 (100%).
sta $2100
Is there a way to load both bytes into $2122 at once? It seems kinda strange to me to set the register to 8 bits, load 8 bits, then load 8 more bits, rather than doing all of this with just one lda/sta.
No. $2122 is an 8-bit memory-mapped register for colour data, the data of which is 16-bits; each write to it is handled internally by the PPU unit on the system. There's no "direct" 16-bit equivalent. If you were to write a 16-bit value to $2122, the LSB would end up going into $2122, and the MSB would end up going into $2123 which is a completely different register (window mask setting).
Per my old SNES documentation:
Code: Select all
| w |$2121 |Colour # (or pallete) selection register [CGADD] |
| | |xxxxxxxx x: Address (color #). |
| | | |
| | | |
| wd |$2122 |Colour data register [CGDATA] |
| | |xxxxxxxx x: Value of colour. |
| | | |
| | |SNES colour is 15 bit; 5 bits for red, green, and blue. The |
| | |order isn't RGB though: It's BGR (RGB reversed!). |
I should note you aren't setting $2121 to the index/offset of the palette entry you wish to modify prior to doing it -- so I assume your init_snes routine is what's responsible. I have to assume you're modifying colour #0. Just an FYI.
juef wrote:Speaking of which... How come doing sta $2122 twice with a byte both times doesn't end up just writing the latest byte of the two? Is writing the low byte first, and the the high byte the "standard way" of setting a color value here?
Because it's an 8-bit memory-mapped register. Each write is handled by the PPU. You should probably find a copy of my old SNES documentation and review the SNES.1 file. Both bytes written via the STA statements are honoured by the PPU/used by VRAM.
juef wrote:I tried copying and pasting the "Set the background [...]" block so that there's two of them, changing the color to red the second time. By moving the Forever label at the top of the first of these blocks, I expected alternating red and green as the background color, but I end up with a rather trippy effect involving red and black only. Am I supposed to do something between (or during) VBlanks?
What's happening is that you're updating the screen "too fast" and not seeing what's going on (visually). This is further complicated by your desire to turn on/off VBlank.
You have two options, and I recommend the former:
1) Leave the screen on at all times/set brightness to 100% and do your screen updates (writes to $2122) inside of VBlank time (NMI). You can wait for the NMI by examining bit 7 of $4210. You'll need to tie VBlank to NMI by setting bit 7 of $4200 as well. You can use the WAI opcode to wait for NMI rather than have to poll $4210.
2) Leave the screen on at all times/set brightness to 100% and do everything in your main loop but instead of disabling VBlank, you need to wait for it. See bit 7 of $4212.
In either case you need to add some delays. The screen is updated at 60 times a second (50 if PAL). The easiest way to delay is to wait for VBlank repetitively (more waits = more delay). I used to use something like this:
Code: Select all
rep #$10
ldx #200 ; Higher value = longer delay
delay jsr WaitVBL
dex
bpl delay
sep #$10
...
;
; Note: Should make sure accum is 8-bit here, not 16-bit
;
WaitVBL:
pha
xxx lda $4210
bpl xxx
lda $4210 ; Reset it
pla
rts
It might be worthwhile, as I said earlier, to download my old SNESdoc. Inside of that archive is an another archive called TEST.LZH, which contains some source code to a very small demo used to show off some of the features on the SNES. The code is simple and should get you started, and it reads fairly easily.