A.D.A. Amiga Demoscene Archive

        Welcome guest!




log in with SceneID


Demos Amiga Demoscene Archive Forum / Coding / coding tutorial: timing
 Page:  1  2  3  »» 
Author Message
#1 - Posted: 21 Nov 2004 19:54
Reply Quote
How does one add timing to a demo?

Suppose that i want to show a picture, wait a couple of seconds, then show another picture,...
#2 - Posted: 21 Nov 2004 21:31 - Edited
Reply Quote
with VBL interrupt (more simple), counter incr 50x/sec. or with a Cia timer (more complex), or Software interrupt started by copperlist - vbl syncro - like TEK Rampage demo.

test in mousewait loop :

moveq #0,d0
btst #5,$dff01f ; test bit 5 Intreq register (vbl)
beq.s wait
move.w #$20,$dff01e ; interrupt ok

addq.w #1,d0

cmp.w #2*50,d0 ; 2 sec.
beq.s stop

btst #6,$bfe001
bne.s wait

#3 - Posted: 21 Nov 2004 22:47
Reply Quote
I'm going to try to explain, to see if i have grasped the idea. Please correct me if i'm wrong. A vertical blank occurs every time that the beam reaches the end of the screen. So on a PAL screen, that is 50 times / sec (what about NTSC, isn't that 60 times => 100 times would not amount to 2 seconds anymore?).

You can test if the vbl occurs by doing a bittest on bit 5 at $dff01f. So by incrementing a register (here d0) each time the vbl occurs, one can count time:
d0 = 50 => 1 second
d0 = 100 => 2 second...

Is that correct. And what about the move.w #$20,$dff01e ; interrupt ok line?

I have the impression that this is purely a wait, during which no routines can be executed. Because, it could happen that d0 is used in some routine, thus loosing it's value for counting in the mainloop?
#4 - Posted: 22 Nov 2004 05:55
Reply Quote
just put an 'add #1, counter' in the vblank interrupt, which is something you may not have set up yet...but if your demo is oneframe you might aswell put it in the mainloop

anyway it's a big pain in the ass to time demos after framecount. could anybody tell me how to detect a p61 signal command?
#5 - Posted: 22 Nov 2004 11:30 - Edited
Reply Quote
it's the problem with pal/ntsc and Vbl (I dont know more about Ntsc)
detect with execbase (if no 2.0 system) :
move.l 4.w,a6 ; execbase
cmp.b #50,VBlankFrequency(a6) ; Am I *running* PAL?
bne.s .ntsc
beq.s .pal

"move.w #$20,$dff01e" : the vbl interrupt is processed. so disable bit 5 of Intreq

more about Interruptions :
INTENA = Interrupt Enable $dff09a write / INTENAR = $dff01c Read
INTREQ = Interrupt Request $dff09c write / INTREQR = $dff01e read

bits :
15 set/clr
14 Inten = allowed
13 Exter CIA-B
12 DskSync
11 Rbf serial port
10-7 Audio channels
6 Blitter ready
5 Vbl
4 Copper
3 Cia-a (keyboard)
2 Software
1 DskBlk Dma Disk

8 levels of interrupt. each level have interrupt vector
level 1 - vector $64 : soft/DskBlk/Tbe
level 2 - vector $68 : keyboard
level 3 - vector $6c : Vbl/Copper/Blitter
level 4 - vector $70 : audio
level 5 - vector $74 : DskSyn/Rbf
level 6 - vector $78 : Cia-b

; setup a "simple" level3 interrupt
; No VBR in this example (vbr is for 68010+)
;save system
move.l $6c.w,oldintvbl ; or $6c(a0) with a0=vbrbase
move.w $dff01c,oldintena
move.w $dff096,olddma
; init new
move.w #$5ff,$dff096 ; blitHog+all
move.w #$7fff,$dff09a ; intena all bit off

lea interruptlev3(pc),a1
move.l a1,$6c.w ; new interrupt - or $6c(a0) with a0=vbrbase
move.w #$20,$dff09c ; intreq vbi off
move.w #$20,$dff09c ; twice
move.w #$c080,$dff096 ; dma copper on
move.w #$c020,$dff09a ; intena bit set and 5 (vbl)
move.w #$20,$dff09c ; intreq vbi off
move.w #$20,$dff09c ;
move.w #$7fff,$dff09a
move.w #$80,$dff096 ; dma copper off
move.l oldintvbl(pc),$6c.w ; or $6c(a0) with a0=vbrbase
move.w olddma(pc),d0 ; restore dma
or.w #$8000,d0
move.w d0,$dff096
move.w oldintena(pc),d0
or.w #$c000,d0
move.w d0,$dff09a

movem.l d0-d7/a0-a6,-(sp) ; creat the macro Push d0-a6 :))
; optional
move.w $dff01c,d0 ; intena
btst #14,d0 ; bit 14 Intena - authorized interruption ?
beq.s no
and.w $dff01e,d0 ; intreq
; or replace lines above by "move.w $dff01e,d0"
btst #5,d0 ; interrupt vbl ?
beq.s .no
lea timer(pc),a0
addq.l #1,(a0)
move.w #$0020,$dff09c ; Intreq = interrupt processed.
move.w #$0020,$dff09c ; twice for compatibility
movem.l (sp)+,d0-d7/a0-a6

