It is currently Sat Aug 18, 2018 7:10 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 72 posts ]  Go to page Previous  1, 2, 3, 4, 5
Author Message
PostPosted: Fri Jul 20, 2018 7:05 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6599
Location: Canada
Ah, I see the problem. Wasn't quite where I was suggesting, though related:

You set up your first IRQ here in your main thread code. This happens directly after the NMI returns:
Code:
 00:9BB8: 20 C0 E3  JSR $E3C0 ; wait for NMI
>00:9BBB: A9 01     LDA #$01 ; setup first interrupt
 00:9BBD: 8D 00 E0  STA $E000
 00:9BC0: 8D 00 C0  STA $C000
 00:9BC3: A9 00     LDA #$00
 00:9BC5: 8D 01 C0  STA $C001
 00:9BC8: A9 01     LDA #$01
 00:9BCA: 8D 01 E0  STA $E001
 00:9BCD: A9 00     LDA #$00
 00:9BCF: 85 74     STA $74


The problem is that the music routine delays when you will return from NMI. On PAL there is plenty of time for it to execute before rendering begins, but on NTSC it will overlap the beginning of the frame sometimes. If this first IRQ setup doesn't happen before scanline 0, the whole screen is thrown off. (Seems to be about 10-15 scanlines late on every other frame.)

The solution should be to put this inside your NMI handler. See my last suggestion from my previous post, you should still add that CLI and RTI, but right there above the suggested CLI do this first IRQ setup right there, when you know you're still in vblank (i.e. before scanline 0) and you haven't yet run the music routine. This will allow that first IRQ to fire on scanline 0 (which will sometimes be within the music routine, but it is perfectly okay to interrupt that).


Alternative option is to put the music playback call in your main thread just after that STA $74. This will get your NMI handler returning earlier again.

Ideally both of these things should be within the NMI, though. Having the IRQs set off by the NMI will prevent them from failling if your main thread ever runs too long (slowdown), and similar with music having it in the NMI makes it slowdown resitant. However, if you can guarantee the main thread will never run long it doesn't matter either way.


Top
 Profile  
 
PostPosted: Sun Jul 22, 2018 7:45 am 
Offline

Joined: Thu Nov 24, 2011 7:16 am
Posts: 205
rainwarrior wrote:
My assumption is that you're running your music within the NMI.

The reason this is a problem is that NMI implicitly does a SEI (cleared by the RTI popping the processor flags). So if your music update happens in your NMI routine, it will overlap and block your interrupts if it takes too long, which it does on NTSC.

Easy fix: just put a CLI in the NMI routine just before it calls the music playback (assuming it is the last thing that happens in your NMI handler). Otherwise if that's not feasible, you can just move the music playback outside of the NMI. It doesn't really matter too much where it gets called as long as it's once per frame, preferably at a consistent time (which is why NMI is usually convenient).


Edit: Actually, peeking at it in a debugger, it looks like your NMI is missing an RTI at the end? It seems to roll right into the IRQ handler after finishing. So in this case, I'd recommend putting a CLI before the music playback there, and also an RTI before the IRQ handler begins.
Code:
 03:E224: A9 00     LDA #$00
 03:E226: 85 02     STA $02 = #$03
 03:E228: 20 4C E8  JSR $E84C ; music playback? place a CLI right before this line
 03:E22B: 68        PLA
 03:E22C: A8        TAY
 03:E22D: 68        PLA
 03:E22E: AA        TAX
 03:E22F: 68        PLA ; shouldn't an RTI follow this line?
>03:E230: 48        PHA ; IRQ handler starts here
 03:E231: 8A        TXA
 03:E232: 48        PHA
 03:E233: 98        TYA
 03:E234: 48        PHA
...
 03:E260: 40        RTI


rainwarrior wrote:
Ah, I see the problem. Wasn't quite where I was suggesting, though related:

You set up your first IRQ here in your main thread code. This happens directly after the NMI returns:
Code:
 00:9BB8: 20 C0 E3  JSR $E3C0 ; wait for NMI
