xref: /plan9-contrib/sys/src/cmd/aux/realemu/pit.c (revision ccaec48a6a7d481d90233fb80c88e608b0a02604)
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