Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Discussion of development of software for any "obsolete" computer or video game system. See the WSdev wiki and ObscureDev wiki for more information on certain platforms.
Post Reply
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by sdm »

I started writing something on Sega Genesis (ASM68K), I have questions related to sending the SAT buffer from WRAM to SAT VRAM - I set the buffer size to 512 bytes (256 words) which is the range for 64 sprites.
I send the buffer without using DMA, in the CPU loop in every frame.
The ROM running on the console works, also on emulators - so even without DMA, sending the buffer to VRAM outside the VBLANK is done without problems - the only question is whether you can do that, are there any restrictions? I tried to send using DMA, but I am doing something wrong and here I would like to advise you on how to do it correctly.

SATBuff Send Code to SAT VRAM Directly, No DMA: (simple_platformer_genesis_DIRECT_SAT.bin)

Code: Select all


0x00FF0000-00FF01FF - SATBuff

;------------------------------

Forever:

	BSR	WaitVSync					; synchronize speed
	BSR	UpdateSAT

; game mechanics

	BRA	Forever

;------------------------------

WaitVSync:

	MOVE.L	(VarVSync),D0					; Read value from VarVSync into D0

WaitVSync_:

	MOVE.L	(VarVSync),D1					; Read value from VarVSync into D1
	CMP.L	D0,D1						; Compare D0 and D1
	BEQ	WaitVsync_					; If result is 0 the value has not been changed
								; so jump back to 1
	RTS

;------------------------------

INT_VInterrupt:							; Vertical interrupt - run once per frame (50hz in PAL, 60hz in NTSC)

	ADD.L	#1,(VarVSync)

	RTE

;------------------------------

UpdateSAT:							; ### Runs on real hardware too, sends SATBuff directly to SAT VRAM ###

	SetVRAMWrite 0xF000					; copy 128 long-words to SAT (512 bytes = 64 sprites)
	LEA	0x00FF0000,A0
	MOVE.W	#128-1,D0

UpdateSAT_Loop:

	MOVE.L	(A0)+,$00C00000					; vdp_data
	DBF	D0,UpdateSAT_Loop				; DBF/DBRA
	RTS

DMA version code, working bad: (simple_platformer_genesis_DMA_SAT.bin)

Code: Select all


;------------------------------

UpdateSAT_:							; ### It works incorrectly, not on every emu and probably it will not work on hardware ###

;	MOVE.W	#$8174,($C00004)				; VDP Register #1, Enable DMA
	MOVE.W	#$0100,D0					; Word's to Send
	MOVE.L	#$70000003,D2					; VRAM destination address
	LEA	$00FF0000,A0					; source address
	JSR	DoDMAtoVRAM
;	MOVE.W	#$8164,($C00004)				; VDP Register #1, Disable DMA

	RTS

;------------------------------

DoDMAtoVRAM:

	MOVE.L	#$C00004,A1					; D0 = WORD's to transfer
	MOVE.L	#$94009300,D1					; D2 = VRAM address
	OR.B	D0,D1						; A0 = Source address
	LSR.W	#8,D0
	SWAP	D0
	CLR.W	D0
	OR.L	D0,D1
	MOVE.L	D1,(A1)
	MOVE.L	A0,D0
	LSR.L	#1,D0
	MOVE.L	#$97009500,D1
	OR.B	D0,D1
	LSR.W	#8,D0
	OR.W	#$9600,D0
	MOVE.W	D0,(A1)						; MID
	SWAP	D0
	SWAP	D1
	AND.B	#$3F,D0
	OR.B	D0,D1
	MOVE.L	D1,(A1)						; LOW, HIGH
	OR.B	#$80,D2
	MOVE.L	D2,(A1)

	RTS

Attachments
simple_platformer_genesis_DIRECT_SAT.bin
(18.46 KiB) Downloaded 65 times
simple_platformer_genesis_DMA_SAT.bin
(18.55 KiB) Downloaded 66 times
Last edited by sdm on Thu Mar 17, 2022 2:16 am, edited 1 time in total.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by calima »

Yes, you can rewrite the sprites during active display. Some game uses it to reuse the same snowflake sprite several times over the screen. But I don't remember the limits, probably it corrupts the sprites on the current line if you do it outside hblank? Search spritesmind.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by sdm »