>00:9BBB: A9 01     LDA #$01 ; setup first interrupt
 00:9BBD: 8D 00 E0  STA $E000
 00:9BC0: 8D 00 C0  STA $C000
 00:9BC3: A9 00     LDA #$00
 00:9BC5: 8D 01 C0  STA $C001
 00:9BC8: A9 01     LDA #$01
 00:9BCA: 8D 01 E0  STA $E001
 00:9BCD: A9 00     LDA #$00
 00:9BCF: 85 74     STA $74


The problem is that the music routine delays when you will return from NMI. On PAL there is plenty of time for it to execute before rendering begins, but on NTSC it will overlap the beginning of the frame sometimes. If this first IRQ setup doesn't happen before scanline 0, the whole screen is thrown off. (Seems to be about 10-15 scanlines late on every other frame.)

The solution should be to put this inside your NMI handler. See my last suggestion from my previous post, you should still add that CLI and RTI, but right there above the suggested CLI do this first IRQ setup right there, when you know you're still in vblank (i.e. before scanline 0) and you haven't yet run the music routine. This will allow that first IRQ to fire on scanline 0 (which will sometimes be within the music routine, but it is perfectly okay to interrupt that).


Alternative option is to put the music playback call in your main thread just after that STA $74. This will get your NMI handler returning earlier again.

Ideally both of these things should be within the NMI, though. Having the IRQs set off by the NMI will prevent them from failling if your main thread ever runs too long (slowdown), and similar with music having it in the NMI makes it slowdown resitant. However, if you can guarantee the main thread will never run long it doesn't matter either way.



Sorry for taking a long time to answer. Busy.

We'll see. I do not have much idea of ​​assembler, but let's see if I can fix this.

The routine that NMI controls is part of the NESlib library. According to the instructions that you indicate, I should put a CLI control before the JSR FamiToneUpdate line and it would look like this:

Code:

;NMI handler

nmi:

...
...
...

@skipNtsc:

   cli
   jsr FamiToneUpdate

   
   pla
   tay
   pla
   tax
   pla


This is correct?

_________________
Projects:
Shadow of the Beast (port)
The Sword of Ianna
The Banketh - The Video Game

My website: RetroNES


Top
 Profile  
 
PostPosted: Sun Jul 22, 2018 9:13 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6599
Location: Canada
Well, there are three things:

1. Put the IRQ setup in your NMI handler before jsr FamitomeUpdate so that it is guaranteed to happen before the end of vblank.
2. Right after the IRQ setup, put cli (also before jsr FamitoneUpdate) so that if an IRQ happens during the music routine it won't be blocked.
3. Put rti on the end of your NMI handler (after that ...tax, pla). Without this, the code just keeps running into the IRQ handler directly below.

The main thing I'm not entirely certain of, without looking at much more of the code, is whether it's appropriate to set up the IRQ every NMI or just on screens that need it. Maybe it should have a flag that turns it on and off? (When I say IRQ setup I mean that code including lines $9BBB to $9BCF in that disassembly.)

