Author |
Message |
- Joined: 23 Aug 2009
- Posts: 213
- Location: Seattle, WA
|
[FIXED] SMS-only VDP issue (works on MD/Genesis)
Posted: Thu Nov 14, 2019 6:13 pm Last edited by SavagePencil on Thu Nov 14, 2019 7:53 pm; edited 2 times in total
|
I'm trying to figure out why something I've written works on a Genesis but doesn't on an actual SMS1. I can reproduce the issue in Emulicious by toggling the "Emulate VDP Constraints" option, but I don't know exactly which constraint I'm violating.
It appears to be an issue with VRAM. I'm either writing to it too fast or I have a register set incorrectly, causing the nametable to behave improperly. Graphics are shifted improperly.
When writing to VRAM, I believe I am in the following state:
* di
* Frame Interrupt is set to OFF on Register $01
* Display is set to OFF on Register $01
I *believe* I have Register $03 set correctly to $FF, but I'm not sure how to see the VDP regs in Emulicious.
Sometimes things stay in the nametable after they are supposed to be cleared. For example, sometimes a character from the title screen will linger when going to the round intro screen, even though I've called the ClearNameTable routine.
ClearNameTable:
ld hl, VDP_NAMETABLE_START_LOC
SET_VRAM_WRITE_LOC_FROM_HL
; Now clear all of VRAM for the nametable.
; Each write to the data port increments the address.
xor a
ld bc, VDP_NAMETABLE_SIZE >> 8
-:
out (VDP_DATA_PORT), a
djnz -
dec c
jr nz, -
ret
I have confirmed that the bad state repros when run on a real SMS and that it looks fine on an actual Genesis.
I'll attach the "with limitations on" and "with limitations off" images. Ignore the "A" character, that's a sprite :)
spies.png (960 B)
Looks incorrect. Limitations ON.
|
|
|
- Joined: 28 Feb 2016
- Posts: 503
- Location: Barcelona
|
Posted: Thu Nov 14, 2019 6:26 pm
|
This is clear a VDP limit error
Try something like:
-:
nop
nop
out (VDP_DATA_PORT), a
nop
nop
djnz -
Until process is corrected.
|
|
|
- Joined: 23 Aug 2009
- Posts: 213
- Location: Seattle, WA
|
Posted: Thu Nov 14, 2019 7:14 pm
|
...but is that necessary when Active Display is off?
I think I've found the problem: I'm not actually in Active Display off.
and ~(VDP_REGISTER1_ENABLE_DISPLAY | VDP_REGISTER1_ENABLE_VBLANK)
Does not "NOT" those OR'd values, as I would expect. It just...lets them be, I guess, because the assembler turns that into:
and $60
...when I would expect it to be:
and $9F
I think I can get the correct thing emitted by making it:
and $FF ~(VDP_REGISTER1_ENABLE_DISPLAY | VDP_REGISTER1_ENABLE_VBLANK)
...but will have to try that when I get home. I'm still interested if Emulicious can show me the state of the VDP registers.
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14745
- Location: London
|
Posted: Thu Nov 14, 2019 7:55 pm
|
It works on a Mega Drive because it has a FIFO buffer on the VDP to help in this situation.
Depending on your assembler, ~ might mean “not” or “XOR” - I guess here it treated it as 0 XOR $9f = $9f, adding the $ff on the left got the result you wanted. I guess this is WLA DX - so maybe raise an issue that it ought to have rejected a unary ~ operator.
|
|
|
- Joined: 23 Aug 2009
- Posts: 213
- Location: Seattle, WA
|
Posted: Thu Nov 14, 2019 9:21 pm
|
That all makes sense. I'll file a bug on WLA-DX. Really, I'd prefer if they allowed a unary ~ instead of XOR.
(fun fact: the problem did NOT appear on MEKA)
Follow-up Qs:
1. Is there a way to see the VDP regs from within Emulicious?
2. Are there any timing constraints necessary when active display is off? Or is a tight loop like above going to work reliably without adding any NOPs?
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14745
- Location: London
|
Posted: Thu Nov 14, 2019 10:48 pm Last edited by Maxim on Fri Nov 15, 2019 9:32 am; edited 1 time in total
|
When the display is off the Z80 cannot access the VDP fast enough to cause problems.
Meka does not emulate timing constraints. I’m pretty sure no game depends on them.
|
|
|
- Joined: 05 Sep 2013
- Posts: 3827
- Location: Stockholm, Sweden
|
Posted: Fri Nov 15, 2019 8:49 am
|
SavagePencil wrote Are there any timing constraints necessary when active display is off? Or is a tight loop like above going to work reliably without adding any NOPs?
you can write to VRAM as fast as you can when display is off (or during vblank)
|
|
|
- Joined: 05 Dec 2019
- Posts: 56
- Location: USA
|
Posted: Sun Dec 22, 2019 11:51 pm
|
I've seen conflicting info about the VDP's rate limit outside vertical or forced blanking: one write every 26, 29, or 32 Z80 cycles. Is there an authoritative document about the VDP's cycle-by-cycle VRAM access pattern the way there is about the NES PPU? (See "PPU rendering" on NESdev Wiki)
There's "Genesis Mode 4 VRAM Timing" on this forum implying that the VDP never uses more than 15 slots in a row, which would mean at least one "external slot" every 16 slots or 32 pixels. It's for Genesis mode 4, but a reply implies that SMS2 mode 4 has the same timing. That sort of implies 22 Z80 cycles as the minimum spacing.
|
|
|
- Joined: 05 Sep 2013
- Posts: 3827
- Location: Stockholm, Sweden
|
Posted: Mon Dec 23, 2019 10:19 am
|
Official documents, AFAIK, state that the required cycles are 29.
Extensive testing shows that everything still works as long as the minimum cycles are at least 26.
Genesis has a FIFO, SMS has no such thing.
|
|
|