It is currently Sun Oct 22, 2017 7:46 pm

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 41 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 5:28 pm 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
I'm writing a simple video player ROM from scratch, and I'm confused on something. With the following code:

Code:
arch snes.cpu

macro seek(variable offset) {
    origin (offset) & $3FFFFF
    base offset
}

// ===Interrupt Handlers===
seek($C00500)
nmi:
// Do NMI stuff
    rti
irq:
// Do IRQ stuff
    rti

// ===Initialization Routine===
seek($C02000)
__init:
// Init stuff here
// . . .
    jml __main

// ===Interrupt Vectors===
seek($C0FF00)
// RESET
    sei
    clc
    xce
    rep #$18
    ldx #$1FFF
    txs
    jml __init

seek($C0FF10)
// NMI
    jml nmi

seek($C0FF14)
// IRQ
    jml irq

seek($C0FF18)
// BRK
-//  lda $ABCDEF
    bra -

seek($C0FFFF)
// EMPTY VECTOR
    rti

seek($C0FFB0)
// ===Internal Header===
snes_header:
    dw $3713            // Maker code
    db 'M','S','U','1'  // Game code
    // Reserved
    db $00,$00,$00,$00,$00,$00,$00
    db $00              // Exp RAM size
    db $00              // Special version
    db $00              // Cartridge type
    // ROM Name
    db 'M','S','U','-','1',' ','V','i','d','e','o'
    db ' ','T','e','s','t',' ','R','O','M',' '
    db $31              // Mapper
    db $02              // ROM type
    db $0C              // ROM size
    db $03              // SRAM size
    db $01              // Country code
    db $33              // Reserved
    db $01              // Version number
    dw $AA00            // Checksum complement
    dw $55FF            // Checksum

// ===Vector Table===
// Native Mode
    dd $FFFFFFFF        // UNUSED
    dw $FFFF            // COP
    dw $FF18            // BRK
    dw $FFFF            // ABORT
    dw $FF10            // NMI
    dw $FFFF            // RESET
    dw $FF14            // IRQ

// Emulation Mode
    dd $FFFFFFFF        // UNUSED
    dw $FF18            // COP
    dw $FFFF            // BRK
    dw $FFFF            // ABORT
    dw $FFFF            // NMI
    dw $FF00            // RESET
    dw $FFFF            // IRQ

seek($D00000)
__main:
    sep #$20        // Set the A register to 8-bit.

    lda #$80
    sta $4200   // Enable NMI

// Loop forever.
-; bra -


I would expect NMI interrputs to jump to $C0FF10, based on the vector table, however, running it in bsnes-plus, if I set a breakpoint on $C0FF10, I never hit it. Instead, I hit $C0FF14 instead. Am I doing something wrong, or just misunderstanding how the vectors work? For now, I've just resorted to putting all of my NMI handling in the IRQ handler instead, which seems to be working, but I'm running into issues where I'm only able to DMA about half of the VRAM data I expect, and I'm curious if maybe this issue is somehow related. Even if not, I'd at least like to try and understand what's going on.


Attachments:
video_test.zip [88.57 KiB]
Downloaded 41 times


Last edited by qwertymodo on Fri Oct 14, 2016 10:32 pm, edited 1 time in total.
Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 7:30 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
I can absolutely assure you with 100% accuracy that VBlank is tied to the NMI vector, not the IRQ vector -- yes, 100% sure.

It looks to me like you're off-by-4 (4 bytes) somewhere, but it's hard to tell.

Is there some reason you aren't providing an assembly listing that contains generated code offsets so you can see what ends up where? Or an actual ROM file so I could go and actually reverse engineer the vectors? An assembly listing would be better.

You've convoluted the process by trying to stick the SNES header + native mode vectors + emulation mode vectors all into one seek($C0FFB0), requiring me to sit down and figure out where each/every byte goes.

Why don't you try putting seek($C0FFE4) in front of your native mode vectors, and seek($C0FFF4) in front of your emulation mode vectors? You can remove the dd $FFFFFFFF statements. And because there's no BRK vector in emulation mode, you can set that to $0000 (it makes it more clear than $FFFF).

Also, you shouldn't use $FFFF as a vector point for anything. Do you know why? Bank $00 is where all the vectors are read, and to my knowledge bank wrapping doesn't happen on vectors (i.e. a vector of $FFFF will either jump to code at $00FFFF (low) and $010000 (high) or $00FFFF (low) and $000000 (high). My guess is the latter.

Also, you really need to be setting your emulation mode vector addresses properly. Guess what mode the CPU starts in? Emulation mode. Vectors read by the CPU natively are actually in bank $00, which is presumably mapped to bank $C0 in the memory model you're using. You should also be setting your RESET vector (in native mode) to the same place as in native mode.

And finally: I can't even determine how your RESET vector is working right now. I don't see how $FFFF (native) or $FF00 (emulation) point to anything in __init. Oh wait, actually, they would point to the rti you have under seek($C0FFFF) (for native). Why aren't you doing things like dw __nmi then making a __nmi label? You've made this troubleshooting process a huge, HUGE pain in the ass.

One more edit: what assembler is this? I really want to know. What you're using looks more like a "patching assembler" (I'm thinking bass or xkas? I forget which tool), and not an "assembler" in the classic sense.


