Jump to content
IGNORED

wait <n> seconds in ASM


Recommended Posts

Hi *,

 

what's a decent way to program a "wait <n> seconds" routine in assembler?

I guess it would be to count frames (like in the pattern 1/50 per frame. ($12,$13,$14) which the OS is doing during VBI)

 

But let's say I have a PAL system or a NTSC system. How would I really know what e.g. "1 second" is?

    lda #0
    sta $14	
r1
    lda $14
    cmp #60
    bne r1

Link to comment
Share on other sites

what's a decent way to program a "wait <n> seconds" routine in assembler?

I guess it would be to count frames (like in the pattern 1/50 per frame. ($12,$13,$14) which the OS is doing during VBI)

 

Unless you have your own VBI or DLI, using RTCLOK registers is fine.

 

But let's say I have a PAL system or a NTSC system. How would I really know what e.g. "1 second" is?

 

Use PAL ($D014) register:

    ldx #60
    lda $D014
    and #$E
    bne r0
    ldx #50
r0
    lda #0
    sta $14	
r1
    cpx $14
    bne r1

(disclaimer: untested)

 

Link to comment
Share on other sites

Some thoughts:

 

If you're writing something outside the OS, then watching how high VCOUNT goes will tell you whether you have a 50 or 60 Hz system, and will still have it work correctly on mixed Antic/GTIA systems (like 50Hz NTSC). Then you just have to count VBIs.

  • Like 1
Link to comment
Share on other sites

When using the RTCLOCK (18,19,20), overwriting it for starters with an arbitrary value (like 0) is not a good practice. It is not your private variable, it is a system-wide resource. So, to count a second in the jiffy ticks it is better to fetch the counter value, add 50 for PAL or 60 for NTSC, then wait for the resulting value.

  • Like 5
Link to comment
Share on other sites

Note machines running "other system's" Antic won't reflect what's intalled by reading the GTIA PAL register, and that regardless of system the frame count is a litle bit under 50/60.

 

Using PAL is better than relying on the Ram based variable, esp since only the OS in XL onwards maintains it.

 

Generating a value of 50 or 60 using the PAL register contents is easy:

 

 

 lda pal
 and #$a
 clc
 adc #50

 

Once done it can be added to current RTCLOK contents to form a compare target value.

Link to comment
Share on other sites

When using the RTCLOCK (18,19,20), overwriting it for starters with an arbitrary value (like 0) is not a good practice. It is not your private variable, it is a system-wide resource

 

???
Available documentation says that you can use - also change - the contents of those location.
"Users can POKE these clock registers with suitable values for their own use. The realtime clock is always updated during the VBLANK interval."
"Diese Uhr wird vom Betriebssystem nicht benutzt und wird auch während zeitkritischer I/0-Operationen weiter erhöht, sie kann vom Benutzer ohne Einschränkungen verwendet werden."
e.t.c.
  • Like 2
Link to comment
Share on other sites

Just because you can does not necessarily mean you should. Imagine a driver which implements a real-time clock using the OS RTC. Reset the OS RTC and you mess up the system time. It's the same rationale as ensuring the OS interrupts are not disabled for prolonged periods of time.

 

Personally I don't rely on the OS RTC or PAL register at all where possible, just in case we're running in some kind of unusual environment. You can test the maximum value of VCOUNT easily enough in the space of a couple of frames in order to establish PAL/NTSC, the watch VCOUNT again to wait for specific numbers of frames.

  • Like 1
Link to comment
Share on other sites

Perhaps the driver that implements the real time clock based on RTCLOCK works on the basis of erroneous assumptions - precisely because there is information in the literature that the user can change these locations.

  • Like 1
Link to comment
Share on other sites

Perhaps the driver that implements the real time clock based on RTCLOCK works on the basis of erroneous assumptions - precisely because there is information in the literature that the user can change these locations.

 

Mapping the Atari is a third-party book, not the OS technical manual, but regardless of that, lots happened in thirty odd years and since it's easy to count elapsed time without resetting the OS RTC, there's no reason to do so unless one's motivation is pure belligerence. :)

 

