Page 1 of 2

vram glitches

Posted: Sun Aug 14, 2016 6:28 am
by infidelity
ok, so what i'm doing is creating an nes game from the ground up. nothing major for my first attempt, but I want to have a bare bones rom. I'm using MMC3 as my mapper. So far I have a functioning controller, sound engine (borrowed from Capcom) and a vram buffer (borrowed from Zelda)

Now here's the problem. I wanted to see if I can have tiles drawn on screen, either horizontally, or vertically, to see if I had this setup correctly for when I want to create a scroll based game. My vram buffer is within the $300ram section. Now, I've been doing manual pastes into the ram of the nes. I'll do 20 tiles horizontaly at a time, and it displays without glitches. I've done a vertical string of tiles as well, all the way down before the attribute section $23C0-$23FFppu, they display correctly with no glitches. So my problem is, I wanted to perform a test using my controller, when a specific button is pressed, it will load the appropriate value for the vram buffer to load the tile construction from a table. Everytime I do it that way, it glitches, i'll get violent screen shaking, i'll even get palette rewrites. I just want to be able to have a constructed vram engine, before I go any further with deciding wht type of game I want to play. Here is my code, and I apologize but this is straight from the fceux debugger.

I don't know what i'm missing, or what i'm doing wrong, ive added the LDA $2002 BPL, etc etc for the proper time the system is needed to have before writing to the screen. Also, I feel it has something to do with timing. Because when I have ppu rendering off, and I use my d-pad to initiate my writes, they are constructed properly. Thanks for reading.

Code: Select all

;nmi
0F:C000:78        SEI
 0F:C001:08        PHP
 0F:C002:48        PHA
 0F:C003:8A        TXA
 0F:C004:48        PHA
 0F:C005:98        TYA
 0F:C006:48        PHA

;jsr to joypad routine
 0F:C007:20 8E FF  JSR $FF8E

;here is where i begin setting up vram
 0F:C00A:A9 00     LDA #$00
 0F:C00C:8D 03 20  STA $2003 = #$00
 0F:C00F:A9 02     LDA #$02
 0F:C011:8D 14 40  STA $4014 = #$FF

;jsr to vram bufer
 0F:C014:20 92 FE  JSR $FE92

 0F:C017:A9 3F     LDA #$3F
 0F:C019:8D 06 20  STA $2006 = #$00
 0F:C01C:A9 00     LDA #$00
 0F:C01E:8D 06 20  STA $2006 = #$00
 0F:C021:8D 06 20  STA $2006 = #$00
 0F:C024:8D 06 20  STA $2006 = #$00
 0F:C027:AD 02 20  LDA $2002 = #$88
 0F:C02A:29 40     AND #$40
 0F:C02C:D0 F9     BNE $C027
 0F:C02E:AD 02 20  LDA $2002 = #$88
 0F:C031:A5 FF     LDA $00FF = #$88
 0F:C033:8D 00 20  STA $2000 = #$88
 0F:C036:A5 FD     LDA $00FD = #$00
 0F:C038:8D 05 20  STA $2005 = #$00
 0F:C03B:A5 FC     LDA $00FC = #$00
 0F:C03D:8D 05 20  STA $2005 = #$00
 0F:C040:A5 FE     LDA $00FE = #$00
 0F:C042:8D 01 20  STA $2001 = #$00
;end of vram stuff

;mmc3 chr registers
0F:C045:A2 05     LDX #$05
 0F:C047:8E 00 80  STX $8000 = #$4C
 0F:C04A:B5 F0     LDA $F0,X @ $00F0 = #$00
 0F:C04C:8D 01 80  STA $8001 = #$6C
 0F:C04F:CA        DEX
 0F:C050:10 F5     BPL $C047

;frame counter
 0F:C052:E6 F6     INC $00F6 = #$00

;jsr to sound engine
 0F:C054:20 00 80  JSR $8000

