C68 & detecting vsync

Anything QL Software or Programming Related.
megatron-uk
ROM Dongle
Posts: 10
Joined: Tue Jan 04, 2022 9:25 am

C68 & detecting vsync

Post by megatron-uk »

Hi folks,

I recently picked up a QL last year and restored it to working state - I was a Spectrum user in my youth, and the QL always seemed rather exotic, so it was nice to be able to finally add one to my collection.

Anyway, at the moment I have an itch to scratch in the form of writing a multi-platform D&D RPG game (well, an engine actually, that runs different games based on the data set it is supplied with). It's a bit of a hybrid of something like the original Bards Tale (text based location descriptions for example - though full screen images may come at some point), crossed with a more modern turn based combat system - the main interface looks like this:
sample.png
I have most of the basic functionality in place - parsing location data, displaying dialogue with npc's, conditional encounters/item/navigation options/enemy spawning (the portal to the north only opens if you posess the crown of righteousness, big boss #2 spawns if you killed all the minions in map location #55... that kind of thing).

For the QL I'm using the latest xtc86 cross compiler version of C68 (https://github.com/stronnag/xtc68) which integrates nicely into the rest of the build toolset that will support the other platforms (Atari, MSX, etc) that I'm targetting. As I'm still in the middle of building a working floppy solution for the physical QL, all testing is done with sQLux on Linux.

However, the game is a bit flat looking; I haven't yet got any animation, loading icons, etc... as I'm finding it difficult to find a method to synchronise / wait on display refresh - the C68 standard library only appears to have a second-granularity sleep() and nothing else that would help.

I see that there is some documentation on https://www.chibiakumas.com/68000/sinclairql.php for reading the state of the vsync interrupt, but I am hampered by the fact that C68 (at least in the xtc68 incarnation) doesn't appear to support inline assembly.

I am trying this at present:

Code: Select all

void vsync_wait(unsigned char wait){
       // Wait a specified number vblank interrupts
	unsigned int v;
	unsigned char c = 0;
	_super();
	while (c < wait){
        	_WAITVBLANK();
        	c++;
	}
	_user();
}
Where _WAITVBLANK() is defined in the following external assembly object, a cut-and-paste from Chibiakumas:

Code: Select all

	.text
	.even
	.extern _WAITVBLANK
_WAITVBLANK:
	move.b	#255,$18021    ;Clear interrupt bits
_WAITVBLANKAGAIN:
	move.b	$18021,d0            ;Read in interrupt state
	tst.b	d0                    ;Wait for an interrupt
	beq		_WAITVBLANKAGAIN
	rts
As I understand it from the Chibiakumas link, after setting address $18021 to 255, it should change to non-zero when the vsync is signalled. However on reading back from that address, I never get anything but 0.

There are some oddities in the C68/Sozobon/JAS assembler; for one it does not like the #% immediate source value format as set as an operand for the move.b instruction in the original example - the % binary value indicator must be removed (and a hex or decimal value substituted) for it to assemble without error.

So a long shot, but has anyone else used C68 to do any graphics/games and had success using the vblank/vsync interrupt to synchronise things?


User avatar
XorA
Site Admin
Posts: 1368
Joined: Thu Jun 02, 2011 11:31 am
Location: Shotts, North Lanarkshire, Scotland, UK

Re: C68 & detecting vsync

Post by XorA »

QL, all testing is done with sQLux on Linux.
As the author of sQLux its possible I broke that register when adding SDL2 support! Could you attach a binary so I can debug?


User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: C68 & detecting vsync

Post by mk79 »

Looks nice.
megatron-uk wrote:However, the game is a bit flat looking; I haven't yet got any animation, loading icons, etc... as I'm finding it difficult to find a method to synchronise / wait on display refresh - the C68 standard library only appears to have a second-granularity sleep() and nothing else that would help.
You can do the same thing as sleep (calling mt_susjb) to get down to 20ms granularity.
I see that there is some documentation on https://www.chibiakumas.com/68000/sinclairql.php for reading the state of the vsync interrupt, but I am hampered by the fact that C68 (at least in the xtc68 incarnation) doesn't appear to support inline assembly.
You will never read anything but 0 as these will always be handled by the appropriate interrupt handlers. For your bit-twiddling solution you would need to disable interrupts and it will never work on advanced emulators like QPC.

The clean thing to do is to link in a polled interrupt service routine and for example increase an integer in it that you can busy-wait on in the main job. This is a bit tricky to do, especially as the routine must be removed when the job is killed, otherwise the system will crash. Explaining the details that must be observed is too time consuming, so I wrote some example code you can try out.
Attachments
poll_demo.zip
(18.03 KiB) Downloaded 61 times


