1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 #include "msaturn.h" 9 10 enum { 11 Timer_ctrl = Saturn + 0x0106, 12 Timer0_load = Saturn + 0x0200, 13 Timer0_cnt = Saturn + 0x0204, 14 Timer1_load = Saturn + 0x0300, 15 Timer1_cnt = Saturn + 0x0304, 16 17 T0_event = RBIT(13, ushort), 18 T0_ie = RBIT(14, ushort), 19 T0_cen = RBIT(15, ushort), 20 T1_event = RBIT(5, ushort), 21 T1_ie = RBIT(6, ushort), 22 T1_cen = RBIT(7, ushort), 23 }; 24 25 static ulong ticks; 26 static Lock tlock; 27 static ushort timer_ctl; 28 29 ulong multiplier; 30 31 ulong 32 µs(void) 33 { 34 uvlong x; 35 36 if(multiplier == 0){ 37 multiplier = (uvlong)(1000000LL << 16) / m->cyclefreq; 38 print("µs: multiplier %ld, cyclefreq %lld, shifter %d\n", multiplier, m->cyclefreq, 16); 39 } 40 cycles(&x); 41 return (x*multiplier) >> 16; 42 } 43 44 void 45 saturntimerintr(Ureg *u, void*) 46 { 47 ushort ctl = *(ushort*)Timer_ctrl, v = 0; 48 49 if(ctl&T1_event){ 50 v = T1_event; 51 ticks++; 52 } 53 54 *(ushort*)Timer_ctrl = timer_ctl|T0_event|v; 55 intack(); 56 timerintr(u, 0); 57 } 58 59 void 60 timerinit(void) 61 { 62 *(ushort*)Timer_ctrl = 0; 63 *(ulong*)Timer0_load = m->bushz / HZ; 64 *(ulong*)Timer0_cnt = m->bushz / HZ; 65 *(ulong*)Timer1_load = m->bushz; 66 *(ulong*)Timer1_cnt = m->bushz; 67 68 intrenable(Vectimer0, saturntimerintr, nil, "timer"); 69 70 timer_ctl = T0_cen|T0_ie|T1_cen; 71 *(ushort*)Timer_ctrl = timer_ctl; 72 } 73 74 uvlong 75 fastticks(uvlong *hz) 76 { 77 assert(*(ushort*)Timer_ctrl&T1_cen); 78 if(*(ushort*)Timer_ctrl&T1_event){ 79 *(ushort*)Timer_ctrl = timer_ctl|T1_event; 80 ticks++; 81 } 82 83 if (hz) 84 *hz = m->bushz; 85 86 return (uvlong)ticks*m->bushz+(uvlong)(m->bushz-*(ulong*)Timer1_cnt); 87 } 88 89 void 90 timerset(Tval next) 91 { 92 ulong offset; 93 uvlong now; 94 95 ilock(&tlock); 96 *(ushort*)Timer_ctrl = T1_cen; 97 98 now = fastticks(nil); 99 offset = next - now; 100 if((long)offset < 10000) 101 offset = 10000; 102 else if(offset > m->bushz) 103 offset = m->bushz; 104 105 *(ulong*)Timer0_cnt = offset; 106 *(ushort*)Timer_ctrl = timer_ctl; 107 assert(*(ushort*)Timer_ctrl & T1_cen); 108 iunlock(&tlock); 109 } 110 111