;custom d-pad setups to test vram & sound
 0F:C057:A5 F8     LDA $00F8 = #$00
 0F:C059:29 80     AND #$80
 0F:C05B:F0 05     BEQ $C062
 0F:C05D:A9 05     LDA #$05
 0F:C05F:20 03 80  JSR $8003
 0F:C062:A5 F8     LDA $00F8 = #$00
 0F:C064:29 04     AND #$04
 0F:C066:F0 0C     BEQ $C074
 0F:C068:A9 04     LDA #$04
 0F:C06A:85 F7     STA $00F7 = #$02
 0F:C06C:A9 DC     LDA #$DC
 0F:C06E:85 F0     STA $00F0 = #$00
 0F:C070:A9 DE     LDA #$DE
 0F:C072:85 F1     STA $00F1 = #$00
 0F:C074:A5 F8     LDA $00F8 = #$00
 0F:C076:29 20     AND #$20
 0F:C078:F0 04     BEQ $C07E
 0F:C07A:A9 1E     LDA #$1E
 0F:C07C:85 FE     STA $00FE = #$00
 0F:C07E:A5 F8     LDA $00F8 = #$00
 0F:C080:29 10     AND #$10
 0F:C082:F0 04     BEQ $C088
 0F:C084:A9 00     LDA #$00
 0F:C086:85 FE     STA $00FE = #$00
 0F:C088:A5 F8     LDA $00F8 = #$00
 0F:C08A:29 08     AND #$08
 0F:C08C:F0 0C     BEQ $C09A
 0F:C08E:A9 06     LDA #$06
 0F:C090:85 F7     STA $00F7 = #$02
 0F:C092:A9 DC     LDA #$DC
 0F:C094:85 F0     STA $00F0 = #$00
 0F:C096:A9 DE     LDA #$DE
 0F:C098:85 F1     STA $00F1 = #$00
 0F:C09A:68        PLA
 0F:C09B:A8        TAY
 0F:C09C:68        PLA
 0F:C09D:AA        TAX
 0F:C09E:68        PLA
 0F:C09F:28        PLP
 0F:C0A0:40        RTI
;END

Re: vram glitches

Posted: Sun Aug 14, 2016 6:37 am
by Quietust
Your "joypad routine" should be done at the end of your NMI routine, not the beginning - on NTSC, you have less than 2300 cycles to update sprites and VRAM, so everything else should happen afterwards.

We also can't see what your "VRAM update" routine looks like - if it's trying to update more than 32 bytes or so, it's probably not going to finish in time.

Re: vram glitches

Posted: Sun Aug 14, 2016 7:09 am
by infidelity
Oh wow thank you! It was because of the joypad routine not being at the end! I moved that jsr to the end, turned on my ppu rendering, and when I initiated my tile write tests, they appeared correctly with no glitches! What I wanted to do, is see if I can draw a single column of tiles the entire width & length of the current screen, individually of course. (horizontaly its 1F bytes of tiles, and verticaly its 1D bytes of tiles) Because my next step is to learn how to perform scrolling and screen construction. So thank you Quietust! :-D

Re: vram glitches

Posted: Sun Aug 14, 2016 7:36 am
by dougeff
On a side note.

NMI is not affected by CLI or SEI. Only a write to $2000 can affect if NMIs are on or off.

Also, you don't have to PHP or PLP. The processor status (pre-NMI) is saved to the stack, and pulled from the stack automatically with RTI.

You're setting the PPU address to 3f00, then immediately setting it to 0.

You're checking for Sprite Zero hit...Keep in mind that Sprite Zero hit status doesn't change until the end of V-blank, so if you check for Sptite Zero status while still in V-blank, you may get a false positive because of the last frame's Sprite Zero hit, and trigger your screen split too early.

Re: vram glitches

Posted: Sun Aug 14, 2016 9:10 am
by infidelity
Thank you for that information as well dougeff. I'll remove the SEI. Also I didn't realize I had a sprite 0 check going on, i'll find where that is and remove it. I plan on inserting an MMC3 irq engine as well, incase I want an info bar while the rest of the screen scrolls freely.

Is the sprite 0 check the, LDA $2002 AND #$40 BNE LDA $2002??? Thanks!

edit
Here is my NMI now with the changes. And my vram test writes are still perfect.

Code: Select all

;push stack
 0F:C000:48        PHA
 0F:C001:8A        TXA
 0F:C002:48        PHA
 0F:C003:98        TYA
 0F:C004:48        PHA

 0F:C005:A9 00     LDA #$00
 0F:C007:8D 03 20  STA $2003 = #$00
 0F:C00A:A9 02     LDA #$02
 0F:C00C:8D 14 40  STA $4014 = #$FF

;jsr to vram buffer 
 0F:C00F:20 92 FE  JSR $FE92

;set nametable, xy scroll, ppu rendering
 0F:C012:A5 FF     LDA $00FF = #$88
 0F:C014:8D 00 20  STA $2000 = #$88
 0F:C017:A5 FD     LDA $00FD = #$00
 0F:C019:8D 05 20  STA $2005 = #$00
 0F:C01C:A5 FC     LDA $00FC = #$00
 0F:C01E:8D 05 20  STA $2005 = #$00
 0F:C021:A5 FE     LDA $00FE = #$00
 0F:C023:8D 01 20  STA $2001 = #$00
 
;set mmc3 chr registers
 0F:C026:A2 05     LDX #$05
 0F:C028:8E 00 80  STX $8000 = #$4C
 0F:C02B:B5 F0     LDA $F0,X @ $00F0 = #$00
 0F:C02D:8D 01 80  STA $8001 = #$6C
 0F:C030:CA        DEX
 0F:C031:10 F5     BPL $C028

;frame counter
 0F:C033:E6 F6     INC $00F6 = #$B3

;jsr to joypad routine
 0F:C035:20 8E FF  JSR $FF8E

;jsr to sound engine
 0F:C038:20 00 80  JSR $8000

;my custom d-pad routine to test vram & sound engine
 0F:C03B:A5 F8     LDA $00F8 = #$00
 0F:C03D:29 80     AND #$80
 0F:C03F:F0 05     BEQ $C046
 0F:C041:A9 09     LDA #$09
 0F:C043:20 03 80  JSR $8003
 0F:C046:A5 F8     LDA $00F8 = #$00
 0F:C048:29 04     AND #$04
 0F:C04A:F0 0C     BEQ $C058
 0F:C04C:A9 04     LDA #$04
 0F:C04E:85 F7     STA $00F7 = #$00
 0F:C050:A9 DC     LDA #$DC
 0F:C052:85 F0     STA $00F0 = #$00
 0F:C054:A9 DE     LDA #$DE
 0F:C056:85 F1     STA $00F1 = #$00
 0F:C058:A5 F8     LDA $00F8 = #$00
 0F:C05A:29 20     AND #$20
 0F:C05C:F0 04     BEQ $C062
 0F:C05E:A9 1E     LDA #$1E
 0F:C060:85 FE     STA $00FE = #$00
 0F:C062:A5 F8     LDA $00F8 = #$00
 0F:C064:29 10     AND #$10
 0F:C066:F0 04     BEQ $C06C
 0F:C068:A9 00     LDA #$00
 0F:C06A:85 FE     STA $00FE = #$00
 0F:C06C:A5 F8     LDA $00F8 = #$00
 0F:C06E:29 08     AND #$08
 0F:C070:F0 0C     BEQ $C07E
 0F:C072:A9 06     LDA #$06
 0F:C074:85 F7     STA $00F7 = #$00
 0F:C076:A9 DC     LDA #$DC
 0F:C078:85 F0     STA $00F0 = #$00
 0F:C07A:A9 DE     LDA #$DE
 0F:C07C:85 F1     STA $00F1 = #$00
 
;pull stack
 0F:C07E:68        PLA
 0F:C07F:A8        TAY
 0F:C080:68        PLA
 0F:C081:AA        TAX
 0F:C082:68        PLA
 0F:C083:40        RTI
does that all look better? and one last thing, where would be a good place to insert the sub routine that will be the origin for everything that my game will be?

Re: vram glitches

Posted: Sun Aug 14, 2016 9:49 am
by Quietust
You still want to read $2002 before setting the scroll registers, just in case the H/V toggle on 2005/2006 is in the wrong state - you just don't need to check the result.

Re: vram glitches

Posted: Sun Aug 14, 2016 9:51 am
by tepples
Unless you're tokumaru, and you want the wrongness of the first/second write latch to fail fast, exposing the wrongness of your VRAM update code in the most obvious way possible.

Re: vram glitches

Posted: Sun Aug 14, 2016 9:54 am
by Quietust
tepples wrote:Unless you're tokumaru, and you want the wrongness of the first/second write latch to fail fast, exposing the wrongness of your VRAM update code in the most obvious way possible.
I actually failed to realize that said code immediately followed the VRAM write routine, which very much relies on the H/V toggle being in the correct state (and most likely reads $2002 itself).

