TMS9918A frame flag on Spectravideo 328

By encore

Supporter (12)

encore's picture

03-04-2023, 11:49

Hi! This year I've started to learn Z80 assembly and do some coding experiments on the Spectravideo 328, so I've been reading up on the TMS9918A, Z80 and so on. I have experience from programming C64 / 6502 for about a decade. Currently I'm developing with WLA-Z80 and testing in the OpenMSX emulator, as well as programming an EEPROM cartridge now and again for testing on my real SV-328.

To set the stage, when I started developing on C64, the first step (the easiest way) to get going to sync code to each video frame was to make a loop that checked the current rasterline on the VIC-chip until a certain rasterline occurred, then execute the code for that video frame and return back to the loop to wait for the next rasterline occurrence.

The next logical step from there was to setup an IRQ that pointed to the frame code and make the VIC-chip generate the interrupt, so that no "check rasterline loop" was necessary.

I'm at the first step on the SV-328. I understand that the TMS9918A sets a frame flag (7th bit) when it reaches the last active line of the video frame, and every time you read the register the frame flag is reset. The code I've used until now has been:

VdpStatus	= $85 (on Spectravideo)

-	in a, (VdpStatus)	; read value from VdpStatus
	cp $7f
	jr c, -		; wait until frame flag is set (carry is set if greater than $7f)

So now to my problem. In OpenMSX (emulating SV-328) this works perfectly. On my real SV-328 however it ...mostly works? It works maybe 90-95% of the time, but now and again it's like it doesn't register the frame flag for that video frame (but still resets it), so it will wait a complete frame until the next flag is set.

My questions are:
- Is this behaviour unique to SV-328 or does it happen on MSX machines too?
- Why does it happen? Is this a timing issue, perhaps I am reading the VdpStatus too often?
- Is this solved completely by setting up an IRQ instead?

Thanks for reading!

Login or register to post comments

By NYYRIKKI

Enlighted (6096)

NYYRIKKI's picture

03-04-2023, 12:10

encore wrote:

- Is this behaviour unique to SV-328 or does it happen on MSX machines too?

No, it happens on MSX too.

Quote:

- Why does it happen? Is this a timing issue, perhaps I am reading the VdpStatus too often?

Yes, it is a timing issue... If you read the flag at exact same time it gets set, you may cause it to reset, but still return old not set value.

Quote:

- Is this solved completely by setting up an IRQ instead?

Yes.

By thegeps

Paragon (1260)

thegeps's picture

03-04-2023, 12:20

On MSX the vdp is connected directly to Z80 int pin. When VDP generates an interrupt the code located at 38h is executed. In that code, the ISR (interrupt service routine), that can be triggered fron other hardware, the bios check if it is generated from the vdp for you. In that case it updates a system variable (jiffy). So, if you aren't using your own isr routine after discarding bios, you don't need to check the vdp status reg (resetting it!). Simply check for jiffy value to change. Or hook yourncode to HTIMi, 5 bytes in RAM where you can set a call to your vbl synched routine.

Example

jiffy:	equ	0fc9eh


	ld	hl,jiffy
	ld	a,(hl)
vblank_loop:
	cp	(hl)
	jr	z,vblank_loop


From here you are in vblank

Else

HTIMI hook
hook	equ	0fd9fh

	ld	hl,your_routine
	ld	a,l
	ld	(hook+1),a
	ld	a,h
	ld	(hook+2),a
	ld	a,0cdh		;opcode for call
	ld	(hook),a

Your code will be executed exactly at vblank

By NYYRIKKI

Enlighted (6096)

NYYRIKKI's picture

03-04-2023, 13:00

In SVI the very first call after interrupt and pushing DE, HL, BC and AF is to #FE79 (H.KEYI). In MSX the hooks are 5-bytes, so CALL can be used (as long as you do RET). This is because usually in MSX interslot calls (RST #30) are used. In SVI hooks have only 3-bytes, so you can use only JP (#C3)
In SVI JIFFY is @ #FE2E. SVI does not really have H.TIMI called dedicated VDP interrupt hook, but as a tip: Disk motor counter hook (H.DMOT, #FF5A) is called right after incrementing JIFFY.

By thegeps

Paragon (1260)

thegeps's picture

03-04-2023, 13:09

Yep, i wrote about MSX, trying to be of some help, but I don't really know SVI. I only know thant it is basically an MSX with different bios, so examples could help

By encore

Supporter (12)

encore's picture

03-04-2023, 21:36

Thanks guys for the answers.

Quote:

Yes, it is a timing issue... If you read the flag at exact same time it gets set, you may cause it to reset, but still return old not set value.

I see. Is this common knowledge? I'm wondering why this isn't emulated on OpenMSX (like too_fast_vram_access is)? Or maybe it is, but for MSX only? Regardless I'm glad to know the answer now, as I have investigated this issue on and off for about a week. Smile

Regarding the IRQ hooks you both mention, I guess this is the case if you write code that is loaded and executed normally via BIOS/Basic? The cartridge ROM image format that I use seems to occupy $0000-$7FFF and the RAM $8000-$FFFF, so I could put whatever I like in the zeropage section at $38?

By NYYRIKKI

Enlighted (6096)

NYYRIKKI's picture

03-04-2023, 23:16

encore wrote:
Quote:

Yes, it is a timing issue... If you read the flag at exact same time it gets set, you may cause it to reset, but still return old not set value.

I see. Is this common knowledge? I'm wondering why this isn't emulated on OpenMSX (like too_fast_vram_access is)? Or maybe it is, but for MSX only?

Well, I think it is relatively well known that it is bad idea to poll the int flag... but I don't think it is well and accurately investigated and that is likely why it is not emulated correctly either. openMSX team usually fixes problems very fast when they have accurate information and peer reviewed test results, but these kinds of things require special software & hardware tools to investigate, so exact information of how these bugs behave in different setups is hard to get. They usually refuse to add "this is most likely how it works" stuff... In this example the question comes down to: Define "exact same time".

Quote:

Regarding the IRQ hooks you both mention, I guess this is the case if you write code that is loaded and executed normally via BIOS/Basic? The cartridge ROM image format that I use seems to occupy $0000-$7FFF and the RAM $8000-$FFFF, so I could put whatever I like in the zeropage section at $38?

Yes... I was maybe a bit carried away filling the gaps of thegeps reply. Smile If you do ROM, your only rule is that your programs two first commands must be DI and LD SP,xxxx If this is true, BIOS starts your program and after that it is all up to you, how you handle your stuff. Even if ROM is visible, you may always switch to IM2 if you want to gain full control. (There is nothing to drive the bus though)

By encore

Supporter (12)

encore's picture

05-04-2023, 19:54

NYYRIKKI wrote:

Well, I think it is relatively well known that it is bad idea to poll the int flag... but I don't think it is well and accurately investigated and that is likely why it is not emulated correctly either.

Ok, understandable. At least it makes it very easy now to write code to distinguish between a real machine and openMSX. Smile

Quote:

They usually refuse to add "this is most likely how it works" stuff... In this example the question comes down to: Define "exact same time".

Yeah I see what you mean.

Quote:

If you do ROM, your only rule is that your programs two first commands must be DI and LD SP,xxxx If this is true, BIOS starts your program and after that it is all up to you, how you handle your stuff.

Good to know! Thanks, I should be able to progress now! And thanks for writing MSX_ROM-load_for_SVI. Cool