Programmable Interval Timer
The Programmable Interval Timer aka the PIC is a device on most x86_64 machines that you can tell to trigger and interrupt at a well programmable interval
The following code will allow you to set it up at a specified tick rate and wait a number of milliseconds to use the PIT for most tasks you would need
Make sure to make the proper C header files for these to work together and for other code to be able to use it.
static inline void io_wait() {
outb(0x80, 0);
}
int pitFrequency;
void pit_sleep_ms(unsigned int ms) {
int startTicks = pitInteruptsTriggered;
int targetTicks = startTicks + (ms * pitFrequency) / 1000;
while (pitInteruptsTriggered < targetTicks) {
int currentTicks = pitInteruptsTriggered;
if (currentTicks < startTicks) {
startTicks = currentTicks;
targetTicks = startTicks + (ms * pitFrequency) / 1000;
}
asm volatile("hlt");
}
}
void setup_pit(unsigned int frequency) {
__asm__ __volatile__("cli");
pitFrequency = frequency;
unsigned int divisor = PIT_FREQUENCY / frequency;
outb(PIT_CONTROL_PORT, 0x36 | 0x02);
io_wait();
outb(PIT_CHANNEL0_PORT, divisor & 0xFF);
io_wait();
outb(PIT_CHANNEL0_PORT, divisor >> 8);
io_wait();
unmask_irq(0);
__asm__ __volatile__("sti");
}
For the interrupt you might want something like this assigned to IRQ 0 / INT 0x20
volatile int pitInteruptsTriggered = 0;
__attribute__((interrupt))
void pit_isr(__attribute__((unused)) void* frame) {
pitInteruptsTriggered++;
outb(0x20,0x20);
}
You should then be able to call setup_pit() as setup_pit(1000); and every ms you will get an interrupt.
And then you can call pit_sleep_ms() as pit_sleep_ms(100); and it will sleep for ~100 MS