timer dc.l 0
#6 - Posted: 22 Nov 2004 11:37
Reply Quote
could anybody tell me how to detect a p61 signal command?

p61 use a cia timer delay, no ?
#7 - Posted: 22 Nov 2004 12:52
Reply Quote

just put an 'add #1, counter' in the vblank interrupt, which is something you may not have set up yet...but if your demo is oneframe you might aswell put it in the mainloop

What do you mean by oneframe?

And can anyone give some more (general) info on what a cia timer is?
#8 - Posted: 22 Nov 2004 14:47 - Edited
Reply Quote
CIA=Complex Interface Adapter : manage a lot of things (serial, parallel port, keyboard, disk drive, joystick, mouse...)

2 parallel port 8 bits, 1 serial port, 2 timers 16 bits and 1 timer 24 bits.

2 CIA : CIA-A ($bfe001) and CIA-B ($bfd000)

16 bits timers : TA and TB - each with control register CRA and CRB
counter decrement x to 0. when -1 reached, can activate interrupt, restart counter... counter start when value write in TA or TB register

TimerA CIA-A : keyboard test
TimerB CIA-A : needed for several things
EC CIA-A : event counter. counter 50hz/60hz (24 bits)

TimerA CIA-B : used by serial data transfert
TimerB CIA-B : used in Blitter syncrone mode
EC CIA-B : event counter. horizontal syncrone impulse = 15625/sec. (24 bits)

ex. Timer 16 bits

delay=1/100 sec. max 9/100 sec (16 bits=65534). for more long delay, use 24 bits timer

amiga PAL : 7.09379 Mhz - CIA : 0.709379. decr 1/0.709379=1.4096836 microsec.
amiga NTSC : 7.15909 Mhz - CIA : 0.715909. decr 1/0.715909=1.3968255 microsec.

delay 1/100 sec = 10000 microsec : 10000/1.3968255=7159 NTSC value, 10000/1.4096839=7093 PAL value

example with TA CiaB for timing trackloader :
; forbid cia-b interrupt
move.w #$2000,$dff09a ; Intena bit 13
; init timer - one shot mode, 3 ms
lea $bfe001,a0 ; cia-B address
move.b $e00(a0),d0 ; CRA register
andi.b #$c0,d0 ; mask unused bits
ori.b #8,d0 ; mode one-shot
move.b d0,$e00(a0) ; new value
; set delay 3ms = $2821 PAL / $2148 Ntsc
move.b #$28,$400(a0) ; talo bit
move.b #$21,$500(a0) ; tahi bit
; wait
btst.b #0,$d00(a0) ; ICR register = Interruption ?
beq.s wait
... code here...
; restart timer and loop
bset.b #0,$e00(a0) ; reset CRA : timer restart
bra wait

CRA bits:
7 - TOD IN - TOD control 0=60 Hz / 1=50 Hz
6 - SPMODE - serial port control 0=input / 1=output
5 - INMODE - timer control 00=clock / 01=CNT
4 - LOAD - strobe
3 - RUNMODE - 0=continuous / 1=one shot
2 - OUTMODE - output 0=pulse / 1=toggle
1 - PBON - redirect timer to port B
0 - START - 0=stop / 1=start

CRB bits:
7 - ALARM -
6-5 - INMODE -... 10=Timer A / 11=CNT+Timer A
#9 - Posted: 23 Nov 2004 12:40
Reply Quote
What do you mean by oneframe?

