It is currently Fri Jul 19, 2019 8:26 pm

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Fri Apr 19, 2019 8:26 pm 
Offline

Joined: Sat Dec 01, 2018 6:02 pm
Posts: 3
Edit:
I now realize I'm an idiot and wrote "DB." instead of ".DB".

I have a simple SNES program that is supposed to color the top part of the screen a light blue color, and the bottom of the screen a dark blue color. Whenever I try to run it in an emulator, the image results in an interlaced picture with two different incorrect colors appearing on different scanlines. The code for the program is as follows.

Code:
.include "Header.inc"
.include "Snes_Init.asm"

; Needed to satisfy interrupt definition in "Header.inc".
VBlank:
   ;Set up HDMA
   stz      $420C      ; Reset HDMA
   lda      #%00000010   ; A to B, Absolute, (3 bits unused), 2 bytes to 1 register
   sta      $4300
   lda      #$22      ; Modify address $(21)22 (Background Color)
   sta      $4301
   lda      #$00      ; Set HDMA table bank to 7E
   sta      $4302      
   rep      #$20
   lda      HDMA_Table   ; Set HDMA table to HDMA table pointer
   sta      $4303      
   lda      #%00000001   ; Activate the first HDMA channel
   sta      $420C
   rti

.BANK 0
.SECTION "Main"

Start:
    ; Initialize the SNES.
    Snes_Init
   ; Initialize input
   Input_Init

    ; Set the background color to blue.
    sep     #$20        ; Set the A register to 8-bit.
    lda     #%10000000  ; Force VBlank by turning off the screen.
    sta     $2100
   lda      #%01110101   ; 1-BG4 tilesize = 8x8 (not used), 2-BG3 tilesize = 16x16, 3-BG2 tilesize = 16x16, 4-BG1 tilesize = 16x16, Background priority set to 0 (?), 6-8- Set graphics to Mode 5
   sta      $2105
    lda     #%11000111  ; Load the low byte of the blue color.
    sta     $2122
    lda     #%01100001  ; Load the high byte of the blue color.
    sta     $2122

   ; Set up HDMA table
   HDMA_Table:
DB.   #$7F      ; Wait for 127 scanlines after transferring
DB.   #%11000111   ; Low byte of light blue color
DB.   #%01100001   ; High byte of light blue color
DB.   #$34      ; Wait for 52 scanlines after transferring
DB.   #%11000111   ; Low byte of light blue color
DB.   #%01100001   ; High byte of light blue color
DB.   #$01      ; Do not wait for a scanline, because this is the final transfer
DB.   #%01100100   ; Low byte of dark blue color
DB.   #%01011101   ; High byte of dark blue color
DB.   #$00      ; Null byte to end table


   lda #$80
   sta $4200   ;Enable VBlank NMI

   rep      #$20      ; set the accumulator (A) register into 16 bit mode
   sep      #$10      ; set the index (X and Y) register into 8 bit mode

   ldy      #$80      ;  we will try to write 128 ($80) bytes in one row ...
   sty      $2115      ; ... and we will let the PPU let this know.

   stz      $2116      ; Set the VRAM address to zero

    lda     #%00001111  ; End VBlank, setting brightness to 15 (100%).
    sta     $2100

    ; Loop forever.
MainLoop:
    jmp MainLoop

.ENDS


Note that I am using mode 5 with interlacing, but I do not think that is related to the problem, because even when using other modes, the problem persists. I included the file in the post. I tested it in Snes9x and zsnes.


Attachments:
HDMA.smc [256 KiB]
Downloaded 89 times
Top
 Profile  
 
PostPosted: Fri Apr 19, 2019 8:45 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 8486
Location: Seattle
There's a bunch of problems here, beyond the one you're identifying.

One is that you can't put tables in the middle of code like that. The CPU doesn't know what you're trying to do and just executes it as though it were code, which it isn't.

Another is that you enable NMIs but don't have an NMI handler, so it just starts executing random crap at address $000000.

And finally, the one you identified in your edit.

Aside from all that, I'd strongly recommend using names instead of magic numbers in your code. It'll help make it easier to understand.


Top
 Profile  
 
PostPosted: Fri Apr 19, 2019 9:26 pm 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 217
Simply writing two bytes to $2122 is not enough to set the background color. The first color you write to $2122 will be written to color 0, which is the background color, but after that, the next color written to $2122 will be color 1, then color 2, and so on.

To fix this, you need to write 0 to $2121, then the new background color to $2122. You could do this with two HDMA channels, the first writing to $2121 and the second writing to $2122. Alternatively, you could have a single HDMA channel that writes four bytes, writing 0 to $2121 twice, then writing the color to $2122.

Another problem, as lidnariq mentions, is that you don't have an NMI/Vblank handler. You do have a label called Vblank, but the ROM you've given actually jumps to $8020 when NMI happens. There must be a problem with the "Header.inc" mentioned in your code, though you don't show it here.

After you fix that, there's another big problem to be aware of. Ideally, code should be written so that no matter when an interrupt happens, it won't break anything. After all, you often don't know when an interrupt might happen. Think of a game that suffers from slowdown when too many enemies are on the screen. You might not finish your calculations for that frame before Vblank happens! Take a look at this example code:
Code:
main:
    lda #5
    sta MyVariable
    jmp main

Vblank:
    lda #10
    sta AnotherVariable
    rti

It loads the number 5 into the A register, then stores it in MyVariable. Meanwhile, there's a Vblank interrupt handler, which loads 10 into A, and stores it in AnotherVariable. You might think this isn't a problem... but what happens if Vblank occurs right here?
Code:
    lda #5
    ; Vblank happens here
    sta MyVariable

First, A is set to 5. Then, Vblank occurs. A is set to 10, and stored in AnotherVariable. Then, the handler returns... and, because A is still 10, 10 is stored in MyVariable. The wrong number has ended up in MyVariable!

To solve this problem, interrupt handlers should save all registers they modify at the start of the handler, and restore them at the end. Here's a fix for the previous example:
Code:
main:
    lda #5
    sta MyVariable
    jmp main

Vblank:
    pha         ; push the current value of A onto the stack
    lda #10
    sta AnotherVariable
    pla         ; pull the old value from the stack and store it in A
    rti


Top
 Profile  
 
PostPosted: Fri Apr 19, 2019 10:00 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4154
Location: A world gone mad
Also: please do not forget to read $4210 once (a single 8-bit read) at the start of your NMI routine (e.g. pha / lda $4210 / ... / pla / rti). Refer to official manual page B-3 for details.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group