#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "msaturn.h" enum { Timer_ctrl = Saturn + 0x0106, Timer0_load = Saturn + 0x0200, Timer0_cnt = Saturn + 0x0204, Timer1_load = Saturn + 0x0300, Timer1_cnt = Saturn + 0x0304, T0_event = RBIT(13, ushort), T0_ie = RBIT(14, ushort), T0_cen = RBIT(15, ushort), T1_event = RBIT(5, ushort), T1_ie = RBIT(6, ushort), T1_cen = RBIT(7, ushort), }; static ulong ticks; static Lock tlock; static ushort timer_ctl; ulong multiplier; ulong µs(void) { uvlong x; if(multiplier == 0){ multiplier = (uvlong)(1000000LL << 16) / m->cyclefreq; print("µs: multiplier %ld, cyclefreq %lld, shifter %d\n", multiplier, m->cyclefreq, 16); } cycles(&x); return (x*multiplier) >> 16; } void saturntimerintr(Ureg *u, void*) { ushort ctl = *(ushort*)Timer_ctrl, v = 0; if(ctl&T1_event){ v = T1_event; ticks++; } *(ushort*)Timer_ctrl = timer_ctl|T0_event|v; intack(); timerintr(u, 0); } void timerinit(void) { *(ushort*)Timer_ctrl = 0; *(ulong*)Timer0_load = m->bushz / HZ; *(ulong*)Timer0_cnt = m->bushz / HZ; *(ulong*)Timer1_load = m->bushz; *(ulong*)Timer1_cnt = m->bushz; intrenable(Vectimer0, saturntimerintr, nil, "timer"); timer_ctl = T0_cen|T0_ie|T1_cen; *(ushort*)Timer_ctrl = timer_ctl; } uvlong fastticks(uvlong *hz) { assert(*(ushort*)Timer_ctrl&T1_cen); if(*(ushort*)Timer_ctrl&T1_event){ *(ushort*)Timer_ctrl = timer_ctl|T1_event; ticks++; } if (hz) *hz = m->bushz; return (uvlong)ticks*m->bushz+(uvlong)(m->bushz-*(ulong*)Timer1_cnt); } void timerset(Tval next) { ulong offset; uvlong now; ilock(&tlock); *(ushort*)Timer_ctrl = T1_cen; now = fastticks(nil); offset = next - now; if((long)offset < 10000) offset = 10000; else if(offset > m->bushz) offset = m->bushz; *(ulong*)Timer0_cnt = offset; *(ushort*)Timer_ctrl = timer_ctl; assert(*(ushort*)Timer_ctrl & T1_cen); iunlock(&tlock); }