oneframe means 50 fps... the effect is rendered faster than the refresh rate of the screen
#10 - Posted: 23 Nov 2004 15:02
Reply Quote
@ timing in general:
oneframe is the goal but cannot be achived in all cases. so you must be prepared that your demo will run slower sometimes. therefore never ever update your timing-counter in the main-loop!
i either used vbi-timing (just added 1 to a variable during the vertical blank interrupt) or mod-steered timing. the former is convienent for all your normal timing needs and gives you a resolution of 20ms (and disregard ntsc here! amiga demos ARE pal). the latter is perfect for "to-the-beat" timing of your demo when you really have a lot of syncs. but don't start with this. use the vbi-method first.

@ how to use the p61 timing:
read the docs and have a look at the souce.

@ cyf: the code you posted seems to be faulty. proper vertical blanc interrupt-code would store and restore all registers (with movem.l) before doing anything as the interrupt can appear ANYTIME! you wouldn't want to overwrite register states in your main-loop from your interrupt. moveover i think you shouldn't copy'n'paste big blocks of somebody-elses documentation as it makes this forum hard to read. give people a link to this document instead (but that's just a thought).
#11 - Posted: 23 Nov 2004 15:15 - Edited
Reply Quote
the code you posted seems to be faulty. proper vertical blanc interrupt-code would store and restore all registers (with movem.l) before doing anything

exact, sorry to have forgotten "movem.l d0-d7/a0-a6,-(sp) ... movem.l (sp)+,d0-d7/a0-a6"
but I can't edit my message !? forum write : "access denied" (@z5_ : why?)

edit: add Timer part in interrupt routine

think you shouldn't copy'n'paste big blocks of somebody-elses documentation as it makes this forum hard to read. give people a link to this document instead (but that's just a thought).

(hmm...not copy'n'paste...really typed !)
yes...I can creat some pages on my site, and give a link...(like my custom mod rip tutos here)
#12 - Posted: 23 Nov 2004 18:51
Reply Quote

Try editing now. Should work (it was a forum parameter)
#13 - Posted: 23 Nov 2004 20:14
Reply Quote
it's ok now :)
#14 - Posted: 24 Nov 2004 09:40
Reply Quote
okay, now it is time for me to paste some code as well. sorry ;)

; code-snippet by Noname 24.11.2004
; taken and stripped from WickedOS
; this is not a startup-code. this is just a code-snippet
; that demonstrates how to set up a working level 3 interrupt.
; works with moved vector base table (68010+) while
; still maintaining 68000 compatibility.
; comes with example interrupt-code that increments a timer.
; hasn't been assembled for testing so bugs my lurk around.


;--- get the vbr which is most probably somewhere in fast-ram
lea getvbr(pc),a5
move.l 4.w,a6
jsr -30(a6) ; returns vbr in d0
lea vbroffset(pc),a0
move.l d0,(a0) ; store vbr

;--- you could store some old values here

;--- register our own level 3 interrupt (vertical blanc and blitter)
lea Level3Int(pc),a1
move.l a1,$6c(a0)

;--- get the vector base register
getvbr: ;movec vbr,d0
dc.l $4e7a0801 ; this is the opcode for the above command
vbroffset: dc.l 0

;--- this is the actual interrupt code
; it could interrupt (!) your main-programm at anytime so better
; save the register states. this is what the push macro does (it uses movem.l).
push d0-a6 ; exercise: rewrite this macro on your own!
lea $dff000,a6

move.w $dff01e,d0 ; intreq-read
btst #5,d0 ; Vertical Blanc?
bne .vertb
btst #6,d0 ; Blitter
bne .blit
bra .quitL3

;--- Blitter
;--- your code here

move.w #$4040,$dff09c
move.w #$4040,$dff09c
bra .quitL3

;--- Vertical Blanc
lea Timer(pc),a0
addq.l #1,(a0) ; increase Timer by 1

;--- your code here

move.w #$4020,$dff09c
move.w #$4020,$dff09c
bra.w .quitL3

pull d0-a6

;--- this Timer is updated once a frame.
; there are 50 FPS on a PAL Amiga, so this variable has a resolution
; of 1/50 s
; or 20/1000 s
; or 20 ms
Timer: dc.l 0
#15 - Posted: 24 Nov 2004 09:43
Reply Quote
hmm, the board ate the line-indentions which makes it hard to read. you would also have to do them again when trying to use this code.
@z5: can we have some kind of syntax coloring here?
#16 - Posted: 3 Dec 2004 21:31 - Edited
Reply Quote
example of timer using the music tracker :

in "new line" routine of tracker, increment the timer variable.
with this method, you can start an effect when tracker play a specific note

