home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
network
/
netlib_1
/
NetLibSrc
/
s
/
gettime
< prev
next >
Wrap
Text File
|
1995-08-19
|
6KB
|
198 lines
; ----------------------------------------------------------------------
; Copyright Adam Goodfellow 1994, all rights reserved.
;
; Fast ARM code implementation of unix gettimeofday(2) function.
;
; C structures and function prototype:
;
; struct timeval {
; long tv_sec; /* seconds */
; long tv_usec; /* and microseconds */
; };
;
; struct timezone {
; int tz_minuteswest; /* minutes west of Greenwich */
; int tz_dsttime; /* type of dst correction */
; };
;
; int gettimeofday(struct timeval *tv, struct timezone *tz);
;
IOC_Base EQU &3200000
IOC_T0CountLow EQU &40
IOC_T0CountHigh EQU &44
IOC_T0LatchLow EQU &40
IOC_T0LatchHigh EQU &44
IOC_T0GoCommand EQU &48
IOC_T0GetCount EQU &4C
XOS_EnterOS EQU &020016
XOS_Word EQU &020007
r0 RN 0
r1 RN 1
r2 RN 2
r3 RN 3
r4 RN 4
r5 RN 5
r6 RN 6
r7 RN 7
r8 RN 8
r9 RN 9
r10 RN 10
r11 RN 11
r12 RN 12
r13 RN 13
r14 RN 14
r15 RN 15
sp RN 13
lr RN 14
pc RN 15
psr RN 15
i_flag EQU &08000000
svc_mode EQU &00000003
AREA |C$$code|,CODE,READONLY
r_s RN 0 ;seconds
r_u RN 1 ;micro seconds
r_a RN 2 ;LS 32 bits of 40bit Risc OS time of day
r_b RN 3 ;MS 8 bits of 40bit Risc OS time of day
r_c RN 4 ;1/2 micro-secs read for IOC timer 0
r_p RN 5 ;Temp reg }
r_t RN 6 ;Temp reg } On of these is not needed
r_v RN 7 ;Temp reg }
r_tv RN 8 ;struct timeval *tv, or NULL
r_tz RN 9 ;struct timezone *tz, or NULL
;Uses 8 bytes of stack for temp space
; 44 bytes for register storage.
; could be reduced to 28 by fiddling temp regs and not saving r0-r3
;
; -------------------------------------------------------------------------
; Read time of day and us from IOC timer 0
;
;On entry:
; R0 = pointer to buffer for timeval struct
; R1 = pointer to buffer for timezone struct
;
EXPORT gettimeofday
gettimeofday
STMFD sp!, {r0-r9, lr}
MOV r_tz, r1
MOVS r_tv, r0 ;timeval wanted?
BEQ tod_tz ;no - straight to timezone
SUB sp, sp, #8
MOV r1, sp ;Take SP here as wont be avilable later
MOV r_p, psr ;Keep PSR from current processor mode
SWI XOS_EnterOS
TEQP psr, #(i_flag :OR: svc_mode) ;Disable IRQs, stay in SVC mode
MOV r_a, #IOC_Base ;Read IOC timer 0 value
STRB r_a, [r_a, #IOC_T0GetCount]
LDRB r_b, [r_a, #IOC_T0LatchLow]
LDRB r_c, [r_a, #IOC_T0LatchHigh]
ORR r_b, r_b, r_c, LSL #8
MOV r_a, #&4e00 ;20000-n
ORR r_a, r_a, #&20
SUB r_b, r_a, r_b
MOV r0, #3 ;Get real time while IRQs still
STRB r0, [r1, #0] ;disabled to stop it ticking over
MOV r0, #14 ;Returns 40 bit binary
SWI XOS_Word
TEQP psr, r_p ;Back to processor mode and IRQ state on entry
MOV r_p, r_p
LDMIA sp!, {r_a, r_b} ;t[4]...t[0] are bytes in r_a and r_b
AND r_b, r_b, #&ff ;Just want one byte from r_b
; r_a, r_b = Real time, r_c counter time (micro secs)
; ----------
LDR r_v, =&6e996a00 ;To Unix and C time range
SUBS r_a, r_a, r_v ;5 byte time - 0x336e996a00
SBC r_b, r_b, #&33 ;Risc OS time of 1st Jan 1970
; ----------
; r_t is a temp, r_v is a temp, r_u is usecs, r_s is secs
; The following is a 40 bit div/mod by 100
MOV r_s, #0 ;tv->tv_sec = 0
MOV r_u, #0 ;tv->tv_usec = 0
MOV r_t, r_b ;t[4]
ORR r_u, r_t, r_u, LSL #8 ;tv->tv_usec = (tv->tv_usec<<8) | t[4];
CMP r_u, #100 ;if (tv->tv_usec>=100)
BLGE divmod100 ; tv->tv_usec = tv->tv_usec % 100;
ORRGE r_s, r_t, r_s, LSL #8 ; tv->tv_sec = (tv->tv_sec<<8) | (tv->tv_usec/100);
MOV r_t, r_a, LSR #24 ;t[3]
ORR r_u, r_t, r_u, LSL #8 ;tv->tv_usec = (tv->tv_usec<<8) | t[4];
CMP r_u, #100 ;if (tv->tv_usec>=100)
BLGE divmod100 ; tv->tv_usec = tv->tv_usec % 100;
ORRGE r_s, r_t, r_s, LSL #8 ; tv->tv_sec = (tv->tv_sec<<8) | (tv->tv_usec/100);
MOV r_t, r_a, LSR #16
AND r_t, r_t, #&ff ;t[2]
ORR r_u, r_t, r_u, LSL #8 ;tv->tv_usec = (tv->tv_usec<<8) | t[4];
CMP r_u, #100 ;if (tv->tv_usec>=100)
BLGE divmod100 ; tv->tv_usec = tv->tv_usec % 100;
ORRGE r_s, r_t, r_s, LSL #8 ; tv->tv_sec = (tv->tv_sec<<8) | (tv->tv_usec/100);
MOV r_t, r_a, LSR #8
AND r_t, r_t, #&ff ;t[1]
ORR r_u, r_t, r_u, LSL #8 ;tv->tv_usec = (tv->tv_usec<<8) | t[4];
CMP r_u, #100 ;if (tv->tv_usec>=100)
BLGE divmod100 ; tv->tv_usec = tv->tv_usec % 100;
ORRGE r_s, r_t, r_s, LSL #8 ; tv->tv_sec = (tv->tv_sec<<8) | (tv->tv_usec/100);
MOV r_t, r_a
AND r_t, r_t, #&ff ;t[0]
ORR r_u, r_t, r_u, LSL #8 ;tv->tv_usec = (tv->tv_usec<<8) | t[4];
CMP r_u, #100 ;if (tv->tv_usec>=100)
BLGE divmod100 ; tv->tv_usec = tv->tv_usec % 100;
ORRGE r_s, r_t, r_s, LSL #8 ; tv->tv_sec = (tv->tv_sec<<8) | (tv->tv_usec/100);
RSB r_t, r_u, r_u, LSL #7 ;cs x 10000 to get usecs
SUB r_u, r_t, r_u, LSL #1
ADD r_u, r_u, r_u, LSL #2
MOV r_u, r_u, LSL #4
ADD r_u, r_u, r_c, LSR #1 ;Add in usecs/2 from IOC Timer
STMIA r_tv, {r_s, r_u} ;Write to timeval struct
tod_tz TEQ r_tz, #0 ;Optionally write time zone (zero for now)
MOVNE r_s, #0
MOVNE r_u, #0
STMNEIA r_tz, {r_s, r_u}
LDMFD sp!, {r0-r9, pc}^
; ----------
; Highly optimised 16 bit div/mod 100
; could inline this with conditionals to give constant execution time.
divmod100
MOV r_v, r_u, LSR #1 ;Divide by 100 to get seconds
RSB r_v, r_v, r_v, LSL #3
RSB r_v, r_v, r_v, LSL #3
RSB r_t, r_v, r_v, LSL #7
ADD r_v, r_v, r_v, LSL #2
SUB r_v, r_t, r_v, LSL #2
MOV r_t, r_v, LSR #18 ;result in r_t
ADD r_v, r_t, r_t, LSL #2 ;Remainder of division (0-99)
ADD r_v, r_v, r_v, LSL #2
SUB r_u, r_u, r_v, LSL #2 ;remainder back in r_u
MOVS pc, lr
END