Earlier, I also wrote something on the Sega Master System, I used a similar solution there, i.e. OAMBuff I sent in the CPU Loop to VRAM and at the beginning I had a problem that the sequential write of the buffer to vram was too fast than the data bus allows - I had to slow down the loop between writing bytes. I do not know what limitations GENESIS has - can you safely copy the buffer as I do above? Of course it works, but I'm just getting started and probably many things are still unclear.

However, since there are DMA channels, I would like to use it, but as you can see there are problems and I don't know how.

Unfortunately, I still have an inactive account on Spritespind - I registered a long time ago, but the admin has not accepted my registration until today :( (exactly the same on the sega-16.com forum ...)
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by Oziphantom »

the MD like the SMS can't access VRAM at full speed during display, so you need to slow it down during active display. Which DMA won't do, unless they added a special slow mode for active display speeds.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by 93143 »

Oziphantom wrote: Thu Mar 17, 2022 3:02 am the MD like the SMS can't access VRAM at full speed during display, so you need to slow it down during active display. Which DMA won't do, unless they added a special slow mode for active display speeds.
Apparently they did, kinda. My understanding is that you can DMA to VRAM during active display, and if the FIFO is full the DMA unit will wait until it's ready to accept the byte (stalling the CPU bus the whole time). The result is roughly 1/10 speed DMA.
User avatar
TmEE
Posts: 960
Joined: Wed Feb 13, 2008 9:10 am
Location: Norway (50 and 60Hz compatible :P)
Contact:

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by TmEE »

It is impossible to get corruption on MD, there's a 4 level FIFO to soften the blow and when it is full the CPU is stalled (and DMA too) until there's a new spot avalable. You have 18 writes possible on an active line and just over 200 during blanking. The access slots on active part you can see easily by doing a DMA to the palette, you'll see "CRAM dots" in places where the access slot is on the screen. They come in groups of 3, 16 pixels apart (4th one is used up by VRAM refresh).

Only complication is that VDP keeps an internal cache to ease its rendering process, and it is updated only when relevant location in VRAM is written into (by CPU or DMA). It is possible to create conditions where sprite rendering is disrupted by updating sprite list in a way that causes a mismatch with what sprite evaluation has determined. VDP fetches attributes and X position from VRAM after visibility evaluation and it is possible to change the data before (or after) it got fetched by VDP and create something possibly undesirable.

Excerpt of a document I am slowly writing :

Code: Select all

Sprite rendering process begins one line (including blanking period that
precedes it) before active display with what was referred to as sprite
preparation line earlier. VDP uses one 320 pixel wide Line Buffer to render
the sprites and stores 7 bits per pixel - priority bit, 2 palette bits and 4
color index bits.

Rendering process happens in 4 steps. Steps 1 and 2 happen concurrently,
starting 16 pixels before right border (start of sprite graphics fetches) and
lasting almost until end of blanking period (until start of BG rendering
process) and concurrent steps 3 and 4 starting 10 pixels before left border
(first sprite attribute fetches) and lasting until 20 pixels before right
border (end of BG rendering period).

The memory used to store info for rendering is 680 bits in size and consists
of 34 bits per 20 sprites. Per entry 7 bits are for of Link values of visible
sprites, 16 bits for attributes, 9 bits for horizontal position and 2 bits
for width.


Step 1
   Scan through the Cache and store up to 20 indexes of sprites that are
   visible using their vertical position and size to determine visibility and
   Link value to determine the order. Storing can happen only when Step 2 has
   made use of the data in the index slot first.
   Scanning is stopped when 80 scan operations are done, 20 indexes are found
   or Link value of 0 is encountered. Sprite Overflow flag should be set when
   21st index is found during this step.
   Number of found visible sprites seems to be stored also because unfilled
   index slots retain their previous values and later render steps always
   do full 20 fetches from VRAM according to those values, but don't actually
   use the data.
Step 2
   Use previously stored 20 attribute values to fetch a slice of graphics 
   from VRAM and store it in Line Buffer according to previously stored
   horizontal positions. Since graphics fetches are in order of discovery
   from Link list, a pixel is stored in Line Buffer only if the particular
   spot hasn't been written to before, otherwise observed priority of sprites
   isn't retained and it also allows easy Sprite Overlap detection. Sprite
   Overlap bit should be set during this step.
Step 3
   Use previously stored 20 index values to fetch horizontal position and
   attributes from VRAM and store them for rendering.
Step 4
   Display the rendered Line Buffer while clearing it out so it can be
   rendered into again (only non zero pixels are rendered into).
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by calima »

I would call the CRAM dots corruption, though.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by 93143 »

I think he means data corruption.

On MD, writes to CRAM during active display work as intended in the sense of properly updating the target palette entry, even though they cause momentary visible glitches.

On SNES, writes to CGRAM during active display do not cause video glitches, but the data goes wherever the PPU happens to be looking at the moment, which typically causes palette corruption.
User avatar
TmEE
Posts: 960
Joined: Wed Feb 13, 2008 9:10 am
Location: Norway (50 and 60Hz compatible :P)
Contact:

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by TmEE »

Yeah, data you write alawys goes where it needs to and nothing ever gets lost. CRAM dots happen only because the memory is single port and when data is read or written, content of databus ends up on pixel output as the video output process cannot be delayed in any way. The "CRAM bitmap" works by exploiting this, long DMA into single CRAM location showing the BG color gets all the data being written also shown on screen at the same time.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by sdm »

So if my SATBuf to SAT sending code without DMA in the CPU Loop works and nothing is "lost", can you use this solution? DMA would only speed it up for me? I don't plan to write to VRAM in CPU Loop anymore (only update small BGR graphics as "ITEMS").
User avatar
TmEE
Posts: 960
Joined: Wed Feb 13, 2008 9:10 am
Location: Norway (50 and 60Hz compatible :P)
Contact:

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by TmEE »

CPU or DMA are functionally same to the VDP, just that DMA hits every access slot available while CPU will miss most of them in passive scan and can hit all of them in active scan due to scarcity of access slots during active scan. If you can use DMA you should, it is much faster (except for tiny transfers of handfuls of bytes, where setup cost of DMA may be bigger than just doing MOVE.Ls to VDP dataport)

Code: Select all

This table shows all the available VRAM DMA bandwidth in one frame :
+---------+-------------------------------+-------------------------------+
|         |              50Hz             |              60Hz             |
|         +---------------+---------------+---------------+---------------+
|         |     V224      |     V240      |     V224      |     V240      |
|         +-------+-------+-------+-------+-------+-------+-------+-------+
|         |  H256 |  H320 |  H256 |  H320 |  H256 |  H320 |  H256 |  H320 |
+---------+-------+-------+-------+-------+-------+-------+-------+-------+
| Active  |  3600 |  4050 |  3856 |  4338 |  3600 |  4050 |  3856 |  4338 |
| Passive | 14696 | 18040 | 12024 | 14760 |  6179 |  7585 |     0 |     0 |
| A + P   | 18296 | 22090 | 15880 | 19098 |  9779 | 11635 |  3856 |  4338 |
| Blanked | 52271 | 64165 | 52271 | 64165 | 43754 | 53710 | 40080 | 49200 |
+---------+-------+-------+-------+-------+-------+-------+-------+-------+
Number of tiles that can be transferred per frame :
+---------+---------------------------+---------------------------+
|         |            50Hz           |            60Hz           |
|         +-------------+-------------+-------------+-------------+
|         |    V224     |    V240     |    V224     |    V240     |
|         +------+------+------+------+------+------+------+------+
|         | H256 | H320 | H256 | H320 | H256 | H320 | H256 | H320 |
+---------+------+------+------+------+------+------+------+------+
| Active  |  112 |  126 |  120 |  135 |  112 |  126 |  120 |  135 |
| Passive |  459 |  563 |  375 |  461 |  193 |  237 |    0 |    0 |
| A + P   |  571 |  690 |  496 |  596 |  305 |  363 |  120 |  135 |
| Blanked | 1633 | 2005 | 1633 | 2005 | 1367 | 1678 | 1252 | 1537 |
+---------+------+------+------+------+------+------+------+------+
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Sega Genesis - Sending SAT buffer to SAT VRAM using DMA

Post by sdm »

Thanks. There are enough bytes to send SATBuff + some minor updates to the BACKGROUND elements.
Post Reply