Page 1 of 2

VDP access from Z80 questions

Posted: Sun Aug 21, 2016 12:57 pm
by Miquel
I'm developing a MD game, at the start I tried to give all the jobs to the 68000, meaning: playfield, sound, graphics and HINT response, so, perhaps I didn't need to program the Z80. I use HINT to change scroll to perform a perspective, very much like Axelay does. Later I discovered that HINT exception, for every line, takes a lot of cpu time from 68000, I don't know exactly but something similar to 50% of cpu time, so I decided to remove HINT from 68000, mostly because collision detection also take a lot of cpu when I try to have 20-30 entities (objects or actors, what ever you call them) at once on screen.

First you should know that the 68000 code, once removed the HINT, only access the VDP in the vertical exception (VINT), but I don't know how much it lasts. At the most it moves throw DMA all the sprite array, all the horizontal scroll array and possibly a single tile. When I need to make big changes to the VDP I turn it off, always at a VINT, and do the job.

By turning off display, I mean 3rth bit off vdp register 1.

So, continuing, now I'm trying to move the HINT code from the 68000 to the Z80. I started with something simple, just a colour change per line, but it blocks the game complitly, screen in black and some of the DMA done other not.

This Z80 code is (I don't care what exactly does, I was just expecting to do something, then I do it right):

Code: Select all

typedef char s8;
typedef short s16;
typedef long s32;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned int uint;
typedef int bool;

#define g_vpdDataPort		(*((volatile u16*)0x8000))
#define g_vpdCtrlPort32		(*((volatile u32*)0x8004))
#define g_vpdHCounterPort	(*((volatile  u8*)0x8008))

void main()
{
	u16 color = 0xFF00;
	u8 lastLine = g_vpdHCounterPort;
	for(;;)
	{
		u8 currLine = g_vpdHCounterPort;
		if( (currLine < 100) && (currLine > 80) && (currLine != lastLine) )
		{
			g_vpdCtrlPort32 = 0xC0000000;
			g_vpdDataPort = color++;
			lastLine = currLine;
		}
	}
}
If don't write to the vdp (from Z80) everything goes as expected.

Questions:
¿When I turn off display hcounter is still on rolling?
¿ Why it goes that catastrophically wrong?
¿ Is there any way to know from Z80 perspective to know when display is off?
¿Is there any procedure to access VPD 68000 and Z80 both syncronized ?

Re: VDP access from Z80 questions

Posted: Sun Aug 21, 2016 3:08 pm
by TmEE co.(TM)
Z80 cannot do 16bit accesses to the VDP, the 8bit accesses done by Z80 (or 68K) to VDP are always seen as 16bit accesses (both halves of the 16bit write will be duplicated). You can get more info from the docs by Charles MacDonald.

Re: VDP access from Z80 questions

Posted: Mon Aug 22, 2016 5:34 pm
by Miquel
TmEE co.(TM) wrote:Z80 cannot do 16bit accesses to the VDP, the 8bit accesses done by Z80 (or 68K) to VDP are always seen as 16bit accesses (both halves of the 16bit write will be duplicated). You can get more info from the docs by Charles MacDonald.
From Charles documentation:
Z80 access to the VDP has the same results as doing byte-wide reads
and writes as described in section 1.2. So only the HV counter and
PSG can be used effectively.
Ok, so no way is going to work. If someone know how to perform a miracle now is the time :cry: . So no "Axelay perspective" for regular levels, for final stages perhaps where there are fewer actors.

Re: VDP access from Z80 questions

Posted: Mon Aug 22, 2016 9:14 pm
by Stef
You can do axelay scrolling using hint, just use a very fast hint callback. You can prepare all the table and setup VDP control port during vint so you just need to write a single (or 2 for 2 plans) 16 bit value to VDP data port during hint... I think you can spent 25% or less CPU time for it.

Re: VDP access from Z80 questions

Posted: Mon Aug 22, 2016 9:48 pm
by Miquel
Stef wrote:You can do axelay scrolling using hint, just use a very fast hint callback. You can prepare all the table and setup VDP control port during vint so you just need to write a single (or 2 for 2 plans) 16 bit value to VDP data port during hint... I think you can spent 25% or less CPU time for it.
Right now, the thing goes like that: in the exception table the hint entry points to a ram region, in that position I have an array of instruction that does the job as quickly as possible, then there are more instructions that modify the literals for previous instructions taken the data from an array like you said, then the exception returns. I can't think of a faster way.

Even so, doing it for every line takes a lot from 68000, I can't quantify it exactly, but without falling in slowdowns, I can show half of entities/actors/objs when hint is activated.

Re: VDP access from Z80 questions

Posted: Tue Aug 23, 2016 7:52 am
by Stef
I guess you're not using sgdk (which add overload for hint handler).
You said your hint is already as fast as possible, do that mean the instructions sequence is similar to:
move.w (a6+),(a4)
rti

It would be a bit more for 2 plans (1 extra 32bit write to prepare vsram write address and replace the 16bit data write by a 32bit one).

You can save a lot time having fixed address registers for that. Still something you can considered is to use hint only on even or odd line. The distortion granularity is only each 2 lines but I think it doesn't hurt to much. Or you start it on each line as top of screen is generally more stretched then you change it to happen each other line, then each third and so on... can spare a lot of the CPU time :-)

Re: VDP access from Z80 questions

Posted: Tue Aug 23, 2016 2:02 pm
by Miquel
Stef wrote:I guess you're not using sgdk (which add overload for hint handler).
No, I'm not using SGDK, aldo at the beginning, when I didn't know very much about MD internals I follow up it very close.
Stef wrote: You said your hint is already as fast as possible, do that mean the instructions sequence is similar to:
move.w (a6+),(a4)
rti
You can save a lot time having fixed address registers for that.
Well, I said as fast as I can think of. Anyway, you should by fast only because you shouldn't miss the VDP beginning to write next line, after that it's not really important how quick is. Since you have to load from hcounter and from an array you have to use registers, I don't think there is any way around it; but the trick is that this is done it AFTER the VDP is serviced.

For both scrolls, it goes like that:
- push d0 and a0
- load vpd address to a0
- write to (a0) and (-a0) two literal values (#value, like "move.l #0x40000010,(%a0)")
(vpd done!)
- then, overwrite the 2 previous literal values, with the corresponding to the next line
- rte

I don't know if is speedy enough for color changes, but for scroll surely is. I give you the code without injecting the data if you want.
Stef wrote: It would be a bit more for 2 plans (1 extra 32bit write to prepare vsram write address and replace the 16bit data write by a 32bit one).
Yes already done, but you just need the second write as I remember it. And be sure that auto increment is 2.
Stef wrote: Still something you can considered is to use hint only on even or odd line. The distortion granularity is only each 2 lines but I think it doesn't hurt to much. Or you start it on each line as top of screen is generally more stretched then you change it to happen each other line, then each third and so on... can spare a lot of the CPU time :-)
For sure, I should try this next. At the beginning I simply tried a general approach for every line.

Re: VDP access from Z80 questions

Posted: Sun Aug 28, 2016 5:23 pm
by Natsumi
Whenever I do anything on h-int each line, I load the code in RAM, then do this:

Code: Select all

move.l #vdpcommand,$C00004
HintAddr = *+2
move.w addr.w,$C00000
addq.w #2,HintAddr.w
rte
This is a very quick way to issue VDP commands and write to VRAM, CRAM, and VSRAM. As a bonus it uses no registers and uses only 24 bytes of RAM. And its really fast.

Re: VDP access from Z80 questions

Posted: Mon Aug 29, 2016 3:33 pm
by Miquel
Natsumi wrote:This is a very quick way to issue VDP commands and write to VRAM, CRAM, and VSRAM. As a bonus it uses no registers and uses only 24 bytes of RAM. And its really fast.
I will take a note on this, and see how it works. But if I remember it correctly, I wrote it some time ago, one of the problems is you never know at which line (horizontal line) are you at that moment: when you enable display it can be at any line. And, waiting for VINT to enable HINT exception produces one frame of discordance that is clearly visible.

EDIT: No, I'm wrong: you can always wait until hcounter reaches some value to enable display. You don't need hcounter after all. And your solution seems very neat, I will check it.

EDIT2: The problem is you should wait for that line to come for all VINT exceptions. If you are at the end of your development and the timing for the exception is fixed, is always the same, it could be worth it. My problem is I have a some king of queue of things to do at VINT, so time is not constant and I don't have time to spare. Using hcounter is not the fastest, but works on all occasions.

Re: VDP access from Z80 questions

Posted: Tue Aug 30, 2016 6:11 am
by Natsumi
Ive never had timing issues on v-int. Even with a lot of DMA's happening durint it, h-ints start at line 0. You should invest in fast and clean code durint v-int either way, or it could take a lot of unnecessary CPU time

Re: VDP access from Z80 questions

Posted: Tue Aug 30, 2016 3:05 pm
by Miquel
Natsumi wrote:Ive never had timing issues on v-int. Even with a lot of DMA's happening durint it, h-ints start at line 0. You should invest in fast and clean code durint v-int either way, or it could take a lot of unnecessary CPU time
As far as I know you should deactivate exceptions in vblank because if you interrupt DMA, DMA data could be corrupted. Also if I remember correctly VINT has precedence on HINT. So, you can't have all HINT exceptions happening, if you do some work on VINT exception.

Re: VDP access from Z80 questions

Posted: Tue Aug 30, 2016 3:40 pm
by TmEE co.(TM)
When DMA is in progress the CPU is halted, no ints will happen or anything else. And there's only one case where VBL and HBL ints can happen at the same time which is the very last active display line.

Re: VDP access from Z80 questions

Posted: Tue Aug 30, 2016 4:51 pm
by Miquel
TmEE co.(TM) wrote:When DMA is in progress the CPU is halted, no ints will happen or anything else.
¿ Do you mean inside VINT exception ? For sure a fill operation can be interrupted, and maybe when your are displaying, VPD goes more slow so perhaps memory access is interleaved, just speculating, I really don't know.
TmEE co.(TM) wrote:And there's only one case where VBL and HBL ints can happen at the same time which is the very last active display line.
¿ Are you sure ? For example, if you disable VINT, ¿ you only get 224 HINTs in NTSC ?

Well, also can happen that VINT is that large that overlaps with HINTs.

Re: VDP access from Z80 questions

Posted: Wed Aug 31, 2016 5:38 am
by TmEE co.(TM)
During fills the CPU runs yeah, but not during other DMAs. 68K will be halted and so will be Z80 if it tries to access 68K side during a DMA.

See page 15 here : http://www.tmeeco.eu/SMD/Genesis%20Soft ... -09%5D.pdf

Re: VDP access from Z80 questions

Posted: Wed Aug 31, 2016 2:28 pm
by Miquel
I'm baffled, when I was going to give up and say there can be only up to 224 HBlank exceptions (in NTSC), because my program seems to work this way, you show me a document with a 225th H exception. I really don't know what to say.
Then it could be a 226th exception and so on...?
H exceptions stop to occur when there is a V exception (until next frame)?
Is there any place where I can read about this?