1 /*
2  *  Copyright (C) 2002-2021  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 
20 #include <math.h>
21 #include "dosbox.h"
22 #include "inout.h"
23 #include "pic.h"
24 #include "mem.h"
25 #include "mixer.h"
26 #include "timer.h"
27 #include "setup.h"
28 #include "support.h"
29 
30 const std::chrono::steady_clock::time_point system_start_time = std::chrono::steady_clock::now();
31 
BIN2BCD(Bit16u & val)32 static inline void BIN2BCD(Bit16u& val) {
33 	const auto b = ((val / 10) % 10) << 4;
34 	const auto c = ((val / 100) % 10) << 8;
35 	const auto d = ((val / 1000) % 10) << 12;
36 	assert(b + c + d <= UINT16_MAX);
37 
38 	const uint16_t temp = (val % 10) + static_cast<uint16_t>(b + c + d);
39 	val = temp;
40 }
41 
BCD2BIN(Bit16u & val)42 static inline void BCD2BIN(Bit16u& val) {
43 	Bit16u temp= (val&0x0f) +((val>>4)&0x0f) *10 +((val>>8)&0x0f) *100 +((val>>12)&0x0f) *1000;
44 	val=temp;
45 }
46 
47 struct PIT_Block {
48 	uint32_t cntr;
49 	double delay;
50 	double start;
51 
52 	Bit16u read_latch;
53 	Bit16u write_latch;
54 
55 	Bit8u mode;
56 	Bit8u latch_mode;
57 	Bit8u read_state;
58 	Bit8u write_state;
59 
60 	bool bcd;
61 	bool go_read_latch;
62 	bool new_mode;
63 	bool counterstatus_set;
64 	bool counting;
65 	bool update_count;
66 };
67 
68 static PIT_Block pit[3];
69 static bool gate2;
70 
71 static Bit8u latched_timerstatus;
72 // the timer status can not be overwritten until it is read or the timer was
73 // reprogrammed.
74 static bool latched_timerstatus_locked;
75 
PIT0_Event(uint32_t)76 static void PIT0_Event(uint32_t /*val*/)
77 {
78 	PIC_ActivateIRQ(0);
79 	if (pit[0].mode != 0) {
80 		pit[0].start += pit[0].delay;
81 
82 		if (GCC_UNLIKELY(pit[0].update_count)) {
83 			pit[0].delay = (1000.0 / (static_cast<double>(PIT_TICK_RATE) /
84 			                          (double)pit[0].cntr));
85 			pit[0].update_count = false;
86 		}
87 		PIC_AddEvent(PIT0_Event,pit[0].delay);
88 	}
89 }
90 
counter_output(const uint32_t counter)91 static bool counter_output(const uint32_t counter)
92 {
93 	PIT_Block *p = &pit[counter];
94 	auto index = PIC_FullIndex() - p->start;
95 	switch (p->mode) {
96 	case 0:
97 		if (p->new_mode) return false;
98 		if (index>p->delay) return true;
99 		else return false;
100 		break;
101 	case 2:
102 		if (p->new_mode) return true;
103 		index = fmod(index, p->delay);
104 		return index>0;
105 	case 3:
106 		if (p->new_mode) return true;
107 		index = fmod(index, p->delay);
108 		return index*2<p->delay;
109 	case 4:
110 		//Only low on terminal count
111 		// if(fmod(index,(double)p->delay) == 0) return false; //Maybe take one rate tick in consideration
112 		//Easiest solution is to report always high (Space marines uses this mode)
113 		return true;
114 	default:
115 		LOG(LOG_PIT,LOG_ERROR)("Illegal Mode %d for reading output",p->mode);
116 		return true;
117 	}
118 }
status_latch(const uint32_t counter)119 static void status_latch(const uint32_t counter)
120 {
121 	// the timer status can not be overwritten until it is read or the timer
122 	// was reprogrammed.
123 	if (!latched_timerstatus_locked) {
124 		PIT_Block *p = &pit[counter];
125 		latched_timerstatus = 0;
126 		// Timer Status Word
127 		// 0: BCD
128 		// 1-3: Timer mode
129 		// 4-5: read/load mode
130 		// 6: "NULL" - this is 0 if "the counter value is in the
131 		// counter" ;) should rarely be 1 (i.e. on exotic modes) 7: OUT
132 		// - the logic level on the Timer output pin
133 		if (p->bcd)
134 			latched_timerstatus |= 0x1;
135 		latched_timerstatus |= ((p->mode & 7) << 1);
136 		if ((p->read_state == 0) || (p->read_state == 3))
137 			latched_timerstatus |= 0x30;
138 		else if (p->read_state == 1)
139 			latched_timerstatus |= 0x10;
140 		else if (p->read_state == 2)
141 			latched_timerstatus |= 0x20;
142 		if (counter_output(counter))
143 			latched_timerstatus |= 0x80;
144 		if (p->new_mode)
145 			latched_timerstatus |= 0x40;
146 		// The first thing that is being read from this counter now is
147 		// the counter status.
148 		p->counterstatus_set = true;
149 		latched_timerstatus_locked = true;
150 	}
151 }
counter_latch(uint32_t counter)152 static void counter_latch(uint32_t counter)
153 {
154 	/* Fill the read_latch of the selected counter with current count */
155 	PIT_Block * p=&pit[counter];
156 	p->go_read_latch=false;
157 
158 	//If gate2 is disabled don't update the read_latch
159 	if (counter == 2 && !gate2 && p->mode !=1) return;
160 
161 	auto elapsed_ms = PIC_FullIndex() - p->start;
162 	auto save_read_latch = [p](double latch_time) {
163 		// Latch is a 16-bit counter, so ensure it doesn't overflow
164 		const auto bound_latch = clamp(static_cast<int>(latch_time), 0,
165 		                               static_cast<int>(UINT16_MAX));
166 		p->read_latch = static_cast<uint16_t>(bound_latch);
167 	};
168 
169 	if (GCC_UNLIKELY(p->new_mode)) {
170 		const auto total_ticks = static_cast<uint32_t>(elapsed_ms /
171 		                                               PERIOD_OF_1K_PIT_TICKS);
172 		// if (p->mode==3) ticks_since_then /= 2; // TODO figure this
173 		// out on real hardware
174 		save_read_latch(p->read_latch - total_ticks);
175 		return;
176 	}
177 	const auto cntr = static_cast<double>(p->cntr);
178 	switch (p->mode) {
179 	case 4:         /* Software Triggered Strobe */
180 	case 0:		/* Interrupt on Terminal Count */
181 		/* Counter keeps on counting after passing terminal count */
182 		if (elapsed_ms > p->delay) {
183 			elapsed_ms -= p->delay;
184 			if (p->bcd) {
185 				elapsed_ms = fmod(elapsed_ms, PERIOD_OF_1K_PIT_TICKS * 10000.0);
186 				save_read_latch(9999 - elapsed_ms * PIT_TICK_RATE_KHZ);
187 			} else {
188 				elapsed_ms = fmod(elapsed_ms, PERIOD_OF_1K_PIT_TICKS * 0x10000);
189 				save_read_latch(0xffff - elapsed_ms * PIT_TICK_RATE_KHZ);
190 			}
191 		} else {
192 			save_read_latch(cntr - elapsed_ms * PIT_TICK_RATE_KHZ);
193 		}
194 		break;
195 	case 1: // countdown
196 		if(p->counting) {
197 			if (elapsed_ms > p->delay) {     // has timed out
198 				save_read_latch(0xffff); // unconfirmed
199 			} else {
200 				save_read_latch(cntr - elapsed_ms * PIT_TICK_RATE_KHZ);
201 			}
202 		}
203 		break;
204 	case 2:		/* Rate Generator */
205 		elapsed_ms = fmod(elapsed_ms, p->delay);
206 		save_read_latch(cntr - (elapsed_ms / p->delay) * cntr);
207 		break;
208 	case 3:		/* Square Wave Rate Generator */
209 		elapsed_ms = fmod(elapsed_ms, p->delay);
210 		elapsed_ms *= 2;
211 		if (elapsed_ms > p->delay)
212 			elapsed_ms -= p->delay;
213 		save_read_latch(cntr - (elapsed_ms / p->delay) * cntr);
214 		// In mode 3 it never returns odd numbers LSB (if odd number is
215 		// written 1 will be subtracted on first clock and then always
216 		// 2) fixes "Corncob 3D"
217 		save_read_latch(p->read_latch & 0xfffe);
218 		break;
219 	default:
220 		LOG(LOG_PIT,LOG_ERROR)("Illegal Mode %d for reading counter %d",p->mode,counter);
221 		save_read_latch(0xffff);
222 		break;
223 	}
224 }
225 
write_latch(io_port_t port,io_val_t value,io_width_t)226 static void write_latch(io_port_t port, io_val_t value, io_width_t)
227 {
228 	const auto val = check_cast<uint8_t>(value);
229 	// LOG(LOG_PIT,LOG_ERROR)("port %X write:%X
230 	// state:%X",port,val,pit[port-0x40].write_state);
231 	const uint16_t counter = port - 0x40;
232 	PIT_Block *p = &pit[counter];
233 	if (p->bcd == true)
234 		BIN2BCD(p->write_latch);
235 
236 	switch (p->write_state) {
237 	case 0:
238 		// write_latch is 16-bits
239 		p->write_latch = static_cast<uint16_t>(p->write_latch |
240 		                                       ((val & 0xff) << 8));
241 		p->write_state = 3;
242 		break;
243 	case 3:
244 		p->write_latch = val & 0xff;
245 		p->write_state = 0;
246 		break;
247 	case 1: p->write_latch = val & 0xff; break;
248 	case 2:
249 		p->write_latch = static_cast<uint16_t>((val & 0xff) << 8);
250 		break;
251 	}
252 
253 	if (p->bcd == true)
254 		BCD2BIN(p->write_latch);
255 
256 	if (p->write_state != 0) {
257 		if (p->write_latch == 0) {
258 			if (p->bcd == false)
259 				p->cntr = 0x10000;
260 			else
261 				p->cntr = 9999;
262 		}
263 		// square wave, count by 2
264 		else if (p->write_latch == 1 && p->mode == 3)
265 			// counter==1 and mode==3 makes a low frequency
266 			// buzz (Paratrooper)
267 			p->cntr = p->bcd ? 10000 : 0x10001;
268 		else
269 			p->cntr = p->write_latch;
270 
271 		if ((!p->new_mode) && (p->mode == 2) && (counter == 0)) {
272 			// In mode 2 writing another value has no direct
273 			// effect on the count until the old one has run
274 			// out. This might apply to other modes too.
275 			// This is not fixed for PIT2 yet!!
276 			p->update_count = true;
277 			return;
278 		}
279 		p->start = PIC_FullIndex();
280 		p->delay = (1000.0 / ((double)PIT_TICK_RATE / (double)p->cntr));
281 
282 		switch (counter) {
283 		case 0x00: /* Timer hooked to IRQ 0 */
284 			if (p->new_mode || p->mode == 0) {
285 				if (p->mode == 0) { // DoWhackaDo demo
286 					PIC_RemoveEvents(PIT0_Event);
287 				}
288 				PIC_AddEvent(PIT0_Event, p->delay);
289 			} else
290 				LOG(LOG_PIT, LOG_NORMAL)
291 			("PIT 0 Timer set without new control word");
292 			LOG(LOG_PIT, LOG_NORMAL)
293 			("PIT 0 Timer at %.4f Hz mode %d", 1000.0 / p->delay,
294 			 p->mode);
295 			break;
296 		case 0x02: // Timer hooked to PC-Speaker
297 			// LOG(LOG_PIT,"PIT 2 Timer at %.3g Hz mode %d",
298 			//     PIT_TICK_RATE/(double)p->cntr,p->mode);
299 			PCSPEAKER_SetCounter(p->cntr, p->mode);
300 			break;
301 		default:
302 			LOG(LOG_PIT, LOG_ERROR)
303 			("PIT:Illegal timer selected for writing");
304 		}
305 		p->new_mode = false;
306 	}
307 }
308 
read_latch(io_port_t port,io_width_t)309 static uint8_t read_latch(io_port_t port, io_width_t)
310 {
311 	// LOG(LOG_PIT,LOG_ERROR)("port read %X",port);
312 	const uint16_t counter = port - 0x40;
313 	Bit8u ret = 0;
314 	if (GCC_UNLIKELY(pit[counter].counterstatus_set)) {
315 		pit[counter].counterstatus_set = false;
316 		latched_timerstatus_locked = false;
317 		ret = latched_timerstatus;
318 	} else {
319 		if (pit[counter].go_read_latch == true)
320 			counter_latch(counter);
321 
322 		if( pit[counter].bcd == true) BIN2BCD(pit[counter].read_latch);
323 
324 		switch (pit[counter].read_state) {
325 		case 0: /* read MSB & return to state 3 */
326 			ret=(pit[counter].read_latch >> 8) & 0xff;
327 			pit[counter].read_state = 3;
328 			pit[counter].go_read_latch = true;
329 			break;
330 		case 3: /* read LSB followed by MSB */
331 			ret = pit[counter].read_latch & 0xff;
332 			pit[counter].read_state = 0;
333 			break;
334 		case 1: /* read LSB */
335 			ret = pit[counter].read_latch & 0xff;
336 			pit[counter].go_read_latch = true;
337 			break;
338 		case 2: /* read MSB */
339 			ret = (pit[counter].read_latch >> 8) & 0xff;
340 			pit[counter].go_read_latch = true;
341 			break;
342 		default:
343 			E_Exit("Timer.cpp: error in readlatch");
344 			break;
345 		}
346 		if( pit[counter].bcd == true) BCD2BIN(pit[counter].read_latch);
347 	}
348 	return ret;
349 }
350 
write_p43(io_port_t,io_val_t value,io_width_t)351 static void write_p43(io_port_t, io_val_t value, io_width_t)
352 {
353 	const auto val = check_cast<uint8_t>(value);
354 	// LOG(LOG_PIT,LOG_ERROR)("port 43 %X",val);
355 	const uint8_t latch = (val >> 6) & 0x03;
356 	switch (latch) {
357 	case 0:
358 	case 1:
359 	case 2:
360 		if ((val & 0x30) == 0) {
361 			/* Counter latch command */
362 			counter_latch(latch);
363 		} else {
364 			// save output status to be used with timer 0 irq
365 			bool old_output = counter_output(0);
366 			// save the current count value to be re-used in
367 			// undocumented newmode
368 			counter_latch(latch);
369 			pit[latch].bcd = (val & 1) > 0;
370 			if (val & 1) {
371 				if (pit[latch].cntr >= 9999)
372 					pit[latch].cntr = 9999;
373 			}
374 
375 			// Timer is being reprogrammed, unlock the status
376 			if (pit[latch].counterstatus_set) {
377 				pit[latch].counterstatus_set = false;
378 				latched_timerstatus_locked = false;
379 			}
380 			pit[latch].start = PIC_FullIndex(); // for undocumented
381 			                                    // newmode
382 			pit[latch].go_read_latch = true;
383 			pit[latch].update_count = false;
384 			pit[latch].counting = false;
385 			pit[latch].read_state = (val >> 4) & 0x03;
386 			pit[latch].write_state = (val >> 4) & 0x03;
387 			Bit8u mode = (val >> 1) & 0x07;
388 			if (mode > 5)
389 				mode -= 4; // 6,7 become 2 and 3
390 
391 			pit[latch].mode = mode;
392 
393 			/* If the line goes from low to up => generate irq.
394 			 * ( BUT needs to stay up until acknowlegded by the
395 			 * cpu!!! therefore: ) If the line goes to low =>
396 			 * disable irq. Mode 0 starts with a low line. (so
397 			 * always disable irq) Mode 2,3 start with a high line.
398 			 * counter_output tells if the current counter is high
399 			 * or low So actually a mode 3 timer enables and
400 			 * disables irq al the time. (not handled) */
401 
402 			if (latch == 0) {
403 				PIC_RemoveEvents(PIT0_Event);
404 				if ((mode != 0) && !old_output) {
405 					PIC_ActivateIRQ(0);
406 				} else {
407 					PIC_DeActivateIRQ(0);
408 				}
409 			} else if (latch == 2) {
410 				PCSPEAKER_SetCounter(0, 3);
411 			}
412 			pit[latch].new_mode = true;
413 		}
414 		break;
415 	case 3:
416 		if ((val & 0x20) == 0) { /* Latch multiple pit counters */
417 			if (val & 0x02)
418 				counter_latch(0);
419 			if (val & 0x04)
420 				counter_latch(1);
421 			if (val & 0x08)
422 				counter_latch(2);
423 		}
424 		// status and values can be latched simultaneously
425 		if ((val & 0x10) == 0) { /* Latch status words */
426 			// but only 1 status can be latched simultaneously
427 			if (val & 0x02)
428 				status_latch(0);
429 			else if (val & 0x04)
430 				status_latch(1);
431 			else if (val & 0x08)
432 				status_latch(2);
433 		}
434 		break;
435 	}
436 }
437 
TIMER_SetGate2(bool in)438 void TIMER_SetGate2(bool in) {
439 	//No changes if gate doesn't change
440 	if(gate2 == in) return;
441 	Bit8u & mode=pit[2].mode;
442 	switch (mode) {
443 	case 0:
444 		if(in) pit[2].start = PIC_FullIndex();
445 		else {
446 			//Fill readlatch and store it.
447 			counter_latch(2);
448 			pit[2].cntr = pit[2].read_latch;
449 		}
450 		break;
451 	case 1:
452 		// gate 1 on: reload counter; off: nothing
453 		if(in) {
454 			pit[2].counting = true;
455 			pit[2].start = PIC_FullIndex();
456 		}
457 		break;
458 	case 2:
459 	case 3:
460 		//If gate is enabled restart counting. If disable store the current read_latch
461 		if(in) pit[2].start = PIC_FullIndex();
462 		else counter_latch(2);
463 		break;
464 	case 4:
465 	case 5:
466 		LOG(LOG_MISC,LOG_WARN)("unsupported gate 2 mode %x",mode);
467 		break;
468 	}
469 	gate2 = in; //Set it here so the counter_latch above works
470 }
471 
TIMER_GetOutput2(void)472 bool TIMER_GetOutput2(void) {
473 	return counter_output(2);
474 }
475 
476 class TIMER final : public Module_base{
477 private:
478 	IO_ReadHandleObject ReadHandler[4];
479 	IO_WriteHandleObject WriteHandler[4];
480 public:
TIMER(Section * configuration)481 	TIMER(Section* configuration):Module_base(configuration){
482 		WriteHandler[0].Install(0x40, write_latch, io_width_t::byte);
483 		//	WriteHandler[1].Install(0x41,write_latch,io_width_t::byte);
484 		WriteHandler[2].Install(0x42, write_latch, io_width_t::byte);
485 		WriteHandler[3].Install(0x43, write_p43, io_width_t::byte);
486 		ReadHandler[0].Install(0x40, read_latch, io_width_t::byte);
487 		ReadHandler[1].Install(0x41, read_latch, io_width_t::byte);
488 		ReadHandler[2].Install(0x42, read_latch, io_width_t::byte);
489 		/* Setup Timer 0 */
490 		pit[0].cntr=0x10000;
491 		pit[0].write_state = 3;
492 		pit[0].read_state = 3;
493 		pit[0].read_latch=0;
494 		pit[0].write_latch=0;
495 		pit[0].mode=3;
496 		pit[0].bcd = false;
497 		pit[0].go_read_latch = true;
498 		pit[0].counterstatus_set = false;
499 		pit[0].update_count = false;
500 
501 		pit[1].bcd = false;
502 		pit[1].read_state = 1;
503 		pit[1].go_read_latch = true;
504 		pit[1].cntr = 18;
505 		pit[1].mode = 2;
506 		pit[1].write_state = 3;
507 		pit[1].counterstatus_set = false;
508 
509 		pit[2].read_latch=1320;	/* MadTv1 */
510 		pit[2].write_state = 3; /* Chuck Yeager */
511 		pit[2].read_state = 3;
512 		pit[2].mode=3;
513 		pit[2].bcd=false;
514 		pit[2].cntr=1320;
515 		pit[2].go_read_latch=true;
516 		pit[2].counterstatus_set = false;
517 		pit[2].counting = false;
518 
519 		pit[0].delay = (1000.0 / ((double)PIT_TICK_RATE / (double)pit[0].cntr));
520 		pit[1].delay = (1000.0 / ((double)PIT_TICK_RATE / (double)pit[1].cntr));
521 		pit[2].delay = (1000.0 / ((double)PIT_TICK_RATE / (double)pit[2].cntr));
522 
523 		latched_timerstatus_locked=false;
524 		gate2 = false;
525 		PIC_AddEvent(PIT0_Event,pit[0].delay);
526 	}
~TIMER()527 	~TIMER(){
528 		PIC_RemoveEvents(PIT0_Event);
529 	}
530 };
531 static TIMER* test;
532 
TIMER_Destroy(Section *)533 void TIMER_Destroy(Section*){
534 	delete test;
535 }
TIMER_Init(Section * sec)536 void TIMER_Init(Section* sec) {
537 	test = new TIMER(sec);
538 	sec->AddDestroyFunction(&TIMER_Destroy);
539 }
540