BGMODE or parameter changes during scanline

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: BGMODE or parameter changes during scanline

Post by koitsu »

Great! When my SD2SNES arrives I'll record stuff and put it up here. Thanks for reviewing stuff + putting up with my delays. (Edit: It's been shipped, so I imagine it'll be here within a week or two. The way Retrogate does their package tracking is bizarre as hell though -- through some third-party site in Ukraine despite them being in Germany. Very weird)

I figured out how to alleviate the audio frequency ramping problem too -- just had to check a couple boxes in VirtualDub (specifically Capture / Timing / Automatically disable resync when integrated audio/video capture is detected). Since the Happauge capture device is doing both audio and video capturing, they're actually always in sync. I figured this out by reading the manual a bit, but also by looking at Capture / Timing graph when doing a test video capture. Now things look great and with very few frame drops (76 for a 1:30 video. 90 seconds * 29.97 fps = 2697.3 frames, 76 / 2697.3 = 0.282 0.0282 frames dropped (0.0282 * 100 = 2.82%), totally acceptable).

I had a bunch else to say about audio stuff (like how apparently some models of SNES units output a high pitch noise (like mine -- I have the original SNES, not a SNES Jr.), but I realised it's not really relevant since we're focused on the video aspect.

Edit: Me doing math wrong (was done right in GNU bc, but I don't tend to copy-paste very much, I type things manually, forgot a zero. :-) Thanks Sik!)
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: BGMODE or parameter changes during scanline

Post by Sik »

I think you forgot a 0 there (0.0282, or 2.82%).

But yeah, so the problem was just bad settings in the end? Go figure. This is probably the most annoying part of video recording, there are just too many settings that can go wrong =P
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: BGMODE or parameter changes during scanline

Post by 93143 »

While we're waiting...

Is there a preferred method of extending VBlank while the IRQ is otherwise occupied?

I was thinking of using a couple of HDMA channels; one to toggle the display and one to hijack the interrupt (which would probably have to be in RAM). This would allow the mode change interrupt code to be as lean as possible, which I imagine is very important for something that runs ~200 times per frame. But if there's a less hacky way to do the same thing, great.

You can't trigger NMI manually, can you? I gather it doesn't trigger on force blank...
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: BGMODE or parameter changes during scanline

Post by koitsu »

There's no way I know of to trigger NMI through software -- it's tied to a pin on the CPU, connected to a particular device (PPU VBlank in this case, or some latch chip that connects to that (I'm talking out my ass here, I don't do EE)). The NMI itself is induced by the hardware it's tied to, e.g. the PPU.

You are correct that forced blank will not trigger NMI.

About my SD2SNES: still waiting. Estimated delivery time from Germany is 15-20 days, and for whatever reason (intentionally) the product goes through cities in Ukraine before going to the US. I can read some Cyrillic, but right now it looks like in Ukraine still on its way here. Last update was on 2014/08/09 and it was originally shipped on 08/05. So another week or so...
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: BGMODE or parameter changes during scanline

Post by tepples »

On the NES, if the NMI hasn't been acknowledged (BIT $2002), disabling and reenabling NMI (LDA #$00 STA $2000 LDA #$80 STA $2000) before vertical blanking has finished will cause an immediate falling edge on /NMI. Does the same thing work on the Super NES?
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: BGMODE or parameter changes during scanline

Post by koitsu »

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?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: BGMODE or parameter changes during scanline

Post by tepples »

The 6502 treats NMI differently from IRQ, and I assume that the 65816 behaves the same way.
  • /IRQ is level sensitive. If /IRQ is held low, the CPU will repeatedly call the IRQ vector every time CLI (or PHP with bit 2 clear) is executed.
  • /NMI is edge sensitive. A transition from high to low causes a flip-flop to get set in the CPU, and the CPU will call the NMI vector only once and not call it again until the signal goes high and low again.
So let me state it from a purely software perspective: On the NES, changing the PPU's NMI enable bit from off to on during vblank causes an immediate call to the NMI vector if the NMI for that frame hasn't already been acknowledged.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BGMODE or parameter changes during scanline

Post by Near »

> You can't trigger NMI manually, can you?

Sure you can.

Push P and your return address onto the stack, and then JML to your NMI vector routine =)

> I can read some Cyrillic, but right now it looks like in Ukraine still on its way here.

Hopefully it's not being transported on a Malaysia Airlines cargo plane :/
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: BGMODE or parameter changes during scanline

Post by tokumaru »

koitsu wrote:The way Retrogate does their package tracking is bizarre as hell though -- through some third-party site in Ukraine despite them being in Germany.
AFAIK, Krikzz, the guy responsible for the Everdrives, lives in Ukraine. For some reason the guy who created the SD2SNES has Krikzz manufacture it. Anyway, I've found retrogate's shipping methods to be pretty reliable, fast and cheap, more so than from any other country I've bought products from (and I never had to pay import taxes for any of my Everdrives or SD2SNES), and the tracking page has an English language option.
User avatar
mikejmoffitt
Posts: 1352
Joined: Sun May 27, 2012 8:43 pm

Re: BGMODE or parameter changes during scanline

Post by mikejmoffitt »

tokumaru wrote:
koitsu wrote:The way Retrogate does their package tracking is bizarre as hell though -- through some third-party site in Ukraine despite them being in Germany.
AFAIK, Krikzz, the guy responsible for the Everdrives, lives in Ukraine. For some reason the guy who created the SD2SNES has Krikzz manufacture it. Anyway, I've found retrogate's shipping methods to be pretty reliable, fast and cheap, more so than from any other country I've bought products from (and I never had to pay import taxes for any of my Everdrives or SD2SNES), and the tracking page has an English language option.
I've found it to be all of those things but fast. But still, the items were in stock and I did receive them.
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: BGMODE or parameter changes during scanline

Post by 93143 »

byuu wrote:> You can't trigger NMI manually, can you?

Sure you can.

Push P and your return address onto the stack, and then JML to your NMI vector routine =)
Well, yeah, it sounds silly when you put it like that...