Re: vram glitches

Posted: Sun Aug 14, 2016 10:38 am
by infidelity
ok I replaced the LDA $2002 before my writes to my xy scrolls. I am still able to freely at will adjust my xy scroll.

Re: vram glitches

Posted: Sun Aug 14, 2016 10:58 am
by tokumaru
tepples wrote:Unless you're tokumaru, and you want the wrongness of the first/second write latch to fail fast, exposing the wrongness of your VRAM update code in the most obvious way possible.
That's me! I like to live dangerously. :beer: :wink:

Re: vram glitches

Posted: Sun Aug 14, 2016 11:19 am
by infidelity
Ok so where is a good spot to begin all of the asm to create my game?

Also I was trying to insert a scanline based IRQ engine. Where in the NMI is the spot I should set that up? I'm assuimg it's after my write to $2000. Thanks again.

Re: vram glitches

Posted: Sun Aug 14, 2016 11:51 am
by tokumaru
infidelity wrote:Ok so where is a good spot to begin all of the asm to create my game?
The game code can be anywhere you want, you just have to make sure it executes after the initialization code, and that it can interrupted by IRQs and NMIs without crashing or glitching.
Also I was trying to insert a scanline based IRQ engine. Where in the NMI is the spot I should set that up? I'm assuimg it's after my write to $2000. Thanks again.
The MMC3 counts scanlines by watching the PPU address changing as the image is rendered, so any time vblank, before rendering starts is fine.

Re: vram glitches

Posted: Sun Aug 14, 2016 12:00 pm
by dougeff
First things first. It appears to me that you're not using an assembler (because you are posting FCEUX disassembly rather than source code). Do you need help setting up / using an assembler.

Second, you will CLI (anywhere), then set-up the MMC3 scanline IRQ during v-blank. Then you will (inside the IRQ handler) change the scroll (or whatever mid-screen event).

You can alternatively, you can set-up another scanline count, if you want another mid-screen split.

Re: vram glitches

Posted: Sun Aug 14, 2016 12:39 pm
by infidelity
Thanks for the info everyone!

I code entirely via hex, using the fceux code data logger and hex editor. That's how I learned and work for over 10 years. I know over here that is unacceptable practice, but it does the same job as writing it out. I can see specific hex and known right away the opcode. I will try to accomplish inserting an irq engine. Thanks again for the info!

Edit - strange, when I set the CLI, it takes me to the irq vector, but when it comes time to RTI it just takes me back to the beginning of the irq vector, putting me in an infinite loop. Idk what im missing so I can get back to where the CLI started.

Re: vram glitches

Posted: Sun Aug 14, 2016 4:12 pm
by tokumaru
infidelity wrote:I know over here that is unacceptable practice, but it does the same job as writing it out. I can see specific hex and known right away the opcode.
I don't see any problems with writing small programs or patches that way, I've done it myself several times. The problem is maintaining complex programs, such as full games. Managing memory is a nightmare, because if you ever need to relocate a variable for whatever reason (I move variables around A LOT!) you have to find every single instruction that references that variable and change the address. Same thing with branches and jumps... if you need to add/remove instructions to/from an existing block of code, you have to manually adjust all addresses and offsets that point to the relocated code. It's simply not practical. Labels are absolutely essential for any large scale assembly project.

I've given up on talking you out of the madness that is writing NES programs using bare hex. Maybe you are some sort of programming wizard that gets programs right on the first try every single time, and never needs to relocate code or variables, but I'm very skeptical about the existence of such a programmer, to be honest. Maybe you'll realize how impractical working without labels is as you progress with this game.
strange, when I set the CLI, it takes me to the irq vector, but when it comes time to RTI it just takes me back to the beginning of the irq vector, putting me in an infinite loop. Idk what im missing so I can get back to where the CLI started.
Don't forget that the APU also generates IRQs, so be sure to disable those in the initialization code to prevent the APU from firing periodic IRQs and seeing up your scanline counting. You also have to acknowledge the MMC3 IRQs in the IRQ handler, otherwise the IRQ signal will remain asserted and the CPU will just keep jumping back to the IRQ handler.