Does anyone know offhand how many cycles the NES uses for initialization before the cart is accessed (memory location $8000 is read from)? I can determine this myself using some counters, latches, resistors, and LEDs, but I was wondering if someone had already done it and could just tell me the result. Plus, I don't have any counters handy.
If you'd like to find out, just wire two counters in cascade, wire the clock for the first counter to cart edge 37 (CLK), wire LE on the latches to PRG /CE, and wire the counter outputs to the latch inputs. When the NES pulls PRG /CE low, the latches will freeze the output of the counters, and you can use an LED/resistor pair to read the binary value of the number of cycles that passed before the cart was queried.
Anyone feel like doing some experimenting for me?
Normally, scince the /RESET signal goes up, the CPU will imediately read the RESET vecor at $fffa (NOT $8000), and load the Programm Counter with this value.
The NES has no initialization delay - upon powerup, the CPU immediately reads from addresses $FFFC and $FFFD (the RESET vector) and jumps to the address stored in those values.
If you want to be technical about it, there are exactly 5 cycles before the reset vector is accessed, during which the CPU makes an opcode fetch (ignored), an operand fetch (ignored), and 3 blocked* stack writes, which is nothing more than the 6502's interrupt handler sequence.
* during normal interrupt handling, there are 3 stack writes (PCL, PCH, and flags); during RESET, writes are blocked, so it simply reads from the stack instead while still decrementing the stack pointer each time.
Does that imply that the CPU immediately reads from $FFFA upon power-up, and then jumps directly to the address contained in $FFFA? There is no power-up init sequence to clear out registers or anything of the sort before PRG /CE goes low?
This actually simplifies what I'm doing, since I can just push PC to $C000, but I was hoping for a clock cycle or two so I could make sure a few things were pulled low even before $FFFA was read.
(Posted before I saw your reply, quietust -- I'm not a flipping moron, I swear)
Yeah, the vector adress at $fffc-$fffd (I was wrong before, $fffa is actially the NMI vector) is directly taken care. You should do your "init" code youreself.
I didn't get the exact details about what Q said, but I don't think that is would be significant for understanding or coding. Yeah, RESET is basically an interupt, so maybe the "programm counter" (that would contain gabarage at this point) and the processor status (also gabarage) may be pushed, like on an NMI or IRQ, if I understood well.
PRG /CE is tied on GND on many cards, so the ROM is always active, this has nothing to do with /RESET.
Quietust wrote:
If you want to be technical about it, there are exactly 5 cycles before the reset vector is accessed, during which the CPU makes an opcode fetch (ignored), an operand fetch (ignored), and 3 blocked* stack writes, which is nothing more than the 6502's interrupt handler sequence.
Ah! I do want to be technical about it. Five cycles is plenty of time for my purposes. Thanks!
Bregalad, the PRG /CE line is driven from the CPU, is it not? I thought it was pulled low only when the on-cart PRG ROM should be active, and driven high when the CPU was working with internal RAM or registers. If it's wired to GND, wouldn't the cart's ROM interfere with those requests?
The PRG /CE line comes in from the cart edge and is defined as /(A15 & Φ2). As such, it is low when the CPU is accessing $8000-$FFFF and high otherwise (i.e. when accessing $0000-$7FFF as well as between all memory accesses).
Thanks for the clarification. One more question -- what exactly is the function of the M2 line?
M2 (or Phi2) is the clock from the CPU.
When high all address and data lines are valid.
BTW, what's the CPU doing when phi2 is low?
Could it be reading/writing memory? or are the address/data lines in set up state?
I thought pin 37 was the clock from the CPU. If M2 is the CPU clock, what's pin 37? Vblank?
Sorry to give you wrong info about /CE, I actually confused it with /OE (outpout enable) that is tied to GND to almost all NES carts I checked. I think there is few difference between the function of /CE (that would "disable" the chip if high, and /OE (that would set all outpouts to high impedence). I think /CE disable internal adress decoding, while /OE doesn't. Also, a low to high edge on /CE would make effect slower than /OE, scince the chip has to decode the adress before actually outpout the result. I'm not very sure about it, tough. I don't know if MMC1, MMC3, etc... card that disables the rom while writing to $8000-$ffff uses some logic with the /A15 signal or if it would connect /RW to /OE.
I think that M2 is CPU clock, and the other clock is the main clock, which is faster.
Pin 37 is CLK 21.47727 Mhz (NTSC), which, if you divid by 12, you get M2 which is 1.7897725 MHz.
The 2A03 must have an internal divider (12), as the 6502 outputs the same clock speed that comes in; however, it is slightly delayed, which is why you must use phi2 out of the 6502.
Ah, ok, so the 2A03 uses a 12-step internal cycle. CLK is the master clock, M2 is the CPU clock. That makes sense.
Is there any sort of timing diagram available for the 2A03? Specifically, I'm interested in exactly when the 2A03 needs data to be valid on the PRG data bus after M2 goes high. There are 12 (six?) steps -- at which step does it acutally pull in the data from the bus?
Let me back up a bit. Here's what I'm trying to do:
I've got an NES standard ROM (in this case, Ice Climber) with a 16K PRG chip and an 8K CHR chip. I've run the address and data lines for each of these, along with their associated R/W and /CE lines, through a bus switch that is controlled by a microcontroller. On the other side of the bus switch is two 8K EPROMs which contain custom code (the PRG EPROM is mirrored at $8000 and $C000). The microcontroller can control which of the two sets of chips can reach the NES -- the Ice Climber ROM chips or my custom EPROM chips.
The idea is that the code on the EPROM will signal the microcontroller (via a write to a specific memory location) when it is ready to give up control. The EPROM will jump to the address contained in the Ice Climber reset vector. Just as that jump occurs, the microcontroller will switch the bus so that the Ice Climber data is readable, which causes the game to proceed normally.
The problem I'm having is that I don't know exactly when the bus will need to be changed, or exactly how long I have to change it. When M2 is high, I know that the address lines won't change, but I don't know at what point before M2 goes low the data needs to be valid.
It just occured to me that the Game Genie does exactly what I'm trying to do -- by pressing [start] at the Game Genie screen it transfers control to the cart. How does the Game Genie handle this? I suppose I ought to look at its code.
rox_midge wrote:
The problem I'm having is that I don't know exactly when the bus will need to be changed
If you want to bankswitch from your custom ROM to the Ice Climber ROM sing a mapper register, then try putting the mapper write and the JMP ($FFFC) in RAM.
Oh, f-ing DUH -- write $6C $FF $FC to $0200-$0202, write to the 'mapper' (the microcontroller in this case), then jump to $0200. The bankswitch is performed shortly thereafter, leaving no hardcore timing issues.
Thanks for the answers to my questions, all.
Actually, it'd be $FC $FF because the 6502 is little-endian.
For a bit more safety so that it won't depend as much on exact microcontroller timing, I'd suggest putting the mapper writes, a loop to burn some CPU time, and the jump all in RAM.
Code:
RAM_code_start:
; write to the mapper
lda #42
sta $8000
; Burn 1280 cycles to wait for even the slowest mapper to catch up
ldy #0
:
iny
bne :-
jmp ($fffc)
RAM_code_end:
; last thing your custom ROM should do is this:
ldx #0
:
lda RAM_code_start,x
sta $0200,x
inx
cpx #RAM_code_end-RAM_code_start
bne :-
jmp $0200
rox_midge:
If you do decide to look at the GG's source code, this RE I've started (and as usual have left unfinished until I have some free time again) might come in handy:
http://www.student.itn.liu.se/~miciw347/nes/GG_RE.zip
And anyone having a non-glop-top GG for sale: please contact me :)
Thanks Bananmos, it looks like the Game Genie is doing exactly what tepples suggested. Now that I've seen it done, it's blindingly obvious that's how it should be done, but I suppose that's what learning is all about
Thanks for your help tepples