sylveos

Toy Operating System
Log | Files | Refs

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 }