lea part,a0
add.l partpos,a0 ; part position
move.l timer,d0
move.l (a0)+,d1 ; get time for next part
cmp.l d0,d1
bhi .notyet
addq.l #8,partpos
move.l (a0),a0 ; next part code
jsr (a0) ; start next part
bra loop
;-------------- protracker for example
newline: ; or "new" or "next", where a new line of the pattern is read
add.l #1,timer ; increment timer var.

timer ds.l 1

; part tab (time,routine)
dc.l 1,init_firstpart ; go to the firstpart init routine when tracker reach line 1 (pattern 0)
dc.l 64,go_firstpart ; when line 64 reached (pattern 1)
#17 - Posted: 3 Dec 2004 21:52
Reply Quote
more simple, you can use the Dos library function "Delay" :
offset -198 : Delay(timeout) (d1)
timeout is 1/50 sec.

; try to write the 3 macros (opendos,calldos and closedos)
opendos ; macro
beq error
move.l #50*3,d1 ; 3 sec.
calldos Delay ; -198
closedos ; macro
#18 - Posted: 4 Dec 2004 10:03
Reply Quote

i was reading with great interest your interrupt level 3 code because i want to include vbl interrupt to add some timing. I understand the interrupt routine itself, but what i don't understand: what is "vector base register" and why is it needed. Also, what is (pc)? Any place i can find out more about these?
#19 - Posted: 4 Dec 2004 12:21 - Edited
Reply Quote
on 68000, vector base address is in chip ram at $0
from 68010, this address can be changed from $0 to fast ram, so all the interrupt vectors (like $6c) and trap vectors (like $80) will be in fast ram at VBR+$6c and VBR+$80...
it's possible to move to $0 the VBR to make old software compatible, but now soft must be coded with VBR in fast for the speed increasing.
all the needed is to know where is the VBR and made offsets from the VBRBASE.

PC=Program Counter. position where the 68000 read the current line code.
use variable(pc) is better for full relocatable code.
(but not possible with variable in chip and code in fast or other mem block)
#20 - Posted: 4 Dec 2004 15:12
Reply Quote
what cyf said.

pc-relative coding is nice but not always possible nor always necessary. it is generally shorter and more versatile because the code can be run from any place in memory (not that it would matter in this case!) without having to relocate the code (that is: fix all absolute addresses for the new location). you also save bytes in the final executeable every time you use pc-relative code but that explanation would go to far for the moment.

get a motorola mc68000 reference manual or any other guide on the subject. google "pc-relative 68000" gave me this link to a book which seems to make sense: The 68000 Microprocessor. but full online infos should be around as well. maybe its worth to gather some links.
#21 - Posted: 4 Dec 2004 15:34 - Edited
Reply Quote
MC680x0 Reference 1.1, (c)April,May 1995 by Flint/DARKNESS.

This is an excellent document. I had v1.0 as an Amiga Guide version and it helped me many times. I also had some other documents on the subject but this one was the most comprehensive. Still you should consider buying a book if you are really serious about assembly programming. They usually don't teach you demo coding but show you other necessary tricks and skills.
#22 - Posted: 4 Dec 2004 17:56 - Edited
Reply Quote
Amiga Related Books FAQ seems to be a must read. Section 2 is about Assembly Programming but all sections seem to be worth reading. Very good!

"This FAQ is compiled as a service to the Amiga community. It is an attempt to give the Amiga programmer and user an overview of useful books for his/her favorite computer. It is not complete."
#23 - Posted: 5 Dec 2004 09:18
Reply Quote
You can also download for free the official Motorola Documentation.
It is not a tutorial, but it's the reference:

http://www.freescale.com/webapp/sps/library/documentationlist.jsp?root NodeId=01&nodeId=018rH3YTLC4622&Device=All&DocTypeKey=10Ksfwlk&Results =25
#24 - Posted: 5 Dec 2004 15:19
Reply Quote
I can't manage to get the interrupt working. I have learned much on the way, but my counter just doesn't add up in my level 3 interrupt routine. I have gotten the vector base register, moved my interrupt routine address in there ($6c + offset vbr), i've turned on my master interrupt + vbl interrupt (move.w $c020, intena(a5)).

Is there any way of checking if the interrupt actually occurs. Anything in asm-one i could monitor/do to actually understand why my timer doesn't count?
#25 - Posted: 5 Dec 2004 15:44
Reply Quote
Áz5: it seems that everthing is right. Can you post the interrupt handler and the code use use to set it up?
#26 - Posted: 5 Dec 2004 18:26 - Edited by Admin
Reply Quote
Well, my source is here. I've worked quite a bit on the startup-code, folowing the tutorial from Dr.Doom in Eurochart, so i think i'm doing all that is needed regarding startup/shutdown. But my interrupt doesn't work. And i really don't see it :) So if anybody could have a look at it, that would be great (please note: i'm a complete newbie!!)
#27 - Posted: 6 Dec 2004 09:44 - Edited
Reply Quote

I write suggestions as long as I go through your source! :-)