As an alternative, just as a quick test, you could just take jsr FamitomeUpdate and move it just under the IRQ setup where it is right now. (Just after where it stores a #0 to your IRQ counter variable at $74.) That would also solve the problem you're having that this music update is happening before you've prepared your IRQs to fire. I wouldn't recommend this as a permanent solution, though, because it's usually appropriate to do music in the NMI handler. If it's not in the NMI handler, music will tend to skip during scene transitions, and also you would need to manually call jsr FamitoneUpdate in each main thread frame loop if there are more than one.


Top
 Profile  
 
PostPosted: Mon Jul 23, 2018 1:22 am 
Offline

Joined: Thu Nov 24, 2011 7:16 am
Posts: 205
Ok, let's see. Right now this is like this:

Code:
;NMI handler

nmi:

...
...
...

@skipNtsc:   
   
   LDA #$01    ; turn off MMC3 IRQ
   STA $E000
   STA $C000   ; count 20 scanlines, then IRQ
   LDA #$00
   STA $C001
   LDA #$01
   STA $E001   ;turn on MMC3 IRQ
   LDA #$00
   STA $74

   cli
   
   jsr FamiToneUpdate

   
   pla
   tay
   pla
   tax
   pla

   rti



irq:
   pha
   txa
   pha
   tya
   pha
   ldy #15            
:   dey               
   bne :-             

   ldx _Scroll_Index    
   lda _Scroll, x
   sta $2005         
   lda _scrollY       
   sta $2005         
   inc _Scroll_Index

   lda #1
   sta $e000          
   lda #14            
   sta $c000          
   sta $c001
   lda #1
   sta $e001          
   
   pla
   tay
   pla
   tax
   pla
   rti



I share the rom. It works in NES PAL and in the emulated NEStopia but now it gives problems in FCEUx and VirtuaNES.


Attachments:
Shadow of the Beast (alpha 0.31) [HB].nes [128.02 KiB]
Downloaded 27 times

_________________
Projects:
Shadow of the Beast (port)
The Sword of Ianna
The Banketh - The Video Game

My website: RetroNES
Top
 Profile  
 
PostPosted: Mon Jul 23, 2018 9:28 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6599
Location: Canada
I think the problem is right here:
Code:
 00:9BB9: 20 D8 E3  JSR $E3D8 ; wait for NMI to finish
 00:9BBC: A9 00     LDA #$00
>00:9BBE: 85 74     STA $74 = #$00 ; reset raster split index
 00:9BC0: AD C3 04  LDA $04C3 = #$04


You moved the IRQ setup into the NMI (before that CLI) but you left this reset of $74 to 0 in the main loop as soon as it returns from the NMI. I don't know what you call the variable at $74 but it appears to be an index into your table of how many scanlines to skip per split. Leaving this extra $74 = 0 in there causes the splits to start over in the middle of the screen.

Doesn't cause a problem in PAL or without music on NTSC because if NMI finishes before vblank it hasn't run any IRQs yet (resets 0 back to 0). Once you add music in, some IRQs will happen before the music is finished, and this reset ends up mid-screen.

(If I replace that STA $74 with two NOPs it seems to run as correctly as the other modes.)


Edit: Oh, you called $74 _Scroll_Index in your IRQ code, you should use that at @skipNtsc too just in case the variable ever moves. I was only calling it $74 because I was looking at it through a disassembly.


Top
 Profile  
 
PostPosted: Mon Jul 23, 2018 2:06 pm 
Offline

Joined: Thu Nov 24, 2011 7:16 am
Posts: 205
rainwarrior wrote:
Oh, you called $74 _Scroll_Index in your IRQ code, you should use that at @skipNtsc too just in case the variable ever moves. I was only calling it $74 because I was looking at it through a disassembly.


Ok, now I have understood.

According to the dougeff tutorial everything that corresponds to the IRQ configuration, etc ... is written in C, even the variable Scroll_Index I put it to 0 from there.

https://nesdoug.com/2016/01/15/24-mmc3- ... hing-irqs/

When you have indicated the faults that you see from assembler, I have not understood very well, but I let myself be guided by you until I understood it.

Well, what I have done next has been to change those two lines and put them in this way:

Code:
   LDA #$00
   STA _Scroll_Index ; ponemos Scroll_Index a 0


Now the rom seems to work well in the emulators VirtuaNES, NEStopia, FCEU, etc ...

I just need to know if it works well now in an NTSC NES.


Attachments:
Shadow of the Beast (alpha 0.32) [HB].nes [128.02 KiB]
Downloaded 28 times

_________________
Projects:
Shadow of the Beast (port)
The Sword of Ianna
The Banketh - The Video Game

My website: RetroNES
Top
 Profile  
 
PostPosted: Mon Jul 23, 2018 3:42 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6599
Location: Canada
That looks better in terms of scrolling.

One more issue though: you haven't set up 4 of the CHR banking registers. You can see the problem using Mesen, but it appears the same way on my PowerPak (i.e. the character sprite and moon sprite are using the wrong tiles). This isn't NTSC / PAL related, it is only about fully initializing the MMC3 (would look the same on PAL PowerPak/Mesen).

Of the 8 bank settings on the MMC3 (selected through $8000) I see setup for: 0, 1, 6, 7 (PPU first page, and CPU banks). You are missing any setup for 2, 3, 4, 5 (PPU second page, i.e. all your sprites).

Some emulators, and apparently the Everdrive, pre-initialize these with default values, but on the real MMC3 these are "random" when powered on. (You can see what FCEUX uses instead of randomness, for example. This seems to be a common setup pattern for emulators, Everdrive must have borrowed it.)

Anyhow, really easy to fix, just send 4,5,6,7 to the uninitialized banks 2,3,4,5 in your startup code:
Code:
lda #2
sta $8000
lda #4
sta $8001
lda #3
sta $8000
lda #5
sta $8001
lda #4
sta $8000
lda #6
sta $8001
lda #5
sta $8000
lda #7
sta $8001


Top
 Profile  
 
PostPosted: Mon Jul 23, 2018 3:47 pm 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20417
Location: NE Indiana, USA (NTSC)
The 0, 2, 4, 5, 6, 7, 0, 1 pattern seen in FCEUX MMC3RegReset() sets up an identity mapping: PPU $0000-$1FFF = CHR ROM $00000-$01FFF. It's also what my stock MMC3 init code sets up.


Top
 Profile  
 
PostPosted: Tue Jul 24, 2018 6:19 am 
Offline

Joined: Thu Nov 24, 2011 7:16 am
Posts: 205
rainwarrior wrote:
That looks better in terms of scrolling.

One more issue though: you haven't set up 4 of the CHR banking registers. You can see the problem using Mesen, but it appears the same way on my PowerPak (i.e. the character sprite and moon sprite are using the wrong tiles). This isn't NTSC / PAL related, it is only about fully initializing the MMC3 (would look the same on PAL PowerPak/Mesen).

Of the 8 bank settings on the MMC3 (selected through $8000) I see setup for: 0, 1, 6, 7 (PPU first page, and CPU banks). You are missing any setup for 2, 3, 4, 5 (PPU second page, i.e. all your sprites).

Some emulators, and apparently the Everdrive, pre-initialize these with default values, but on the real MMC3 these are "random" when powered on. (You can see what FCEUX uses instead of randomness, for example. This seems to be a common setup pattern for emulators, Everdrive must have borrowed it.)

Anyhow, really easy to fix, just send 4,5,6,7 to the uninitialized banks 2,3,4,5 in your startup code:
Code:
lda #2
sta $8000
lda #4
sta $8001
lda #3
sta $8000
lda #5
sta $8001
lda #4
sta $8000
lda #6
sta $8001
lda #5
sta $8000
lda #7
sta $8001


I have not understood what this really does, but I have tried to fix it.

Is it right now?


Attachments:
Shadow of the Beast (alpha 0.33) [HB].nes [128.02 KiB]
Downloaded 27 times

_________________
Projects:
Shadow of the Beast (port)
The Sword of Ianna
The Banketh - The Video Game

My website: RetroNES
Top
 Profile  
 
PostPosted: Tue Jul 24, 2018 8:49 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6599
Location: Canada
Yes, this one now works on PowerPak on my (NTSC) NES with music. It also works in Mesen. The only emulator that seems to fail with it now is Nintendulator, but I'm not sure why that is.

There are smaller glitches still, I'm sure you've seen, but the main stuff is working. This is good!!


Top
 Profile  
 
PostPosted: Tue Jul 24, 2018 9:41 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6599
Location: Canada
The problem this Nintendulator is the same kind of issue as with the sprites, just this time with PRG banking. You haven't initialized the bank at $8000-9FFF (banking register 6) before you use it. Apparently almost all emulators initialize this to 0, and even the PowerPak and Everdrive seem to do this too, but again this would be random on the real MMC3 cart.

Your startup code:
Code:
 03:E005: A9 40     LDA #$40 ; reset begins here
 03:E007: 8D 17 40  STA $4017 = #$00
 03:E00A: 78        SEI
 03:E00B: A2 FF     LDX #$FF
 03:E00D: 9A        TXS
 03:E00E: E8        INX
 03:E00F: 8E 01 20  STX $2001 = #$00
 03:E012: 8E 10 40  STX $4010 = #$00
 03:E015: 8E 00 20  STX $2000 = #$00
 03:E018: 2C 02 20  BIT $2002 = #$00
 03:E01B: 2C 02 20  BIT $2002 = #$00
 03:E01E: 10 FB     BPL $E01B
 03:E020: 2C 02 20  BIT $2002 = #$00
 03:E023: 10 FB     BPL $E020
 03:E025: A9 3F     LDA #$3F
 03:E027: 8D 06 20  STA $2006 = #$00
 03:E02A: 8E 06 20  STX $2006 = #$00
 03:E02D: A9 0F     LDA #$0F
 03:E02F: A2 20     LDX #$20
 03:E031: 8D 07 20  STA $2007 = #$00
 03:E034: CA        DEX
 03:E035: D0 FA     BNE $E031
 03:E037: 8A        TXA
 03:E038: A0 20     LDY #$20
 03:E03A: 8C 06 20  STY $2006 = #$00
 03:E03D: 8D 06 20  STA $2006 = #$00
 03:E040: A0 10     LDY #$10
 03:E042: 8D 07 20  STA $2007 = #$00
 03:E045: E8        INX
 03:E046: D0 FA     BNE $E042
 03:E048: 88        DEY
 03:E049: D0 F7     BNE $E042
 03:E04B: 8A        TXA
 03:E04C: 95 00     STA $00,X @ $0000 = #$F7
 03:E04E: 9D 00 01  STA $0100,X @ $0100 = #$52
 03:E051: 9D 00 02  STA $0200,X @ $0200 = #$B6
 03:E054: 9D 00 03  STA $0300,X @ $0300 = #$B6
 03:E057: 9D 00 04  STA $0400,X @ $0400 = #$4E
 03:E05A: 9D 00 05  STA $0500,X @ $0500 = #$2A
 03:E05D: 9D 00 06  STA $0600,X @ $0600 = #$84
 03:E060: 9D 00 07  STA $0700,X @ $0700 = #$2A
 03:E063: E8        INX
 03:E064: D0 E6     BNE $E04C
 03:E066: A9 04     LDA #$04
 03:E068: 20 0E E3  JSR $E30E
 03:E06B: 20 E3 E2  JSR $E2E3
 03:E06E: 20 39 E3  JSR $E339
>03:E071: 20 91 9F  JSR $9F91 ; crash occurs here!
 03:E074: 20 FD 9E  JSR $9EFD


You need to initialize banking register 6 before that line is reached. These 4 lines would do it:
Code:
lda #6
sta $8000
lda #0
sta $8001


However, it's probably a good idea to initialize all 8 MMC3 bank registers very early on in your startup code. Like I see that you've added the CHR banking initialization that I suggested but it takes place a long time after this startup routine. Might as well do all 8 in here at once. Tepples posted a suggested initial set of values to load earlier on (it's the same as FCEUX and some other emulators use, probably the same as Everdrive's initialization too).


Top
 Profile  
 
PostPosted: Tue Jul 24, 2018 4:20 pm 
Offline

Joined: Thu Nov 24, 2011 7:16 am
Posts: 205
rainwarrior wrote:
The problem this Nintendulator is the same kind of issue as with the sprites, just this time with PRG banking. You haven't initialized the bank at $8000-9FFF (banking register 6) before you use it. Apparently almost all emulators initialize this to 0, and even the PowerPak and Everdrive seem to do this too, but again this would be random on the real MMC3 cart.

You need to initialize banking register 6 before that line is reached. These 4 lines would do it:
Code:
lda #6
sta $8000
lda #0
sta $8001


However, it's probably a good idea to initialize all 8 MMC3 bank registers very early on in your startup code. Like I see that you've added the CHR banking initialization that I suggested but it takes place a long time after this startup routine. Might as well do all 8 in here at once. Tepples posted a suggested initial set of values to load earlier on (it's the same as FCEUX and some other emulators use, probably the same as Everdrive's initialization too).


Ok, it seems that now it works correctly in Nintendulator.

Yes, this technical demo contains minor errors about the scroll and the nametables.


Attachments:
Shadow of the Beast (alpha 0.34) [HB].nes [128.02 KiB]
Downloaded 40 times

_________________
Projects:
Shadow of the Beast (port)
The Sword of Ianna
The Banketh - The Video Game

My website: RetroNES
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 72 posts ]  Go to page Previous  1, 2, 3, 4, 5

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


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