PCem

view src/pit.c @ 165:0710d7cb935f

Silence PC speaker output at very high frequencies - fixes Lemmings and other games that use high frequency as "speaker off".
author TomW
date Sun Sep 28 11:33:08 2014 +0100
parents 912e602b3406
children
line source
1 /*IBM AT -
2 Write B0
3 Write aa55
4 Expects aa55 back*/
6 #include <string.h>
7 #include "ibm.h"
9 #include "cpu.h"
10 #include "dma.h"
11 #include "io.h"
12 #include "pic.h"
13 #include "pit.h"
14 #include "timer.h"
15 #include "video.h"
17 /*B0 to 40, two writes to 43, then two reads - value does not change!*/
18 /*B4 to 40, two writes to 43, then two reads - value _does_ change!*/
19 //Tyrian writes 4300 or 17512
20 int displine;
22 double PITCONST;
23 float cpuclock;
24 float isa_timing, bus_timing;
26 int firsttime=1;
27 void setpitclock(float clock)
28 {
29 // printf("PIT clock %f\n",clock);
30 cpuclock=clock;
31 PITCONST=clock/1193182.0;
32 CGACONST=(clock/(19687503.0/11.0));
33 MDACONST=(clock/2032125.0);
34 VGACONST1=(clock/25175000.0);
35 VGACONST2=(clock/28322000.0);
36 isa_timing = clock/8000000.0;
37 bus_timing = clock/(double)cpu_busspeed;
38 video_updatetiming();
39 // pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock);
40 /* if (video_recalctimings)
41 video_recalctimings();*/
42 RTCCONST=clock/32768.0;
43 TIMER_USEC = (int)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT));
44 device_speed_changed();
45 }
47 //#define PITCONST (8000000.0/1193000.0)
48 //#define PITCONST (cpuclock/1193000.0)
49 void pit_reset()
50 {
51 memset(&pit,0,sizeof(PIT));
52 pit.l[0]=0xFFFF; pit.c[0]=0xFFFF*PITCONST;
53 pit.l[1]=0xFFFF; pit.c[1]=0xFFFF*PITCONST;
54 pit.l[2]=0xFFFF; pit.c[2]=0xFFFF*PITCONST;
55 pit.m[0]=pit.m[1]=pit.m[2]=0;
56 pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0;
57 pit.thit[0]=1;
58 spkstat=0;
59 pit.gate[0] = pit.gate[1] = 1;
60 pit.gate[2] = 0;
61 pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1;
62 }
64 void clearpit()
65 {
66 pit.c[0]=(pit.l[0]<<2);
67 }
69 float pit_timer0_freq()
70 {
71 if (pit.l[0])
72 return 1193182.0f/(float)pit.l[0];
73 else
74 return 1193182.0f/(float)0x10000;
75 }
77 static void (*pit_set_out_funcs[3])(int new_out, int old_out);
79 static void pit_set_out(int t, int out)
80 {
81 pit_set_out_funcs[t](out, pit.out[t]);
82 pit.out[t] = out;
83 }
85 static void pit_load(int t)
86 {
87 int l = pit.l[t] ? pit.l[t] : 0x10000;
88 timer_process();
89 pit.newcount[t] = 0;
90 // pclog("pit_load: t=%i l=%x\n", t, l);
91 switch (pit.m[t])
92 {
93 case 0: /*Interrupt on terminal count*/
94 pit.count[t] = l;
95 pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST);
96 pit_set_out(t, 0);
97 pit.thit[t] = 0;
98 pit.enabled[t] = pit.gate[t];
99 break;
100 case 1: /*Hardware retriggerable one-shot*/
101 pit.enabled[t] = 1;
102 break;
103 case 2: /*Rate generator*/
104 if (pit.initial[t])
105 {
106 pit.count[t] = l - 1;
107 pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST);
108 pit_set_out(t, 1);
109 pit.thit[t] = 0;
110 }
111 pit.enabled[t] = pit.gate[t];
112 break;
113 case 3: /*Square wave mode*/
114 if (pit.initial[t])
115 {
116 pit.count[t] = l;
117 pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST);
118 pit_set_out(t, 1);
119 pit.thit[t] = 0;
120 }
121 pit.enabled[t] = pit.gate[t];
122 // pclog("pit_load: square wave mode c=%x\n", pit.c[t]);
123 break;
124 case 4: /*Software triggered stobe*/
125 if (!pit.thit[t] && !pit.initial[t])
126 pit.newcount[t] = 1;
127 else
128 {
129 pit.count[t] = l;
130 pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST);
131 pit_set_out(t, 0);
132 pit.thit[t] = 0;
133 }
134 pit.enabled[t] = pit.gate[t];
135 break;
136 case 5: /*Hardware triggered stobe*/
137 pit.enabled[t] = 1;
138 break;
139 }
140 pit.initial[t] = 0;
141 pit.running[t] = pit.enabled[t] && pit.using_timer[t];
142 timer_update_outstanding();
143 // pclog("pit_load: t=%i running=%i thit=%i enabled=%i m=%i l=%x c=%g gate=%i\n", t, pit.running[t], pit.thit[t], pit.enabled[t], pit.m[t], pit.l[t], pit.c[t], pit.gate[t]);
144 }
146 void pit_set_gate(int t, int gate)
147 {
148 int l = pit.l[t] ? pit.l[t] : 0x10000;
149 timer_process();
150 switch (pit.m[t])
151 {
152 case 0: /*Interrupt on terminal count*/
153 case 4: /*Software triggered stobe*/
154 pit.enabled[t] = gate;
155 break;
156 case 1: /*Hardware retriggerable one-shot*/
157 case 5: /*Hardware triggered stobe*/
158 if (gate && !pit.gate[t])
159 {
160 pit.count[t] = l;
161 pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST);
162 pit_set_out(t, 0);
163 pit.thit[t] = 0;
164 pit.enabled[t] = 1;
165 }
166 break;
167 case 2: /*Rate generator*/
168 if (gate && !pit.gate[t])
169 {
170 pit.count[t] = l - 1;
171 pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST);
172 pit_set_out(t, 1);
173 pit.thit[t] = 0;
174 }
175 pit.enabled[t] = gate;
176 break;
177 case 3: /*Square wave mode*/
178 if (gate && !pit.gate[t])
179 {
180 pit.count[t] = l;
181 pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST);
182 pit_set_out(t, 1);
183 pit.thit[t] = 0;
184 }
185 pit.enabled[t] = gate;
186 break;
187 }
188 pit.gate[t] = gate;
189 pit.running[t] = pit.enabled[t] && pit.using_timer[t];
190 timer_update_outstanding();
191 // pclog("pit_set_gate: t=%i gate=%i\n", t, gate);
192 }
194 static void pit_over(int t)
195 {
196 int l = pit.l[t] ? pit.l[t] : 0x10000;
197 // if (!t) pclog("pit_over: t=%i l=%x c=%x %i\n", t, pit.l[t], pit.c[t], pit.c[t] >> TIMER_SHIFT);
198 switch (pit.m[t])
199 {
200 case 0: /*Interrupt on terminal count*/
201 case 1: /*Hardware retriggerable one-shot*/
202 if (!pit.thit[t])
203 pit_set_out(t, 1);
204 pit.thit[t] = 1;
205 pit.count[t] += 0xffff;
206 pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST);
207 break;
208 case 2: /*Rate generator*/
209 pit.count[t] += l;
210 pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST);
211 pit_set_out(t, 0);
212 pit_set_out(t, 1);
213 break;
214 case 3: /*Square wave mode*/
215 if (pit.out[t])
216 {
217 pit_set_out(t, 0);
218 pit.count[t] += (l >> 1);
219 pit.c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST);
220 }
221 else
222 {
223 pit_set_out(t, 1);
224 pit.count[t] += ((l + 1) >> 1);
225 pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST);
226 }
227 // if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST);
228 break;
229 case 4: /*Software triggered strove*/
230 if (!pit.thit[t])
231 {
232 pit_set_out(t, 0);
233 pit_set_out(t, 1);
234 }
235 if (pit.newcount[t])
236 {
237 pit.newcount[t] = 0;
238 pit.count[t] += l;
239 pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST);
240 }
241 else
242 {
243 pit.thit[t] = 1;
244 pit.count[t] += 0xffff;
245 pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST);
246 }
247 break;
248 case 5: /*Hardware triggered strove*/
249 if (!pit.thit[t])
250 {
251 pit_set_out(t, 0);
252 pit_set_out(t, 1);
253 }
254 pit.thit[t] = 1;
255 break;
256 }
257 pit.running[t] = pit.enabled[t] && pit.using_timer[t];
258 }
260 static int pit_read_timer(int t)
261 {
262 timer_clock();
263 // pclog("pit_read_timer: t=%i using_timer=%i m=%i\n", t, pit.using_timer[t], pit.m[t]);
264 if (pit.using_timer[t])
265 {
266 int read = (int)((pit.c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT;
267 if (pit.m[t] == 2)
268 read++;
269 if (read < 0)
270 read = 0;
271 if (read > 0x10000)
272 read = 0x10000;
273 if (pit.m[t] == 3)
274 read <<= 1;
275 return read;
276 }
277 if (pit.m[t] == 2)
278 return pit.count[t] + 1;
279 return pit.count[t];
280 }
282 extern int ins;
283 void pit_write(uint16_t addr, uint8_t val, void *priv)
284 {
285 int t;
286 cycles -= (int)PITCONST;
287 // /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins, pit.gate[0]);
289 switch (addr&3)
290 {
291 case 3: /*CTRL*/
292 if ((val&0xC0)==0xC0)
293 {
294 if (!(val&0x20))
295 {
296 if (val & 2)
297 pit.rl[0] = pit.using_timer[0] ? ((int)(pit.c[0] / PITCONST) >> TIMER_SHIFT) : pit.count[0];
298 if (val & 4)
299 pit.rl[1] = pit.using_timer[1] ? ((int)(pit.c[1] / PITCONST) >> TIMER_SHIFT) : pit.count[1];
300 if (val & 8)
301 pit.rl[2] = pit.using_timer[2] ? ((int)(pit.c[2] / PITCONST) >> TIMER_SHIFT) : pit.count[2];
302 }
303 return;
304 }
305 t = val >> 6;
306 pit.ctrls[val>>6]=pit.ctrl=val;
307 if ((val>>7)==3)
308 {
309 printf("Bad PIT reg select\n");
310 return;
311 // dumpregs();
312 // exit(-1);
313 }
314 // printf("CTRL write %02X\n",val);
315 if (!(pit.ctrl&0x30))
316 {
317 pit.rl[t] = pit_read_timer(t);
318 // pclog("Timer latch %f %04X %04X\n",pit.c[0],pit.rl[0],pit.l[0]);
319 pit.ctrl |= 0x30;
320 pit.rereadlatch[t] = 0;
321 pit.rm[t] = 3;
322 }
323 else
324 {
325 pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3;
326 pit.m[val>>6]=(val>>1)&7;
327 if (pit.m[val>>6]>5)
328 pit.m[val>>6]&=3;
329 if (!(pit.rm[val>>6]))
330 {
331 pit.rm[val>>6]=3;
332 pit.rl[t] = pit_read_timer(t);
333 }
334 pit.rereadlatch[val>>6]=1;
335 if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1;
336 pit.initial[t] = 1;
337 // pclog("ppispeakon %i\n",ppispeakon);
338 }
339 pit.wp=0;
340 pit.thit[pit.ctrl>>6]=0;
341 break;
342 case 0: case 1: case 2: /*Timers*/
343 t=addr&3;
344 // if (t==2) ppispeakon=speakon=0;
345 // pclog("Write timer %02X %i\n",pit.ctrls[t],pit.wm[t]);
346 switch (pit.wm[t])
347 {
348 case 1:
349 pit.l[t]=val;
350 // pit.thit[t]=0;
351 pit_load(t);
352 // pit.c[t]=pit.l[t]*PITCONST;
353 // if (!t)
354 // picintc(1);
355 break;
356 case 2:
357 pit.l[t]=(val<<8);
358 // pit.thit[t]=0;
359 pit_load(t);
360 // pit.c[t]=pit.l[t]*PITCONST;
361 // if (!t)
362 // picintc(1);
363 break;
364 case 0:
365 pit.l[t]&=0xFF;
366 pit.l[t]|=(val<<8);
367 pit_load(t);
368 // pit.c[t]=pit.l[t]*PITCONST;
369 // pclog("%04X %f\n",pit.l[t],pit.c[t]);
370 // pit.thit[t]=0;
371 pit.wm[t]=3;
372 // if (!t)
373 // picintc(1);
374 break;
375 case 3:
376 pit.l[t]&=0xFF00;
377 pit.l[t]|=val;
378 pit.wm[t]=0;
379 break;
380 }
381 speakval=(((float)pit.l[2]/(float)pit.l[0])*0x4000)-0x2000;
382 // printf("Speakval now %i\n",speakval);
383 // if (speakval>0x2000)
384 // printf("Speaker overflow - %i %i %04X %04X\n",pit.l[0],pit.l[2],pit.l[0],pit.l[2]);
385 if (speakval>0x2000) speakval=0x2000;
386 /* if (!pit.l[t])
387 {
388 pit.l[t]|=0x10000;
389 pit.c[t]=pit.l[t]*PITCONST;
390 }*/
391 break;
392 }
393 }
395 uint8_t pit_read(uint16_t addr, void *priv)
396 {
397 int t;
398 uint8_t temp;
399 cycles -= (int)PITCONST;
400 // printf("Read PIT %04X ",addr);
401 switch (addr&3)
402 {
403 case 0: case 1: case 2: /*Timers*/
404 t = addr & 3;
405 if (pit.rereadlatch[addr & 3])
406 {
407 pit.rereadlatch[addr & 3] = 0;
408 pit.rl[t] = pit_read_timer(t);
409 }
410 switch (pit.rm[addr & 3])
411 {
412 case 0:
413 temp = pit.rl[addr & 3] >> 8;
414 pit.rm[addr & 3] = 3;
415 pit.rereadlatch[addr & 3] = 1;
416 break;
417 case 1:
418 temp = (pit.rl[addr & 3]) & 0xFF;
419 pit.rereadlatch[addr & 3] = 1;
420 break;
421 case 2:
422 temp = (pit.rl[addr & 3]) >> 8;
423 pit.rereadlatch[addr & 3] = 1;
424 break;
425 case 3:
426 temp = (pit.rl[addr & 3]) & 0xFF;
427 if (pit.m[addr & 3] & 0x80)
428 pit.m[addr & 3] &= 7;
429 else
430 pit.rm[addr & 3] = 0;
431 break;
432 }
433 break;
434 case 3: /*Control*/
435 temp = pit.ctrl;
436 break;
437 }
438 // pclog("%02X\n", temp);
439 // printf("%02X %i %i %04X:%04X %i\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc, ins);
440 return temp;
441 }
443 void pit_poll()
444 {
445 // printf("Poll pit %f %f %f\n",pit.c[0],pit.c[1],pit.c[2]);
446 if (pit.c[0] < 1 && pit.running[0])
447 pit_over(0);
448 if (pit.c[1] < 1 && pit.running[1])
449 pit_over(1);
450 if (pit.c[2] < 1 && pit.running[2])
451 pit_over(2);
452 }
454 void pit_timer_over(void *p)
455 {
456 int timer = (int) p;
457 // pclog("pit_timer_over %i\n", timer);
459 pit_over(timer);
460 }
462 void pit_clock(int t)
463 {
464 if (pit.thit[t] || !pit.enabled[t])
465 return;
467 if (pit.using_timer[t])
468 return;
470 pit.count[t] -= (pit.m[t] == 3) ? 2 : 1;
471 if (!pit.count[t])
472 pit_over(t);
473 }
475 void pit_set_using_timer(int t, int using_timer)
476 {
477 // pclog("pit_set_using_timer: t=%i using_timer=%i\n", t, using_timer);
478 timer_process();
479 if (pit.using_timer[t] && !using_timer)
480 pit.count[t] = pit_read_timer(t);
481 if (!pit.using_timer[t] && using_timer)
482 pit.c[t] = (int)((pit.count[t] << TIMER_SHIFT) * PITCONST);
483 pit.using_timer[t] = using_timer;
484 pit.running[t] = pit.enabled[t] && pit.using_timer[t];
485 timer_update_outstanding();
486 }
488 void pit_set_out_func(int t, void (*func)(int new_out, int old_out))
489 {
490 pit_set_out_funcs[t] = func;
491 }
493 void pit_null_timer(int new_out, int old_out)
494 {
495 }
497 void pit_irq0_timer(int new_out, int old_out)
498 {
499 if (new_out && !old_out)
500 picint(1);
501 if (!new_out)
502 picintc(1);
503 }
505 void pit_irq0_timer_pcjr(int new_out, int old_out)
506 {
507 if (new_out && !old_out)
508 {
509 picint(1);
510 pit_clock(1);
511 }
512 if (!new_out)
513 picintc(1);
514 }
516 void pit_refresh_timer_xt(int new_out, int old_out)
517 {
518 if (new_out && !old_out)
519 dma_channel_read(0);
520 }
522 void pit_refresh_timer_at(int new_out, int old_out)
523 {
524 if (new_out && !old_out)
525 ppi.pb ^= 0x10;
526 }
528 void pit_speaker_timer(int new_out, int old_out)
529 {
530 int l = pit.l[2] ? pit.l[2] : 0x10000;
531 if (l < 25)
532 speakon = 0;
533 else
534 speakon = new_out;
535 ppispeakon = new_out;
536 }
539 void pit_init()
540 {
541 io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, NULL);
542 pit.gate[0] = pit.gate[1] = 1;
543 pit.gate[2] = 0;
544 pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1;
546 timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)0);
547 timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)1);
548 timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)2);
550 pit_set_out_func(0, pit_irq0_timer);
551 pit_set_out_func(1, pit_null_timer);
552 pit_set_out_func(2, pit_speaker_timer);
553 }