We are starting new season of the labs. Season 2 will be named as “Close to hardware”. And we start from important point to have clocks and timers working. But first we made a decision to make our codes close to 9pi source codes, especially assembler parts. But we found it little complicated as UReg struct on Plan 9 have r14 and link as union while Inferno has them separate. We can not change Ureg in arm/include as we would break another ports. Instead we created os/rpi/include and copied modified ureg.h there.

As it was done, we can make our codes for exceptions very similar (lamost same) as used in 9pi.

To add clocks and timers we would modify rpi and mkfile to add ready module from ports – tod. And add clock.c file:

  1#include "../port/portclock.c"
  2
  3#define SYSTIMERS   (IOBASE+0x3000)
  4#define ARMTIMER    (IOBASE+0xB400)
  5
  6enum {
  7	SystimerFreq    = 1*Mhz,
  8	MaxPeriod   = SystimerFreq/HZ,
  9	MinPeriod   = SystimerFreq/(100*HZ)
 10};
 11
 12typedef struct Systimers Systimers;
 13typedef struct Armtimer Armtimer;
 14
 15struct Systimers {
 16	u32int  cs;
 17	u32int  clo;
 18	u32int  chi;
 19	u32int  c0;
 20	u32int  c1;
 21	u32int  c2;
 22	u32int  c3;
 23};
 24
 25struct Armtimer {
 26	u32int  load;
 27	u32int  val;
 28	u32int  ctl;
 29	u32int  irqack;
 30	u32int  irq;
 31	u32int  maskedirq;
 32	u32int  reload;
 33	u32int  predivider;
 34	u32int  count;
 35};
 36
 37enum {
 38	CntPrescaleShift    = 16,       /* freq is sys_clk/(prescale+1) */
 39	CntPrescaleMask     = 0xFF,
 40	CntEnable           = 1<<9,
 41	TmrDbgHalt          = 1<<8,
 42	TmrEnable           = 1<<7,
 43	TmrIntEnable        = 1<<5,
 44	TmrPrescale1        = 0x00<<2,
 45	TmrPrescale16       = 0x01<<2,
 46	TmrPrescale256      = 0x02<<2,
 47	CntWidth16          = 0<<1,
 48	CntWidth32          = 1<<1
 49};
 50
 51static void
 52clockintr(Ureg * ureg, void *)
 53{
 54	Systimers *tn;
 55
 56	tn = (Systimers*)SYSTIMERS;
 57	/* dismiss interrupt */
 58	tn->cs = 1<<3;
 59	timerintr(ureg, 0);
 60}
 61
 62void
 63clockinit(void)
 64{
 65	Systimers *tn;
 66	Armtimer *tm;
 67	u32int t0, t1;
 68	u32int tstart, tend;
 69
 70	tn = (Systimers*)SYSTIMERS;
 71	tm = (Armtimer*)ARMTIMER;
 72	tm->load = 0;
 73	tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
 74
 75	tstart = tn->clo;
 76	do{
 77		t0 = lcycles();
 78	}while(tn->clo == tstart);
 79	tend = tstart + 10000; /* 10 msecs */
 80	do{
 81		t1 = lcycles();
 82	}while(tn->clo != tend);
 83	t1 -= t0;
 84	m->cpuhz = 100 * t1;
 85
 86	tn->c3 = tn->clo - 1;
 87	irqenable(IRQtimer3, clockintr, nil);
 88}
 89
 90void
 91clockcheck(void) { return; }
 92
 93uvlong
 94fastticks(uvlong *hz)
 95{
 96	Systimers *tn;
 97	ulong lo, hi;
 98
 99	tn = (Systimers*)SYSTIMERS;
100	if(hz)
101		*hz = SystimerFreq;
102	do{
103		hi = tn->chi;
104		lo = tn->clo;
105	}while(tn->chi != hi);
106	m->fastclock = (uvlong)hi<<32 | lo;
107	return m->fastclock;
108}
109
110void
111timerset(uvlong next)
112{
113	Systimers *tn;
114	vlong now, period;
115
116	tn = (Systimers*)SYSTIMERS;
117	now = fastticks(nil);
118	period = next - fastticks(nil);
119	if(period < MinPeriod)
120		next = now + MinPeriod;
121	else if(period > MaxPeriod)
122		next = now + MaxPeriod;
123	tn->c3 = (ulong)next;
124}

Also there are another minor changes to dat.h, etc.

FILES: