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