const arch = @import("root.zig"); const std = @import("std"); const out = arch.port.out; const in = arch.port.in; const log = std.log.scoped(.tsc); pub var tsc_khz: usize = 0; pub inline fn rdtsc() u64 { var low: u32 = undefined; var high: u32 = undefined; asm volatile ("rdtsc" : [low] "={eax}" (low), [high] "={edx}" (high), ); return (@as(u64, high) << 32) | @as(u64, low); } /// This should be called if we cannot get the TSC rate from /// CPUID.15h and 16h on Intel platforms. The calibration will be done /// against the 8254 PIT. pub fn calibrate_pit() !void { // Set up the PIC arch.interrupts.pic.init(); out(u8, 0x61, in(u8, 0x61) & 0b1111_1101 | 0x01); var pollcnt: u32 = 0; var start: usize = 0; var end: usize = 0; var prev_end: usize = 0; var delta: usize = 0; arch.interrupts.pit.mode0(50); start = rdtsc(); end = start; while (in(u8, 0x61) & 0x20 == 0) { end = rdtsc(); delta = end - prev_end; prev_end = end; pollcnt += 1; } if (pollcnt < 1000) return error.PitError; tsc_khz = (end - start) / 50; log.debug("{} MHz", .{tsc_khz / 1000}); } /// Delay for a set amount of ms using crappy polling pub fn delay_poll(ms: usize) void { const start = rdtsc(); const target = start + ms * tsc_khz; while (rdtsc() < target) {} }