1*ccaec48aSDavid du Colombier #include <u.h>
2*ccaec48aSDavid du Colombier #include <libc.h>
3*ccaec48aSDavid du Colombier #include "dat.h"
4*ccaec48aSDavid du Colombier #include "fns.h"
5*ccaec48aSDavid du Colombier
6*ccaec48aSDavid du Colombier enum {
7*ccaec48aSDavid du Colombier AC0 = 0,
8*ccaec48aSDavid du Colombier AC1,
9*ccaec48aSDavid du Colombier AC2,
10*ccaec48aSDavid du Colombier Actl,
11*ccaec48aSDavid du Colombier
12*ccaec48aSDavid du Colombier Readback = 3,
13*ccaec48aSDavid du Colombier
14*ccaec48aSDavid du Colombier RBC0 = 1<<1,
15*ccaec48aSDavid du Colombier RBC1 = 1<<2,
16*ccaec48aSDavid du Colombier RBC2 = 1<<3,
17*ccaec48aSDavid du Colombier RBlatchstatus = 1<<4,
18*ccaec48aSDavid du Colombier RBlatchcount = 1<<5,
19*ccaec48aSDavid du Colombier
20*ccaec48aSDavid du Colombier AMlatchcount = 0,
21*ccaec48aSDavid du Colombier AMloonly,
22*ccaec48aSDavid du Colombier AMhionly,
23*ccaec48aSDavid du Colombier AMlohi,
24*ccaec48aSDavid du Colombier
25*ccaec48aSDavid du Colombier OM0 = 0,
26*ccaec48aSDavid du Colombier OM1,
27*ccaec48aSDavid du Colombier OM2,
28*ccaec48aSDavid du Colombier OM3,
29*ccaec48aSDavid du Colombier OM4,
30*ccaec48aSDavid du Colombier OM5,
31*ccaec48aSDavid du Colombier OM2b,
32*ccaec48aSDavid du Colombier OM3b,
33*ccaec48aSDavid du Colombier };
34*ccaec48aSDavid du Colombier
35*ccaec48aSDavid du Colombier static void
latchstatus(Pit * ch)36*ccaec48aSDavid du Colombier latchstatus(Pit *ch)
37*ccaec48aSDavid du Colombier {
38*ccaec48aSDavid du Colombier if(ch->rlatched)
39*ccaec48aSDavid du Colombier return;
40*ccaec48aSDavid du Colombier ch->rlatch[0] = ch->bcd | ch->omode<<1 | ch->amode<<4 | ch->count0<<6 | ch->out<<7;
41*ccaec48aSDavid du Colombier ch->rcount = 0;
42*ccaec48aSDavid du Colombier ch->rlatched = 1;
43*ccaec48aSDavid du Colombier }
44*ccaec48aSDavid du Colombier
45*ccaec48aSDavid du Colombier static void
latchcount(Pit * ch)46*ccaec48aSDavid du Colombier latchcount(Pit *ch)
47*ccaec48aSDavid du Colombier {
48*ccaec48aSDavid du Colombier ulong w;
49*ccaec48aSDavid du Colombier
50*ccaec48aSDavid du Colombier if(ch->rlatched)
51*ccaec48aSDavid du Colombier return;
52*ccaec48aSDavid du Colombier w = ch->count & 0xFFFF;
53*ccaec48aSDavid du Colombier if(ch->bcd)
54*ccaec48aSDavid du Colombier w = (w % 10) + ((w/10) % 10)<<4 + ((w/100) % 10)<<8 + ((w/1000) % 10)<<12;
55*ccaec48aSDavid du Colombier ch->rlatch[0] = w & 0xFF;
56*ccaec48aSDavid du Colombier ch->rlatch[1] = (w >> 8) & 0xFF;
57*ccaec48aSDavid du Colombier ch->rcount = 0;
58*ccaec48aSDavid du Colombier ch->rlatched = 1;
59*ccaec48aSDavid du Colombier switch(ch->amode){
60*ccaec48aSDavid du Colombier case AMhionly:
61*ccaec48aSDavid du Colombier ch->rcount++;
62*ccaec48aSDavid du Colombier break;
63*ccaec48aSDavid du Colombier case AMlohi:
64*ccaec48aSDavid du Colombier ch->rlatched++;
65*ccaec48aSDavid du Colombier break;
66*ccaec48aSDavid du Colombier }
67*ccaec48aSDavid du Colombier }
68*ccaec48aSDavid du Colombier
69*ccaec48aSDavid du Colombier static void
setcount(Pit * ch)70*ccaec48aSDavid du Colombier setcount(Pit *ch)
71*ccaec48aSDavid du Colombier {
72*ccaec48aSDavid du Colombier ulong w;
73*ccaec48aSDavid du Colombier
74*ccaec48aSDavid du Colombier w = (ulong)ch->wlatch[0] | (ulong)ch->wlatch[1] << 8;
75*ccaec48aSDavid du Colombier if(ch->bcd)
76*ccaec48aSDavid du Colombier w = (w & 0xF) + 10*((w >> 4)&0xF) + 100*((w >> 8)&0xF) + 1000*((w >> 12)&0xF);
77*ccaec48aSDavid du Colombier ch->count = w;
78*ccaec48aSDavid du Colombier ch->count0 = 0;
79*ccaec48aSDavid du Colombier }
80*ccaec48aSDavid du Colombier
81*ccaec48aSDavid du Colombier static int
deccount(Pit * ch,vlong * cycles)82*ccaec48aSDavid du Colombier deccount(Pit *ch, vlong *cycles)
83*ccaec48aSDavid du Colombier {
84*ccaec48aSDavid du Colombier if(ch->count0){
85*ccaec48aSDavid du Colombier *cycles = 0;
86*ccaec48aSDavid du Colombier return 0;
87*ccaec48aSDavid du Colombier } else {
88*ccaec48aSDavid du Colombier vlong passed, remain;
89*ccaec48aSDavid du Colombier
90*ccaec48aSDavid du Colombier passed = *cycles;
91*ccaec48aSDavid du Colombier if(ch->count == 0){
92*ccaec48aSDavid du Colombier ch->count = ch->bcd ? 9999 : 0xFFFF;
93*ccaec48aSDavid du Colombier passed--;
94*ccaec48aSDavid du Colombier }
95*ccaec48aSDavid du Colombier if(passed <= ch->count){
96*ccaec48aSDavid du Colombier remain = 0;
97*ccaec48aSDavid du Colombier ch->count -= passed;
98*ccaec48aSDavid du Colombier } else {
99*ccaec48aSDavid du Colombier remain = passed - ch->count;
100*ccaec48aSDavid du Colombier ch->count = 0;
101*ccaec48aSDavid du Colombier }
102*ccaec48aSDavid du Colombier *cycles = remain;
103*ccaec48aSDavid du Colombier return ch->count == 0;
104*ccaec48aSDavid du Colombier }
105*ccaec48aSDavid du Colombier }
106*ccaec48aSDavid du Colombier
107*ccaec48aSDavid du Colombier void
setgate(Pit * ch,uchar gate)108*ccaec48aSDavid du Colombier setgate(Pit *ch, uchar gate)
109*ccaec48aSDavid du Colombier {
110*ccaec48aSDavid du Colombier if(ch->gate == 0 && gate)
111*ccaec48aSDavid du Colombier ch->gateraised = 1;
112*ccaec48aSDavid du Colombier ch->gate = gate;
113*ccaec48aSDavid du Colombier }
114*ccaec48aSDavid du Colombier
115*ccaec48aSDavid du Colombier static void
clockpit1(Pit * ch,vlong * cycles)116*ccaec48aSDavid du Colombier clockpit1(Pit *ch, vlong *cycles)
117*ccaec48aSDavid du Colombier {
118*ccaec48aSDavid du Colombier switch(ch->omode){
119*ccaec48aSDavid du Colombier case OM0: /* Interrupt On Terminal Count */
120*ccaec48aSDavid du Colombier if(ch->count0){
121*ccaec48aSDavid du Colombier setcount(ch);
122*ccaec48aSDavid du Colombier ch->out = 0;
123*ccaec48aSDavid du Colombier Next:
124*ccaec48aSDavid du Colombier --*cycles;
125*ccaec48aSDavid du Colombier return;
126*ccaec48aSDavid du Colombier }
127*ccaec48aSDavid du Colombier if(ch->gate && deccount(ch, cycles)){
128*ccaec48aSDavid du Colombier ch->out = 1;
129*ccaec48aSDavid du Colombier return;
130*ccaec48aSDavid du Colombier }
131*ccaec48aSDavid du Colombier break;
132*ccaec48aSDavid du Colombier
133*ccaec48aSDavid du Colombier case OM1: /* Hardware Re-triggerable One-shot */
134*ccaec48aSDavid du Colombier if(ch->gateraised){
135*ccaec48aSDavid du Colombier ch->gateraised = 0;
136*ccaec48aSDavid du Colombier setcount(ch);
137*ccaec48aSDavid du Colombier ch->out = 0;
138*ccaec48aSDavid du Colombier goto Next;
139*ccaec48aSDavid du Colombier }
140*ccaec48aSDavid du Colombier if(deccount(ch, cycles) && ch->out == 0){
141*ccaec48aSDavid du Colombier ch->out = 1;
142*ccaec48aSDavid du Colombier return;
143*ccaec48aSDavid du Colombier }
144*ccaec48aSDavid du Colombier break;
145*ccaec48aSDavid du Colombier
146*ccaec48aSDavid du Colombier case OM2: /* Rate Generator */
147*ccaec48aSDavid du Colombier case OM2b:
148*ccaec48aSDavid du Colombier ch->out = 1;
149*ccaec48aSDavid du Colombier if(ch->count0){
150*ccaec48aSDavid du Colombier setcount(ch);
151*ccaec48aSDavid du Colombier goto Next;
152*ccaec48aSDavid du Colombier }
153*ccaec48aSDavid du Colombier if(ch->gate == 0)
154*ccaec48aSDavid du Colombier break;
155*ccaec48aSDavid du Colombier if(ch->gateraised){
156*ccaec48aSDavid du Colombier ch->gateraised = 0;
157*ccaec48aSDavid du Colombier setcount(ch);
158*ccaec48aSDavid du Colombier goto Next;
159*ccaec48aSDavid du Colombier }
160*ccaec48aSDavid du Colombier if(deccount(ch, cycles)){
161*ccaec48aSDavid du Colombier setcount(ch);
162*ccaec48aSDavid du Colombier ch->out = 0;
163*ccaec48aSDavid du Colombier return;
164*ccaec48aSDavid du Colombier }
165*ccaec48aSDavid du Colombier break;
166*ccaec48aSDavid du Colombier
167*ccaec48aSDavid du Colombier case OM3: /* Square Wave Generator */
168*ccaec48aSDavid du Colombier case OM3b:
169*ccaec48aSDavid du Colombier if(ch->count0){
170*ccaec48aSDavid du Colombier setcount(ch);
171*ccaec48aSDavid du Colombier goto Next;
172*ccaec48aSDavid du Colombier }
173*ccaec48aSDavid du Colombier if(ch->gate == 0)
174*ccaec48aSDavid du Colombier break;
175*ccaec48aSDavid du Colombier if(ch->gateraised){
176*ccaec48aSDavid du Colombier ch->gateraised = 0;
177*ccaec48aSDavid du Colombier setcount(ch);
178*ccaec48aSDavid du Colombier goto Next;
179*ccaec48aSDavid du Colombier }
180*ccaec48aSDavid du Colombier if(deccount(ch, cycles)){
181*ccaec48aSDavid du Colombier setcount(ch);
182*ccaec48aSDavid du Colombier ch->out ^= 1;
183*ccaec48aSDavid du Colombier return;
184*ccaec48aSDavid du Colombier }
185*ccaec48aSDavid du Colombier break;
186*ccaec48aSDavid du Colombier
187*ccaec48aSDavid du Colombier case OM4: /* Software Triggered Strobe */
188*ccaec48aSDavid du Colombier ch->out = 1;
189*ccaec48aSDavid du Colombier if(ch->count0){
190*ccaec48aSDavid du Colombier setcount(ch);
191*ccaec48aSDavid du Colombier goto Next;
192*ccaec48aSDavid du Colombier }
193*ccaec48aSDavid du Colombier if(ch->gate && deccount(ch, cycles)){
194*ccaec48aSDavid du Colombier ch->out = 0;
195*ccaec48aSDavid du Colombier return;
196*ccaec48aSDavid du Colombier }
197*ccaec48aSDavid du Colombier break;
198*ccaec48aSDavid du Colombier
199*ccaec48aSDavid du Colombier case OM5: /* Hardware Triggered Strobe */
200*ccaec48aSDavid du Colombier ch->out = 1;
201*ccaec48aSDavid du Colombier if(ch->gateraised){
202*ccaec48aSDavid du Colombier ch->gateraised = 0;
203*ccaec48aSDavid du Colombier setcount(ch);
204*ccaec48aSDavid du Colombier goto Next;
205*ccaec48aSDavid du Colombier }
206*ccaec48aSDavid du Colombier if(deccount(ch, cycles)){
207*ccaec48aSDavid du Colombier ch->out = 0;
208*ccaec48aSDavid du Colombier return;
209*ccaec48aSDavid du Colombier }
210*ccaec48aSDavid du Colombier break;
211*ccaec48aSDavid du Colombier }
212*ccaec48aSDavid du Colombier *cycles = 0;
213*ccaec48aSDavid du Colombier }
214*ccaec48aSDavid du Colombier
215*ccaec48aSDavid du Colombier void
clockpit(Pit * pit,vlong cycles)216*ccaec48aSDavid du Colombier clockpit(Pit *pit, vlong cycles)
217*ccaec48aSDavid du Colombier {
218*ccaec48aSDavid du Colombier Pit *ch;
219*ccaec48aSDavid du Colombier int i;
220*ccaec48aSDavid du Colombier
221*ccaec48aSDavid du Colombier if(cycles <= 0)
222*ccaec48aSDavid du Colombier return;
223*ccaec48aSDavid du Colombier for(i = 0; i<Actl; i++){
224*ccaec48aSDavid du Colombier ch = pit + i;
225*ccaec48aSDavid du Colombier if(ch->wlatched){
226*ccaec48aSDavid du Colombier vlong c;
227*ccaec48aSDavid du Colombier
228*ccaec48aSDavid du Colombier switch(ch->omode){
229*ccaec48aSDavid du Colombier case OM3:
230*ccaec48aSDavid du Colombier case OM3b:
231*ccaec48aSDavid du Colombier c = cycles * 2;
232*ccaec48aSDavid du Colombier break;
233*ccaec48aSDavid du Colombier default:
234*ccaec48aSDavid du Colombier c = cycles;
235*ccaec48aSDavid du Colombier }
236*ccaec48aSDavid du Colombier while(c > 0)
237*ccaec48aSDavid du Colombier clockpit1(ch, &c);
238*ccaec48aSDavid du Colombier }
239*ccaec48aSDavid du Colombier ch->gateraised = 0;
240*ccaec48aSDavid du Colombier }
241*ccaec48aSDavid du Colombier }
242*ccaec48aSDavid du Colombier
243*ccaec48aSDavid du Colombier uchar
rpit(Pit * pit,uchar addr)244*ccaec48aSDavid du Colombier rpit(Pit *pit, uchar addr)
245*ccaec48aSDavid du Colombier {
246*ccaec48aSDavid du Colombier Pit *ch;
247*ccaec48aSDavid du Colombier uchar data;
248*ccaec48aSDavid du Colombier
249*ccaec48aSDavid du Colombier if(addr >= Actl)
250*ccaec48aSDavid du Colombier return 0;
251*ccaec48aSDavid du Colombier ch = pit + addr;
252*ccaec48aSDavid du Colombier if(ch->rlatched){
253*ccaec48aSDavid du Colombier data = ch->rlatch[ch->rcount & 1];
254*ccaec48aSDavid du Colombier ch->rlatched--;
255*ccaec48aSDavid du Colombier } else {
256*ccaec48aSDavid du Colombier data = 0;
257*ccaec48aSDavid du Colombier switch(ch->amode){
258*ccaec48aSDavid du Colombier case AMloonly:
259*ccaec48aSDavid du Colombier data = ch->count & 0xFF;
260*ccaec48aSDavid du Colombier break;
261*ccaec48aSDavid du Colombier case AMhionly:
262*ccaec48aSDavid du Colombier data = (ch->count >> 8) & 0xFF;
263*ccaec48aSDavid du Colombier break;
264*ccaec48aSDavid du Colombier case AMlohi:
265*ccaec48aSDavid du Colombier data = (ch->count >> ((ch->rcount & 1)<<3)) & 0xFF;
266*ccaec48aSDavid du Colombier break;
267*ccaec48aSDavid du Colombier }
268*ccaec48aSDavid du Colombier }
269*ccaec48aSDavid du Colombier ch->rcount++;
270*ccaec48aSDavid du Colombier if(0) fprint(2, "rpit %p: %.2x %.2x\n", pit, (int)addr, (int)data);
271*ccaec48aSDavid du Colombier return data;
272*ccaec48aSDavid du Colombier }
273*ccaec48aSDavid du Colombier
274*ccaec48aSDavid du Colombier void
wpit(Pit * pit,uchar addr,uchar data)275*ccaec48aSDavid du Colombier wpit(Pit *pit, uchar addr, uchar data)
276*ccaec48aSDavid du Colombier {
277*ccaec48aSDavid du Colombier Pit *ch;
278*ccaec48aSDavid du Colombier
279*ccaec48aSDavid du Colombier if(0) fprint(2, "wpit %p: %.2x %.2x\n", pit, (int)addr, (int)data);
280*ccaec48aSDavid du Colombier if(addr > Actl)
281*ccaec48aSDavid du Colombier return;
282*ccaec48aSDavid du Colombier if(addr == Actl){
283*ccaec48aSDavid du Colombier uchar sc, amode, omode, bcd;
284*ccaec48aSDavid du Colombier
285*ccaec48aSDavid du Colombier bcd = (data & 1);
286*ccaec48aSDavid du Colombier omode = (data >> 1) & 7;
287*ccaec48aSDavid du Colombier amode = (data >> 4) & 3;
288*ccaec48aSDavid du Colombier sc = (data >> 6) & 3;
289*ccaec48aSDavid du Colombier
290*ccaec48aSDavid du Colombier if(sc == Readback){
291*ccaec48aSDavid du Colombier ch = nil;
292*ccaec48aSDavid du Colombier for(;;){
293*ccaec48aSDavid du Colombier if(data & RBC0){
294*ccaec48aSDavid du Colombier ch = pit;
295*ccaec48aSDavid du Colombier break;
296*ccaec48aSDavid du Colombier }
297*ccaec48aSDavid du Colombier if(data & RBC1){
298*ccaec48aSDavid du Colombier ch = pit + 1;
299*ccaec48aSDavid du Colombier break;
300*ccaec48aSDavid du Colombier }
301*ccaec48aSDavid du Colombier if(data & RBC2){
302*ccaec48aSDavid du Colombier ch = pit + 2;
303*ccaec48aSDavid du Colombier break;
304*ccaec48aSDavid du Colombier }
305*ccaec48aSDavid du Colombier break;
306*ccaec48aSDavid du Colombier }
307*ccaec48aSDavid du Colombier if(ch == nil)
308*ccaec48aSDavid du Colombier return;
309*ccaec48aSDavid du Colombier if((data & RBlatchcount) == 0)
310*ccaec48aSDavid du Colombier latchcount(ch);
311*ccaec48aSDavid du Colombier if((data & RBlatchstatus) == 0)
312*ccaec48aSDavid du Colombier latchstatus(ch);
313*ccaec48aSDavid du Colombier return;
314*ccaec48aSDavid du Colombier }
315*ccaec48aSDavid du Colombier
316*ccaec48aSDavid du Colombier ch = pit + sc;
317*ccaec48aSDavid du Colombier if(amode == AMlatchcount){
318*ccaec48aSDavid du Colombier latchcount(ch);
319*ccaec48aSDavid du Colombier return;
320*ccaec48aSDavid du Colombier }
321*ccaec48aSDavid du Colombier ch->bcd = bcd;
322*ccaec48aSDavid du Colombier
323*ccaec48aSDavid du Colombier ch->amode = amode;
324*ccaec48aSDavid du Colombier ch->omode = omode;
325*ccaec48aSDavid du Colombier
326*ccaec48aSDavid du Colombier ch->rlatched = 0;
327*ccaec48aSDavid du Colombier ch->rcount = 0;
328*ccaec48aSDavid du Colombier ch->rlatch[0] = 0;
329*ccaec48aSDavid du Colombier ch->rlatch[1] = 0;
330*ccaec48aSDavid du Colombier
331*ccaec48aSDavid du Colombier ch->wlatched = 0;
332*ccaec48aSDavid du Colombier ch->wcount = 0;
333*ccaec48aSDavid du Colombier ch->wlatch[0] = 0;
334*ccaec48aSDavid du Colombier ch->wlatch[1] = 0;
335*ccaec48aSDavid du Colombier
336*ccaec48aSDavid du Colombier ch->count0 = 1;
337*ccaec48aSDavid du Colombier ch->out = !!omode;
338*ccaec48aSDavid du Colombier return;
339*ccaec48aSDavid du Colombier }
340*ccaec48aSDavid du Colombier
341*ccaec48aSDavid du Colombier ch = pit + addr;
342*ccaec48aSDavid du Colombier switch(ch->amode){
343*ccaec48aSDavid du Colombier case AMloonly:
344*ccaec48aSDavid du Colombier case AMhionly:
345*ccaec48aSDavid du Colombier ch->wlatch[ch->amode - AMloonly] = data;
346*ccaec48aSDavid du Colombier ch->wcount++;
347*ccaec48aSDavid du Colombier break;
348*ccaec48aSDavid du Colombier case AMlohi:
349*ccaec48aSDavid du Colombier ch->wlatch[ch->wcount++ & 1] = data;
350*ccaec48aSDavid du Colombier if(ch->wcount < 2)
351*ccaec48aSDavid du Colombier return;
352*ccaec48aSDavid du Colombier break;
353*ccaec48aSDavid du Colombier }
354*ccaec48aSDavid du Colombier ch->wlatched = ch->wcount;
355*ccaec48aSDavid du Colombier ch->wcount = 0;
356*ccaec48aSDavid du Colombier ch->count0 = 1;
357*ccaec48aSDavid du Colombier }
358