timer.zig (2332B)
1 const std = @import("std"); 2 3 const clock = @import("./clock.zig"); 4 5 const interrupts = @import("../interrupts.zig"); 6 const mem = @import("../mem.zig"); 7 8 const BASE_ADDRESS: usize = mem.BASE_ADDRESS + 0xB400; 9 10 const TIMER_LOAD: usize = BASE_ADDRESS + 0x00; 11 const TIMER_VALUE: usize = BASE_ADDRESS + 0x04; 12 const TIMER_CONTROL: usize = BASE_ADDRESS + 0x08; 13 14 const TIMER_IRQ_CLEAR: usize = BASE_ADDRESS + 0x0C; 15 const TIMER_IRQ_RAW: usize = BASE_ADDRESS + 0x10; 16 const TIMER_IRQ_MASKED: usize = BASE_ADDRESS + 0x14; 17 18 const TIMER_RELOAD: usize = BASE_ADDRESS + 0x18; 19 const TIMER_PREDIV: usize = BASE_ADDRESS + 0x1C; 20 const TIMER_COUNTER: usize = BASE_ADDRESS + 0x20; 21 22 const PreScale = enum(u2) { 23 None = 0b00, 24 Sixteen = 0b01, 25 TwoFiftySix = 0b10, 26 One = 0b11, 27 }; 28 29 const Counter = enum(u1) { 30 Bit16 = 0, 31 Bit32 = 1, 32 }; 33 34 const Control = packed struct(u32) { 35 _unused_1: u1, // 0 36 counter: Counter, // 1 37 pre_scale: PreScale, // 2-3 38 _unused_4: u1, // 4 39 interrupt_enabled: bool, // 5 40 _unused_6: u1, // 6 41 timer_enabled: bool, // 7 42 run_in_debug_halted: bool, // 8 43 free_running_counter_enable: bool, // 9 44 _unused_15_10: u5, // 10-15 45 free_running_counter_pre_scaler: u7, // 16-23 46 _unused_31_24: u10, 47 }; 48 49 fn default_control() Control { 50 return @bitCast(@as(u32, 0)); 51 } 52 53 fn empty(regs: interrupts.Registers) void { 54 _ = regs; 55 } 56 57 var tick_fn: *const fn (interrupts.Registers) void = empty; 58 59 pub fn initialize(pre_scale: PreScale, cycles: u32) void { 60 mem.barrier(.Write); 61 62 interrupts.set_exception_handler(.IRQ, timer_handler); 63 interrupts.enable_basic_interrupt(.Timer); 64 65 mem.put_u32(@ptrFromInt(TIMER_LOAD), cycles); 66 67 var control = default_control(); 68 control.counter = .Bit32; 69 control.timer_enabled = true; 70 control.interrupt_enabled = true; 71 control.pre_scale = pre_scale; 72 73 mem.put_u32_barrier(@ptrFromInt(TIMER_CONTROL), @bitCast(control)); 74 } 75 76 noinline fn timer_handler(reg: interrupts.Registers) void { 77 mem.barrier(.Write); // Sync 78 79 if (!interrupts.pending_basic(.Timer)) return; 80 81 // Clear interrupt 82 mem.put_u32_barrier(@ptrFromInt(TIMER_IRQ_CLEAR), 1); 83 84 tick_fn(reg); 85 86 mem.barrier(.Write); // Sync before restoring 87 } 88 89 pub inline fn set_tick(tick: *const fn (interrupts.Registers) void) void { 90 tick_fn = tick; 91 }