FB II Compiler

PG PRO

Debugging

Memory

System

Mathematics

Resources

Disk I/O

Windows

Controls

Menus

Mouse

Keyboard

Text

Fonts

Drawing

Sound

Clipboard

Printing

Communication

ASM

Made with FB

MATHEMATICS

Set delays in milliseconds


The following example was posted a couple of months ago. It includes a minor refinement: a correction term gMSOverhead (set in FN MeasureMSOverhead) that improves the accuracy of the delay on slow machines. You could remove all mention of gMSOverhead on any reasonably fast machine, i.e. if the overhead reported by this program is much less than the delays you actually want.
'--------------A Complete FB2 Program----------------
COMPILE 0,_dimmedVarsOnly

DIM RECORD anyOldNameAtAll
 DIM mSHi&,mSLo&
DIM END RECORD.microSecRecord

DIM gMSOverhead&

END GLOBALS

LOCAL FN Microseconds (mSRecPtr&)
 ` move.l ^mSRecPtr&,-(sp)
 ` dc.w $A193 ; 68k trap word
 ` move.l (sp)+,a1
 ` move.l a0,(a1)+
 ` move.l d0,(a1)
END FN

LOCAL FN MeasureMSOverhead
 DIM myMS1.microSecRecord, myMS2.microSecRecord, j
 FN Microseconds(@myMS1)
 FOR j=1 TO 1000
  FN Microseconds(@myMS2)
 NEXT
 gMSOverhead& = (myMS2.mSLo&-myMS1.mSLo&)/1000
END FN

LOCAL FN DelayMicroSeconds (delayMicrS&)
 ' Waste time (up to _maxlong'!47483647 microseconds).
 ' Accuracy is best for delayMicrS& at least a few hundred.
 DIM myMS1.microSecRecord, myMS2.microSecRecord
 ' compensate for time calling FN Microseconds
 delayMicrS& = delayMicrS& - gMSOverhead&
 IF delayMicrS&<=0 THEN EXIT FN
 'calculate what time to wait until
 FN Microseconds(@myMS1)        'read the timer
 LONG IF ((myMS1.mSLo& + delayMicrS&) < myMS1.mSLo&)
  INC(myMS1.mSHi&)              ' addition caused carry
 END IF
 myMS1.mSLo&=myMS1.mSLo& + delayMicrS&

 DO                             'waste time in this loop
  FN Microseconds(@myMS2)       'poll the timer
 UNTIL (myMS2.mSLo&>=myMS1.mSLo&) AND (myMS2.mSHi&>=myMS1.mSHi&)
END FN

' demo main program
DIM ticksWas&, ticksNow&, microSecDelayWanted&, j
WINDOW 1
FN MeasureMSOverhead
PRINT "Overhead = " gMSOverhead& " microseconds"

microSecDelayWanted&= 5 * 1000  ' 5 ms
ticksWas&=FN TICKCOUNT
FOR j=1 TO 200                  ' do 200 individual delays
 FN DelayMicroSeconds(microSecDelayWanted&)
NEXT
ticksNow&=FN TICKCOUNT
PRINT ticksNow&-ticksWas&" ticks elapsed"

DO: HANDLEEVENTS: UNTIL FN BUTTON
'--------------------------------------------------------
Robert Purves

'=================
'timing in microseconds
LONG FN MicroSeconds&
` dc.w $A193  ;  trap word
END FN' returns low longword of 8-byte result
'=================
Don't use the tiny FN above (for which I claim, or perhaps admit, responsibility). It was devised for minimum overhead, and worked OK in FB2, but for FB^3 you need something better.

The program below shows the proper syntax, allowing 68K, PPC or FAT.

Note that the components of the microSecRecord are defined as the new FB^3 type UNSIGNED LONG. The definition unfortunately reveals a bug in release 0 of FB^3: it cannot print variables of that type.

You can print them with the help of the STR$ function, but _another_ bug is revealed: the UNSIGNED nature is lost. Since microSecLo counts MOD 4294967296, it has a period of 4294.967296s (about 71 minutes). STR$(myMS.microSecLo) therefore displays as a positive number for 35 minutes then negative for 35 minutes. The UNS$ function correctly displays myMS.microSecLo as always positive, but it shouldn't be necessary to use UNS$ on an already UNSIGNED variable.
'----------------------------------------------------------
BEGIN RECORD microSecRecord
DIM microSecHi AS UNSIGNED LONG
DIM microSecLo AS UNSIGNED LONG
END RECORD

TOOLBOX Microseconds (LONG) `0xA193,0x225F,0x22C8,0x2280
/* what those 0x values mean in 68K
  dc.w $A193      ;0xA193
  move.l (sp)+,a1 ;0x225F
  move.l a0,(a1)+ ;0x22C8
  move.l d0,(a1)  ;0x2280
*/

LOCAL FN ShowTime
DIM myMS as microSecRecord
DEFSTR LONG
FN Microseconds(@myMS)
' Next line doesn't compile - comment it out
'PRINT myMS.microSecHi, myMS.microSecLo ' BUG
' STR$ should show unsigned values, but doesn't - another BUG
PRINT STR$(myMS.microSecHi), STR$(myMS.microSecLo)
' At last...a way to show the unsigned longs
PRINT UNS$(myMS.microSecHi), UNS$(myMS.microSecLo)
END FN

WINDOW 1
ON TIMER(1) FN ShowTime
DO
HANDLEEVENTS
UNTIL FN BUTTON
'----------------------------------------------------------
Robert Purves

See below. For a delay in milliseconds, just call FN DelayMicroSeconds(millisecs*1000). This works in 68K or PPC, and on a machine of any speed. There's no need for an initial testing function, since the Time Manager uses an internal fixed-rate clock.
'--------------------------------------------------------
BEGIN RECORD microSecRecord
DIM microSecHi AS UNSIGNED LONG
DIM microSecLo AS UNSIGNED LONG
END RECORD

TOOLBOX Microseconds (LONG) `0xA193,0x225F,0x22C8,0x2280

LOCAL FN DelayMicroSeconds(delayMicrS&)
' waste time (up to _maxlong!47483647 microseconds)
  DIM myMS1 as microSecRecord, myMS2 as microSecRecord
  IF delayMicrS&<=0 THEN EXIT FN
'calculate what time to wait until
  FN Microseconds(@myMS1)
  LONG IF (myMS1.microSecLo + delayMicrS& < myMS1.microSecLo)
    inc(myMS1.microSecHi) ' addition caused carry
  END IF
  myMS1.microSecLo=myMS1.microSecLo + delayMicrS&

  DO 'waste time in this loop
    FN Microseconds(@myMS2)
  UNTIL (myMS2.microSecLo>=myMS1.microSecLo) AND (myMS2.microSecHi>=myMS1.microSecHi)
END FN

' demo main program
DIM microSecsAsked&,ticksWas&, ticksNow&
WINDOW 1
microSecsAsked&=1000000
ticksWas&=FN TICKCOUNT
FN DelayMicroSeconds(microSecsAsked&)
ticksNow&=FN TICKCOUNT
PRINT "Requested delay = " microSecsAsked&/16666 " ticks"
PRINT "Measured delay = " ticksNow&-ticksWas&" ticks"
DO
  HANDLEEVENTS
UNTIL FN BUTTON
'--------------------------------------------------------
Robert Purves