1) put, before the start of any routine, a cnop 0,4, so that the routine will be LONG aligned, which is better for the caching and fetching of instructions

2) I would put the call to LVOForbid, earlier. It may happen that after you do the LoadView(NULL), a different task change the view. So better Forbid them before the LoadView. The same also for VBR.

3) ERROR!!!! :-) in the KillsintDMA, you should do move.W #$7fff,dmacon
DMACON is a 16 bit register. With INTENA you do .L because at the same time you clear INTREQ ;-)

4) the double move #$0020 to intreq before the write to intena is useless, you already cleared INTREQ in the subroutine KillsintDMA

5) ERROR: IMHO, you should first build the copperlist with the routines
bsr initspritept
bsr initbplpointers
THEN load the copper location pointer with
lea copper,a1 ;indicate where our copper list is
move.l a1,cop1lc(a5) ;load copper list
move dx,COPJMP1(a5) <-*********** you forget this!!!!!!! very important

THEN turn ON DMA, but better first SET to 0 all DMA you don't need and then turn ON the master DMA, so:

;and here, the control bit is 0, which means that all bits with a 1 are
;cleared in dmacon, so here bit 5 is set to 0 => disable sprite dma

move.w #%0000000000100000,dmacon(a5)

;enable copper, blitter and bitplane dma
; EPS!!! Forget to turn ON the Master DMA, controls all the others!!!

move.w #%1000000111000000,dmacon(a5)

FINALLY allow interrupts
move.w #$c020,intena(a5)

6) again, why fill the copperlist with useless color-loading instruction?
in the routine startpic, simply change from lea colorcop+2,a2
to lea color00(a5),a2, remove the addq.l #2,a2 in the loop and remove all the colorcop stuff from the copperlist. You gain speed and memory!

Ok, now it should work, please try! ;-)
By the way, in the Interrupt Handler, it's useless to clear bit #14 if INTREQ, that bit is only used in INTENA, in INTREQ is hardwired to 0,
so MOVE #$0020,INTREQ(a5).
In the future, I may have other suggestions about how to clear the INTREQ , a way to avoid the double write....but I still have to do experiments. Let's see... ;-)

Hope it helps
#28 - Posted: 6 Dec 2004 13:47 - Edited
Reply Quote
I read somewhere that the double WaitTOF cancel the Forbid...so forbid after waittof

I tried to rewrite quickly a startup code (good old days!) : interrupt works fine but a little problem with copper not displayed! ^^

which only goes to show it's important to have a good example of startup!

so if you want to post a step by step modern startup code with all good explanations.

why? because I tested my old codes, and I see that with some of my startup a1200 compatible using the same way - waittof,vbr...- interrupt doesnt work anymore under WB A1200 or winuae but versions already compiled on A500 works!!, and old version of startup (without waittof,vbr) works fine on A1200,winuae...!?? arrggl
#29 - Posted: 6 Dec 2004 13:55
Reply Quote
I second that. I have a nice startup written by Piru (resident of amiga.org)

http://ada.planet-d.net/forum/index.php?action=vthread&forum=4&topic=2 2

But the more startup examples explained to detail the better.

Whats the link to the Eurochart Dr. Doom tutorial?
#30 - Posted: 6 Dec 2004 14:00
Reply Quote

I read somewhere that the double WaitTOF cancel the Forbid...so forbid after waittof

where did you read this? I'll check my copy of RKRM, but I don't think it's true. While the Amiga hardare has several obscure points, the AmigaOS system calls are well documented in the RKRM and in the autodocs of the C= developers kit. So if the WaitTOF has this side effect, this should be mentioned there. Anyway, what I really do is to call LVODisable before taking control of the display, i.e. after the LoadView and the WaitTof. The Disable/Enable pair stops multitasking even better than the Forbid/Permit, I don't recall the difference but its explained in the RKRM. My programs never had any problems in taking control of the system (well, at least not with this issue!! :-)
Well, I'll try to comment my startup code and propose it to you!
Hope it helps
 Page:  1  2  3  »» 

  Please log in to comment





A.D.A. Amiga Demoscene Archive, Version 3.0