Here is my pit timing code:
Code: Select all
// pit trigger speed in hz
#define CYCLE ((uint64_tp)1193182)
static uint32_tp pit_hz = 200;
static uint32_tp pit_divisor = CYCLE / pit_hz;
// count of ticks since start where there are pit_hz ticks per second.
static volatile uint64_tp pit_ticks = 0;
// IRQ handler
void smos_pit_tick(registers_tp *regs_)
{
++pit_ticks;
}
void pit()
{
ASM("cli");
// do note, while this is registered, its the only irq we'll handle
// (besides PF and GPF)
smos_register_int_handler(32, smos_pit_tick);
// chan 0, lo/hibyte rate generator
smos_outb(0x43, FROM_BINARY(0, 0, 1, 1, 0, 1, 0, 0));
smos_outb(0x40, pit_divisor & 0xff);
smos_outb(0x40, (pit_divisor >> 8) & 0xff);
clear_irq_mask(0);
ASM("sti");
}
void pit_done()
{
ASM("cli");
smos_register_int_handler(32, 0);
set_irq_mask(0);
// TODO: actually stop the pit
}
Code: Select all
#define APIC_SPURIOUS 0xf0
#define APIC_LVT_TMR 0x320
#define APIC_TMRDIV 0x3e0
#define APIC_TMRINITCNT 0x380
#define APIC_DISABLE 0x10000
#define APIC_TMRCURRCNT 0x390
#define APIC_SW_ENABLE 0x100
typedef uint8_tp *addr_tp;
void set_dword_at(addr_tp addr_, uint32_tp val_) { *((uint32_tp *)addr_) = val_; }
func()
{
// where the registers are in regular virtual space (mapped earlier)
addr_tp apic = (addr_tp)smos.apic_registers_base;
// set spurious irq.. My int handler just returns if this triggers.
set_dword_at(apic + APIC_SPURIOUS, 39 + APIC_SW_ENABLE);
set_dword_at(apic + APIC_LVT_TMR, 32); // timer irq to use (?)
set_dword_at(apic + APIC_TMRDIV, 0x03); // divide ratio is 16.
uint32_tp target = pit_hz / 4; // we wait 250ms
pit(); // start the timer
// start the apic counting down.
set_dword_at(apic + APIC_TMRINITCNT, 0xffffffff);
while (pit_ticks < target) ASM("hlt"); // wait til 250ms has elapsed
pit_done(); // stop pit
set_dword_at(apic + APIC_LVT_TMR, APIC_DISABLE); // disable apic
uint32_tp count = get_dword_at(apic + APIC_TMRCURRCNT);
uint32_tp diff = (0xffffffff - count); // number of ticks that occurred in 250ms
// * 16 because we used a divisor of 16
// * 4 because we only waited 250ms.
uint64_tp cpu_bus_hz = (uint64_tp)diff * 16 * 4;
kprintf("speed %u mhz\n", cpu_bus_hz / 1024 / 1024); // this outputs approx 218
}