Last edited by koitsu on Fri Oct 14, 2016 7:39 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 7:34 pm 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 137
By the way, why are these repeated like this?

Code:
seek($C0FF10)
// NMI
    jml nmi

seek($C0FF14)
// IRQ
    jml irq

seek($C0FF18)
// BRK
-//  lda $ABCDEF
    bra -

seek($C0FFFF)
// EMPTY VECTOR
    rti

seek($C0FF10)
// NMI
    jml nmi

seek($C0FF14)
// IRQ
    jml irq

seek($C0FF18)
// BRK
-//  lda $ABCDEF
    bra -

seek($C0FFFF)
// EMPTY VECTOR
    rti

I don't think it would cause your particular issue, but there's no reason to duplicate these lines.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 8:37 pm 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
Nicole, that was a stupid copy/paste error, I'll fix it as soon as I'm not on my phone. Koitsu, this is bass v14, yes a patching assembler, since this is actually going to be turned into a patch, but I wanted to get the functionality working on its own. I'll post a ROM when I get home. I copied the vector tables from Chrono Trigger, including the FFFF's (they didn't have the rti at C0FFFF as far as I know, I just did that because I thought it made sense, maybe I was wrong about that).


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 8:59 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
If this is a "patched ROM" (i.e. a patched commercial ROM), please do not upload it here -- it will be deleted by a mod immediately citing copyright. An IPS patch would be fine.

There's nothing wrong with using rti as code at a vector point. But it sounds like the commercial ROM just set unused vectors to $FFFF (this is probably because Nintendo mandated that "unused portions of a ROM be filled with $FF" even though tons of games didn't do this -- it just made it easier on the EPROM and mask ROM process (hardware folks please correct me if I'm wrong)).

Either way, I can assure you that VBlank is tied to NMI, not IRQ. Geiger's SNES9x with debugging capabilities, although runs extremely wonky in present-day OSes (Windows 7 up), will give you vector information. I think there's a modified bsnes-classic that has some debugging capability as well.

Chrono Trigger has a special place in my heart, filed under "games that really made my (technical) life hell" (for a couple reasons), so I'm already gritting my teeth. ;)

Edit: these are the official vectors from Chrono Trigger (MD5 and filename: a2bc447961e52fd2227baed164f729dc Chrono Trigger (U) [!].sfc). "8-bit" means emulation mode, "16-bit" means native mode.

Code:
Vectors:
   8 Bit      16 Bit
ABT   $00:FFFF   $00:FFFF
BRK   $00:FFFF   $00:FF18
COP   $00:FF18   $00:FFFF
IRQ   $00:FFFF   $00:FF14
NMI   $00:FFFF   $00:FF10
RES  $00:FF00

Review of the actual code at vectors $FF18 (native mode BRK and emulation mode COP), and $FFFF (a placeholder vector, i.e. isn't used), tell me the following:

The $FF18 vector contains an infinite loop that just does an lda $abcdef infinitely (i.e. something you could easily witness/see in a debugger or possibly on a hardware ICE):

Code:
$00/FF18 AF EF CD AB LDA $ABCDEF[$AB:CDEF]   A:0000 X:0000 Y:0000 P:envMXdIzC
$00/FF1C 80 FA       BRA $FA    [$FF18]      A:0000 X:0000 Y:0000 P:envMXdIzC

The $FFFF vector is worthless: $00FFFF (contains $FF) and $000000 (direct page, so it's going to vary). So, this is as I suspected: it's just filling unused vectors with $FFFF.

The RESET vector at $FF00, however, is legitimate:

Code:
$00/FF00 78          SEI                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$00/FF01 18          CLC                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$00/FF02 FB          XCE                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$00/FF03 5C 00 C0 FD JMP $FDC000[$FD:C000]   A:0000 X:0000 Y:0000 P:envMXdIzC
$FD/C000 C2 10       REP #$10                A:0000 X:0000 Y:0000 P:envMXdIzC

The NMI and IRQ vectors for emulation mode are set to $FFFF because the game *immediately* inhibits IRQs and switches to native mode (see above RESET code). This is important because the NMI and IRQ vectors in native mode jump to code located in RAM:

Code:
$00/FF10 5C 00 05 00 JMP $000500[$00:0500]   A:0000 X:0000 Y:0000 P:envMXdIzC
$00/FF14 5C 04 05 00 JMP $000504[$00:0504]   A:0000 X:0000 Y:0000 P:envMXdIzC

In other words: Chrono Trigger, during run-time, almost certainly modifies $000500 to $000503 to a long jump (5C xx xx xx) to a location of its choosing, allowing for different kinds of VBlank and IRQ handling routines to be used. Common technique.

Finally: breakpoints for vectors often requires that you add breakpoints for bank $00 addresses, not higher banks ($80 or $C0). Bank $00 is where the vectors are loaded from in the actual CPU (the vectors are only 16-bit, as you know). Quoting WDC documentation, with the relevant part underlined:

Quote:
When an interrupt is first received, the processor finishes the currently executing instruction and pushes the double-byte program counter (which now points to the instruction following the one being executed when the interrupt was received) and the status flag byte onto the stack. Since the 6502 and 65C02 have only a sixteen-bit program counter, only a sixteen-bit program counter address is pushed onto the stack; naturally, this is the way the 65802 and 65816 behave when in emulation mode as well. The native-mode 65802 and 65816 must (and do) also push the program counter bank register, since it is changed to zero when control is transferred through the bank zero interrupt vectors.

"Program counter bank register" refers to what's known as K, or alternately PCB (program counter bank). This refers to the bank code is currently executing out of. Do not confuse it with B (data bank register).


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 10:07 pm 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
My ROM as it stands is not Chrono Trigger, it is my own code and some of the tutorial code from the super famicom wiki. I only copied a few tiny things I didn't understand like that BRK vector and the vector tables themselves. This is a from-scratch ROM to test out my own video loading code, which I will eventually be turning into a patch for CT, so I wanted things like the mapping to match up just to avoid headaches in that stage of the process. I still don't have access to my laptop, but I'll try to post it in an hour or so when I get home.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Fri Oct 14, 2016 10:38 pm 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
I edited the OP, and uploaded the ROM, which I just now tested again, only to find that the NMI breakpoint at $FF10 was hitting properly. I don't know if it's just a difference between my machines, or if something changed since I posted, or if I was just tired and delirious and thought I was hitting the wrong breakpoint, but whatever it was, it's working now. What *isn't* working, however, is my tile data DMA, which is still only transferring about half of the tiles I queued up (a little over 9,000 bytes per VBLANK over the course of 4 consecutive VBLANKs), but that's another problem for another day.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 12:30 am 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 137
For the DMA, you are giving it the number of bytes to transfer, right? That's what you need, not the number of units to transfer, because DMA uses DASxL/H as a byte counter (it can stop mid-unit).


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 4:48 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
Yeah, what Nicole said. It'd help to just see the code itself (maybe the whole thing, or maybe just relevant snippets including setup procedures done before the transfer, as well as your full NMI routine).


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 5:49 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19116
Location: NE Indiana, USA (NTSC)
qwertymodo wrote:
a little over 9,000 bytes per VBLANK

You appear not to have the Location set in your profile. Are you in Europe? Because unless you're either on a PAL SNES or using the forced blank register ($2100) to disable rendering early and enable it late, you can't fit much more than about 6,000 bytes in a vblank.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 8:35 am 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
I'm in the US, I thought I'd read the number was supposed to be closer to 13K for NTSC, but if that's not correct, that would explain it. My full code is included in the zip attached to the first post (some of the commenting might be incorrect, I'm still figuring out some of these things, and others I might have changed without updating the comment lines, but it should be mostly close).

This is what I'm getting (with 4 VBLANKs).

Image


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 9:52 am 
Offline

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 430
qwertymodo wrote:
I'm in the US, I thought I'd read the number was supposed to be closer to 13K for NTSC, but if that's not correct, that would explain it. My full code is included in the zip attached to the first post (some of the commenting might be incorrect, I'm still figuring out some of these things, and others I might have changed without updating the comment lines, but it should be mostly close).

This is what I'm getting (with 4 VBLANKs).

Image


Yeah, those gaps are almost certainly caused by your program trying to write to VRAM past the end of VBlank and failing.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 10:15 am 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
Then, can anybody help me understand where these numbers are coming from? I need to transfer ~33K over the course of 4 frames (15fps@60Hz), or else I need to drastically reduce my frame size.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 11:02 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19116
Location: NE Indiana, USA (NTSC)
93143's post was assuming the use of 28 lines of forced blanking at the top and 28 at the bottom: "With 168 active scanlines". This matches a 16:9 TV's safe area fairly well.

If you need full frame on a 4:3 TV, you'll need to plan on reusing tiles from frame to frame (possibly including flipping), making some tiles 2-bit (for use on BG3), or using HDMA to change vertical scroll after each scanline to halve the vertical resolution. It's also possible to reduce effective vertical background resolution to 448/3 = 149 lines by mixing vertical scroll with interlace mode so that each scanline of tile data is displayed for an average 1.5 lines.


Top
 Profile  
 
 Post subject: Re: NMI vs IRQ
PostPosted: Sat Oct 15, 2016 11:21 am 
Offline

Joined: Mon Jul 02, 2012 7:46 am
Posts: 759
The source video is letterboxed to 256x144 (or maybe 160, I don't remember), so I'll look into the use of forced blanking. Not really sure how to do that though. This whole video thing is new for me.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 41 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 7 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