I guess what I was hoping for with that question was something I could poke with HDMA, since as far as I'm aware it's the only thing left that auto-triggers on a timer (the IRQ is busy with the mode change and needs to be lean, and the NMI fires too late). Like tepples' method, but more flexible. It would be even better if there were a way to freely move the NMI trigger point itself...

I suppose I'm not doing too badly as it stands, though. It seems to me that I could even get away with just using one HDMA channel instead of two, by simply writing a branch into the IRQ code before the last scanline and letting the resulting pseudo-NMI handle the screen blanking. If the IRQ code ends up having to be in ROM for some reason, I could just have it check a memory location, and have the HDMA write to that location - but that's, what, at least two extra instructions every scanline? Still faster than checking OPVCT...

Since I have almost no experience at SNES coding, I was trying to find out if there's a standard procedure or something that people follow in this situation. If there isn't, that's okay; I'm sure there's a way to make it work.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BGMODE or parameter changes during scanline

Post by Near »

Given the extremeness of raster effects, I would recommend writing a very specialized, static loop for the active display area. No IRQs, no checking counters. Each line consumes exactly 1324 cycles. Then run your NMI routine (doesn't even have to be a real NMI since you know you're in Vblank now) to do your game logic, then sync up to V=0,H=0 and start the next frame.

That will require some learning on your part in how to calculate exact cycle times and penalties. But set an IRQ for V=261,H=~330 or so and then use WAI. Have that bail out so that you're now within 6 clocks of V=0,H=0. You can actually sync perfectly to V=0,H=0 but it's complicated, so you'll have to learn that on your own.
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: BGMODE or parameter changes during scanline

Post by 93143 »

How narrow do you think I can get the garbage area? Or should we wait for better video?

I don't know if running the game logic in VBlank is a good idea in this case. Even with a 144x192 playfield, after accounting for all the stuff that needs to happen via DMA, plus related maneuvering, I figure I'd be lucky to have 20 scanlines of actual compute time left before the mode change loop had to restart. Anything that didn't fit would have to be offloaded onto the GSU, which is already pretty busy.

On the other hand, if I understand correctly, running non-timed game code during active display could produce a variance in the position of the mode switch of up to W*(N-1) pixels, where W is the number of pixels per cycle and N is the number of cycles taken by the longest instruction that could conceivably be executing when the interrupt fires. If this is the case, it seems to me that minimizing the width of the sprite mask would require this section of the code to be written exclusively with instructions of four cycles or less, which could be very restrictive... or I could use FastROM in the CPU-only area, which should allow at least five cycles per instruction, maybe six... unless the interrupt timing itself has jitter, as implied by the use of "~" in the timing docs, which would have to be added to the variance...

A cycle-timed game engine (or part of it) could be the best of both worlds.

...or I could give up and run most of the game on the GSU, and hope it can handle it...
byuu wrote:Given the extremeness of raster effects
I'm not sure I get this. To me, using that much mission-critical cycle-timed code in the middle of an active game environment seems more extreme than changing a register in an IRQ, especially if the timed loop eats most of the available CPU power without doing any actual computing...

I mean, the IRQ works; it's just a question of how much extra glitch masking it forces me to do. Am I missing something?
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: BGMODE or parameter changes during scanline

Post by 93143 »

...okay, so it looks like Sik called it. Apparently you can change from Mode 7, but not to Mode 7, at least if the line doesn't start in Mode 7. Unless there's a bug in my code that doesn't trigger in higan...

Also, something funny is going on with the timing; it doesn't look quite the same as in higan v094. It looks like there's more jitter on the real system, and the garbage starts sooner.

But it looks like the scroll changes work more or less as expected, except that they seem to be widening the garbage area... Maybe zeroing the scroll, rather than bumping it positive, would have a different effect...

It strikes me that a lot of cases may have to be tested for confidence in describing the behaviour. Then again, I haven't spent a decade writing an obsessively accurate emulator for this system, so maybe it's more clear what's going on to someone who has...

...

...call me paranoid, but can you confirm that you're using an original SNES, and not a SNES Jr.?
Post Reply