Fight... fight... fight! Man this is geekdom at its best. As I progressed through this thread, I found myself nodding in agreement almost each time a new post came out and thinking "that makes sense." And yes, that applies even though new posts may contradict previous ones I that I had thought were the gold standard until the new one comes down. Anyway, I love it., as it provides for a good learning experience. I guess what I'm trying to say is that this discourse has provided a positive.

  • Like 4
Link to comment
Share on other sites

???

Available documentation says that you can use - also change - the contents of those location.

This is why I wrote that "it is not a good practice", and not that "you cannot". It is also a good practice to understand the point of the discussion before entering it.

Link to comment
Share on other sites

You can test the maximum value of VCOUNT easily enough in the space of a couple of frames in order to establish PAL/NTSC, the watch VCOUNT again to wait for specific numbers of frames.

But how long is the code that does all that initialization and checking ? ~100 Bytes or more ?

 

Don't you ever miss that memory for sume LUT or data ? Of course, for an 8-32 KB demo it's not an issue, but I can imagine it would be easier to just have 2 separate executables for PAL/NTSC for anything bigger than 32 KB, no ?

 

Or is it the convenience of having everything merged in just one build ? Just trying to understand the rationale here, that's all.

Link to comment
Share on other sites

You can test for 50/60 in about 11 bytes (disable VBIs first).

 

http://atariage.com/forums/topic/233365-modifying-ntsc-machines-to-run-pal-software/?p=3144654

loop1
   lda VCOUNT   ;We must start on a non-zero VCOUNT.
   beq loop1
loop2
   tay
   lda VCOUNT   ;Save VCOUNT in Y until it wraps.
   bne loop2
 
;Y now equals the maximum VCOUNT found.
  • Like 4
Link to comment
Share on other sites

But how long is the code that does all that initialization and checking ? ~100 Bytes or more ?

 

Don't you ever miss that memory for sume LUT or data ? Of course, for an 8-32 KB demo it's not an issue, but I can imagine it would be easier to just have 2 separate executables for PAL/NTSC for anything bigger than 32 KB, no ?

 

Or is it the convenience of having everything merged in just one build ? Just trying to understand the rationale here, that's all.

See Bryan's post. And waiting a single frame consumes 11 bytes:

WaitForSync
	lda VCount
	bne WaitForSync
Loop	lda VCount
	beq Loop ; typo corrected - thank you Bryan!
	rts

I tend to go for this approach after writing a driver which - for all I knew - could have been called with the interrupts disabled. Adding n to the LSB of the OS RTC and looping is a little more concise, and that approach is taken in some drivers. It's six and two threes as far as I'm concerned, and when all one wants to do is wait n frames rather than n seconds, no additional calibration setup is required for the VCOUNT method. So yeah: it's cheap to make one binary which works with both PAL and NTSC, just as it's cheap to write code which doesn't stamp on global OS variables.

Edited by flashjazzcat
  • Like 2
Link to comment
Share on other sites

That's way cheaper than I thought :)

 

I guess I got distracted by the idea of waiting several seconds, and then pick the highest value (e.g. sorting), but now I realize you could just add one additional condition and branch and just use X register for 2 outer loops, which is just literally couple bytes more.

 

So, yeah - more than worth the bytes it occupies :)

God, I miss the 6502 ASM. The simplicity and beauty...

  • Like 1
Link to comment
Share on other sites

See Bryan's post. And waiting a single frame consumes 11 bytes:

WaitForSync
	lda VCount
	bne WaitForSync
Loop	lda VCount
	bne Loop
	rts

 

Would this work? Once Vcount is 0, you drop to the 2nd part (Loop) where you read it again and probably get 0 again. I think you'd need a couple WSYNCs in the middle, or loop until a certain line is reached.

  • Like 3
Link to comment
Share on other sites

 

Would this work? Once Vcount is 0, you drop to the 2nd part (Loop) where you read it again and probably get 0 again. I think you'd need a couple WSYNCs in the middle, or loop until a certain line is reached.

 

You're quite right: good spot. This was the original code I transposed, and introduced the typo when removing the MADS macros for clarity:

	.proc WaitForSync
	lda VCount
	rne
	lda VCount
	req
	rts
	.endp

This corresponds to "bne Loop" being replaced by "beq Loop". It does work without any writes to WSYNC (which I dislike in mainline code since they can clobber DLIs) and you can just add an outer indexed loop to count multiple frames.

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...