megatron-uk
ROM Dongle
Posts: 10
Joined: Tue Jan 04, 2022 9:25 am

Re: C68 & detecting vsync

Post by megatron-uk »

XorA wrote:
QL, all testing is done with sQLux on Linux.
As the author of sQLux its possible I broke that register when adding SDL2 support! Could you attach a binary so I can debug?
I think I've sorted it - it was as the last reply says; I think QDOS was scheduling stuff and clearing the isr. I have changed the waitvblank routine to disable interrupts for the duration of the while() loop, as so:

Code: Select all

	.text
	.even
	.extern _WAITVBLANK
_WAITVBLANK:
	ori     	#1792,sr			;Disable interrupts
	move.b	#255,$18021    		;Clear interrupt bits
_WAITVBLANKAGAIN:
	move.b	$18021,d0            	;Read in interrupt state
	tst.b		d0                    	;Wait for an interrupt
	beq		_WAITVBLANKAGAIN
	rts
This does appear to work, and I now have a neat little flashing animation for selected menu items now. However, I'm not entirely clear on how to then restore the status register back to 'normal' state when I come out of supervisor mode at the end of the while() loop; my animation plays (a simple alternating black on white, white on black scheme every 3 vblanks for around 30 vblanks in total), but then the game freezes (or more likely - stops responding to input) at (I suspect) the next time I try to read the keyboard.

Before I call _user() to exit supervisor mode, what should I be setting the sr back to?


Silvester
Gold Card
Posts: 436
Joined: Thu Dec 12, 2013 10:14 am
Location: UK

Re: C68 & detecting vsync

Post by Silvester »

mk79 wrote:The clean thing to do is to link in a polled interrupt service routine and for example increase an integer in it that you can busy-wait on in the main job. This is a bit tricky to do, especially as the routine must be removed when the job is killed, otherwise the system will crash..
Exactly what I did with MIDI file player (viewtopic.php?f=2&t=1587&hilit=qsound&start=10#p14069).

You just need to also set up scheduler task to clean up if job removed.

I initially tried suspending a job for required period but it wasn't reliable. Setting job priority at 127 and using a poll task with 'counter to next event' to release suspended job proved the most accurate.


David
megatron-uk
ROM Dongle
Posts: 10
Joined: Tue Jan 04, 2022 9:25 am

Re: C68 & detecting vsync

Post by megatron-uk »

I've definitely lost my keyboard input though as the debug box on the next page cannot be cleared (it responds to any key press), so I'clearly need to set something back again.

https://www.youtube.com/watch?v=DkHqnkMqHHM[/youtube]

Example animation:
https://www.youtube.com/watch?v=DkHqnkMqHHM


User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: C68 & detecting vsync

Post by mk79 »

Silvester wrote:You just need to also set up scheduler task to clean up if job removed.
No, using my method you don't (well, not really mine, I clearly state in the code that I have stolen it from TT ;) ). The job_removed routine is called by the OS in this case and cleans up.
Last edited by mk79 on Sat Feb 12, 2022 8:40 pm, edited 1 time in total.


User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: C68 & detecting vsync

Post by mk79 »

megatron-uk wrote:I've definitely lost my keyboard input though as the debug box on the next page cannot be cleared (it responds to any key press), so I'clearly need to set something back again.
Why not do it right in the first place? I even provided the code :?:


Silvester
Gold Card
Posts: 436
Joined: Thu Dec 12, 2013 10:14 am
Location: UK

Re: C68 & detecting vsync

Post by Silvester »

mk79 wrote:
Silvester wrote:You just need to also set up scheduler task to clean up if job removed.
No, using my method you don't. The job_removed routine is called by the OS in this case and cleans up.
Ah, I was talking from 68k code POV. Like Tebby I find 'C' too unnecessary abstract.


David
User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: C68 & detecting vsync

Post by mk79 »

Silvester wrote:
mk79 wrote:
Silvester wrote:You just need to also set up scheduler task to clean up if job removed.
No, using my method you don't. The job_removed routine is called by the OS in this case and cleans up.
Ah, I was talking from 68k code POV. Like Tebby I find 'C' too unnecessary abstract.
What's it got to do with C? It was just for this thread that I translated the original assembler code (https://www.kilgus.net/soft/qmovie-v2.00-src.zip) into a C function (still written in assembler). I don't think this has ever been done in C before.


Post Reply