2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
24 /* frequency of the oscillator driving the 8254 timer */
25 #define OSC_FREQ_HZ 1193182
27 /* macro to divide and round to the nearest integer */
28 #define DIV_ROUND(a, b) ((a) / (b) + ((a) % (b)) / ((b) / 2))
30 /* I/O ports connected to the 8254 */
31 #define PORT_DATA0 0x40
32 #define PORT_DATA1 0x41
33 #define PORT_DATA2 0x42
38 #define CMD_CHAN1 (1 << 6)
39 #define CMD_CHAN2 (2 << 6)
40 #define CMD_RDBACK (3 << 6)
43 #define CMD_ACCESS_LOW (1 << 4)
44 #define CMD_ACCESS_HIGH (2 << 4)
45 #define CMD_ACCESS_BOTH (3 << 4)
47 #define CMD_OP_INT_TERM 0
48 #define CMD_OP_ONESHOT (1 << 1)
49 #define CMD_OP_RATE (2 << 1)
50 #define CMD_OP_SQWAVE (3 << 1)
51 #define CMD_OP_SOFT_STROBE (4 << 1)
52 #define CMD_OP_HW_STROBE (5 << 1)
54 #define CMD_MODE_BIN 0
55 #define CMD_MODE_BCD 1
58 #define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000)
61 int dt; /* remaining ticks delta from the previous event */
62 struct timer_event *next;
65 /* defined in intr_asm.S */
66 void intr_entry_fast_timer(void);
68 static struct timer_event *evlist;
73 /* calculate the reload count: round(osc / freq) */
74 int reload_count = DIV_ROUND(OSC_FREQ_HZ, TICK_FREQ_HZ);
76 /* set the mode to square wave for channel 0, both low
77 * and high reload count bytes will follow...
79 outb(CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE, PORT_CMD);
81 /* write the low and high bytes of the reload count to the
84 outb(reload_count & 0xff, PORT_DATA0);
85 outb((reload_count >> 8) & 0xff, PORT_DATA0);
87 /* set the timer interrupt handler */
88 /*interrupt(IRQ_TO_INTR(0), timer_handler);*/
89 /* set low level fast timer interrupt routine directly in the IDT */
90 set_intr_entry(IRQ_TO_INTR(0), intr_entry_fast_timer);
94 static void timer_handler(int inum)