I don't know what "falling edge" means. This is again more hardware talk and doesn't really shed any light on what actually happens at a software level (read: does the CPU notice hardware NMI and thus run code at NMI vector or not?). What is it going to take for folks to actually comprehend this point? :P
Likewise, descriptions
like the below ("forced high", "output low", "output high", etc.) are a little more helpful but not by much. The below seems to imply that "NMI output low" means "NMI is firing / code at NMI vector will be executed". Whether or not that's "falling edge" is unknown to me.
A forced blank is accomplished by setting bit 7 of $2100 to 1. It essentially "turns the screen off" (meaning you get a black screen, or black for whatever duration you set it + unset it), but the electron gun and video synchronisation stuff keep working during this time.
Some of the below is irrelevant to the discussion topic. The important stuff is at the top.
Code: Select all
INTERRUPTS
----------
The internal timer will set its NMI output low at H=0.5 at the beginning of
V-Blank. The CPU's /NMI input is forced high by clearing bit 7 of register
$4200, so the CPU may not actually see the NMI transition. The CPU will jump to
the NMI routine at the end of the instruction during which /NMI transitions.
The internal timer sets its NMI output high at H=0 V=0, or when register
$4210 is read. Possibly also when $4200 is written?
If the CPU is halted (i.e. for DMA) while /NMI goes low, the NMI will trigger
after the DMA completes (even if /NMI goes high again before the DMA
completes). In this case, there is a 24-30 cycle delay between the end of DMA
and the NMI handler, time enough for an instruction or two.
The internal timer will set its IRQ output low under the following conditions
('x' and 'y' are bits 4 and 5 of $4200, HTIME is registers $4207-8, and VTIME
is $4209-a):
yx trigger point
00 => Never
01 => H-IRQ: every scanline, H=HTIME+~3.5
10 => V-IRQ: V=VTIME, H=~2.5
11 => HV-IRQ: V=VTIME, H=HTIME+~3.5
The actual formula for the trigger point is as follows. V-IRQ is just like
HV-IRQ with H=0. If H=0, $4211 bit 7 gets set 1374 master cycles after dot 0.0
of the previous scanline. Otherwise, it gets set 14+H*4 master cycles after
dot 0.0 of the current scanline. Note that the 'dot offset' will change due to
the two long dots per scanline. Also, no IRQ will trigger for dot 153 on the
short scanline in non-interlace mode, and no IRQ will trigger for dot 153 on
the last scanline of any frame.
The internal timer will set its IRQ output high when $4211 is read, or when
IRQs are disabled by a write to $4200. Note that the expansion port and the
cart connector both have access to the /IRQ line, and may be able to trigger
IRQs on their own. When enabling IRQs, the IRQ output will go low even if the
enable write occurs at the exact cycle when the IRQ is scheduled to trigger
For example, if HV-IRQ is set for (0,1) and the last cycle of the STA $4200 is
at (0,0)+1372 master cycles, the IRQ line will still go low.
The CPU will jump to the NMI or IRQ handler at the end of the instruction when
/NMI transitions or when /IRQ is low and the I flag is clear. The actual check
occurs just before the final CPU cycle of the instruction, which means that the
jump will begin at the earliest 6 to 12 master cycles after /NMI or /IRQ. Also
note that PLP, CLI, SEI, SEP #$04, and REP #$04 update the flags during their
final CPU cycle, so the IRQ check will use the old value of I rather than the
new one set by the current instruction. RTI, BRK, and COP on the other hand do
not have this issue.
So for the following code:
> ; set up IRQ
> SEI
> WAI
> STZ $00
> LDA #$01
> CLI
> LDA #$42
> STP
>
> IRQHandler:
> STA $00
> RTI
Memory location $00 will end up set to 0x42, not 0 or 1, because the I flag
isn't clear before the final cycle of CLI. And for the following code:
> ; set up IRQ
> SEI
> WAI
> CLI
> SEI
The IRQ will actually trigger following the SEI instruction, not before it (but
the flags pushed during the IRQ handler will have the I flag set). OTOH, the
following code will not allow an IRQ to trigger at all if the RTI sets the I
flag:
> ; set up IRQ
> SEI
> WAI
> CLI
> RTI
And the following code (with RTI clearing I):
> ; set up IRQ
> SEI
> WAI
> STZ $00
> LDA #$01
> RTI
>
> ; -> RTI returns here
> LDA #$42
> STP
>
> IRQHandler:
> STA $00
> RTI
Will result in memory location $00 being set to 1, not 0x42.
If /NMI and /IRQ are both pending, NMI takes precedence.
And the datasheet is inaccurate regarding that first cycle of the IRQ/NMI
pseudo-opcode. It's an opcode fetch cycle from PB:PC (typically 6 or 8 master
cycles), not an IO cycle (always 6 master cycles) as the datasheet claims.
There is
also this, but it says nothing about NMI:
Note that force blank CAN be disabled mid-scanline. However, this can result in glitched graphics on that scanline, as the internal rendering buffers will not have been updated during force blank. Current theory is that BGs will be glitched for a few tiles (depending on how far in advance the PPU operates), and OBJ will be glitched for the entire scanline. Also, writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur.
And
then this:
Code: Select all
Forced Blank Color
In Forced Blank, the whole screen is Black (no matter of CGRAM settings, Sub
Screen Backdrop Color, and Master Brightness settings). Vsync/Hsync are kept
generated (sending a black picture with valid Sync signals to the TV set)
...
2100h - INIDISP - Display Control 1 (W)
7 Forced Blanking (0=Normal, 1=Screen Black)
6-4 Not used
3-0 Master Brightness (0=Screen Black, or N=1..15: Brightness*(N+1)/16)
In Forced Blank, VRAM, OAM and CGRAM can be freely accessed (otherwise it's
accessible only during Vblank). Even when in forced blank, the TV Set keeps
receiving Vsync/Hsync signals (thus producing a stable black picture). And, the
CPU keeps receiving Hblank/Vblank signals (so any enabled video NMIs, IRQs,
HDMAs are kept generated).
Forced blank doesn't apply immediately... so one must wait whatever
(maybe a scanline) before VRAM can be freely accessed... or is it only
vice-versa: disabling forced blank doesn't apply immediately/shows garbage
pixels?