#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);
}
|