sylveos

Toy Operating System
Log | Files | Refs

debug.zig (7847B)


      1 // CP14
      2 const mem = @import("./mem.zig");
      3 
      4 // # Debug ID Register
      5 // Reference: ARM1176JZF-S Technical Reference Manual - 13.3.2
      6 pub const DIDR = packed struct(u32) {
      7     revision: u4,
      8     variant: u4,
      9     _reserved_8_11: u4,
     10     debug_revision: u4,
     11     debug_version: u4,
     12     context: u4,
     13     breakpoint_pairs: u4,
     14     watchpoint_pairs: u4,
     15 
     16     pub inline fn get() @This() {
     17         return asm volatile ("MRC p14, 0, %[result], c0, c0, 0"
     18             : [result] "=r" (-> @This()),
     19         );
     20     }
     21 };
     22 
     23 // # Debug Status and Control Register
     24 // Reference: ARM1176JZF-S Technical Reference Manual - 13.3.3
     25 pub const DSCR = packed struct(u32) {
     26     pub const EntryMethod = enum(u4) {
     27         Halt = 0b0000,
     28         Breakpoint = 0b0001,
     29         Watchpoint = 0b0010,
     30         BKPT = 0b0011,
     31         EDBGRQ = 0b0100,
     32         VectorCatch = 0b0101,
     33     };
     34     pub const ModeSelect = enum(u1) {
     35         Monitor = 0,
     36         Halting = 1,
     37     };
     38 
     39     core_halted: bool,
     40     core_restarted: bool,
     41     entry_method: EntryMethod,
     42     sticky_precise: bool,
     43     sticky_imprecise: bool,
     44     sticky_undefined: bool,
     45     power_down_disable: bool,
     46     dbg_ack: bool,
     47     interrupts: bool,
     48     user_comms_access: bool,
     49     execute_arm: bool,
     50     mode_select: ModeSelect,
     51     monitor_debug: bool,
     52     invasive_debug: bool,
     53     non_invasive_debug: bool,
     54     world_status: u1,
     55     imprecise_aborts_ignore: bool,
     56     _reverse_20_28: u9,
     57     w_dtr_full: bool,
     58     r_dtr_full: bool,
     59     _reserved_31: u1,
     60 
     61     pub inline fn get() @This() {
     62         return asm volatile ("MRC p14, 0, %[result], c0, c1, 0"
     63             : [result] "=r" (-> @This()),
     64         );
     65     }
     66 
     67     pub inline fn set(dscr: *const @This()) void {
     68         return asm volatile ("MCR p14, 0, %[value], c0, c1, 0"
     69             :
     70             : [value] "r" (@as(u32, @bitCast(dscr.*))),
     71         );
     72     }
     73 };
     74 
     75 pub const SupervisorAccess = enum(u2) {
     76     Priviledged = 0b01,
     77     User = 0b10,
     78     Either = 0b11,
     79 };
     80 
     81 pub const ByteAddressSelect = packed struct(u4) {
     82     pub const All: @This() = .{
     83         .@"0" = true,
     84         .@"1" = true,
     85         .@"2" = true,
     86         .@"3" = true,
     87     };
     88 
     89     @"0": bool,
     90     @"1": bool,
     91     @"2": bool,
     92     @"3": bool,
     93 };
     94 
     95 pub const Matches = enum(u2) {
     96     Both = 0b00,
     97     NonSecure = 0b01,
     98     Secure = 0b10,
     99 };
    100 
    101 inline fn register(comptime n: u4) []const u8 {
    102     return switch (n) {
    103         0 => "c0",
    104         1 => "c1",
    105         2 => "c2",
    106         3 => "c3",
    107         4 => "c4",
    108         5 => "c5",
    109         6 => "c6",
    110         7 => "c7",
    111         8 => "c8",
    112         9 => "c9",
    113         10 => "c10",
    114         11 => "c11",
    115         12 => "c12",
    116         13 => "c13",
    117         14 => "c14",
    118         15 => "c15",
    119     };
    120 }
    121 
    122 // # Breakpoint Control Register
    123 // Reference: ARM1176JZF-S Technical Reference Manual - 13.3.8
    124 pub const BCR = packed struct(u32) {
    125     pub const BVRMeaning = enum(u2) {
    126         IMVAMatch = 0b00,
    127         ContextIdMatch = 0b01,
    128         IMVAMismatch = 0b10,
    129     };
    130 
    131     enabled: bool,
    132     supervisor_access: SupervisorAccess,
    133     _reserved_3_4: u2,
    134     byte_address_select: ByteAddressSelect,
    135     _reserved_9_13: u5,
    136     matches: Matches,
    137     linked_brp: u4,
    138     linking: bool,
    139     bvr_meaning: BVRMeaning,
    140     _reserved_23_31: u9,
    141 
    142     pub inline fn get(comptime n: u4) @This() {
    143         const Crn = register(n);
    144 
    145         return asm volatile ("MRC p14, 0, %[result], c0, " ++ Crn ++ ", 5"
    146             : [result] "=r" (-> @This()),
    147         );
    148     }
    149     pub inline fn get_pc(comptime n: u4) u32 {
    150         const Crn = register(n);
    151 
    152         return asm volatile ("MRC p14, 0, %[result], c0, " ++ Crn ++ ", 4"
    153             : [result] "=r" (-> u32),
    154         );
    155     }
    156 
    157     pub inline fn set(self: *const @This(), comptime n: u4) void {
    158         const Crn = register(n);
    159 
    160         asm volatile ("MCR p14, 0, %[value], c0, " ++ Crn ++ ", 5"
    161             :
    162             : [value] "r" (@as(u32, @bitCast(self.*))),
    163         );
    164     }
    165     pub inline fn set_pc(comptime n: u4, pc: u32) void {
    166         const Crn = register(n);
    167 
    168         asm volatile ("MCR p14, 0, %[value], c0, " ++ Crn ++ ", 4"
    169             :
    170             : [value] "r" (pc),
    171         );
    172     }
    173 };
    174 
    175 // # Watchpoint Control Register
    176 // Reference: ARM1176JZF-S Technical Reference Manual - 13.3.10
    177 pub const WCR = packed struct(u32) {
    178     pub const LoadStoreAccess = enum(u2) {
    179         Load = 0b01,
    180         Store = 0b10,
    181         Either = 0b11,
    182     };
    183 
    184     enabled: bool,
    185     supervisor_access: SupervisorAccess,
    186     load_store_access: LoadStoreAccess,
    187     byte_address_select: ByteAddressSelect,
    188     _reserved_9_13: u5,
    189     matches: Matches,
    190     linked_brp: u4,
    191     linking: bool,
    192     _reserved_21_31: u11,
    193 
    194     pub inline fn get(comptime n: u4) @This() {
    195         const Crn = register(n);
    196 
    197         return asm volatile ("MRC p14, 0, %[result], c0, " ++ Crn ++ ", 7"
    198             : [result] "=r" (-> @This()),
    199         );
    200     }
    201     pub inline fn get_address(comptime n: u4) u32 {
    202         const Crn = register(n);
    203 
    204         return asm volatile ("MRC p14, 0, %[result], c0, " ++ Crn ++ ", 6"
    205             : [result] "=r" (-> u32),
    206         );
    207     }
    208 
    209     pub inline fn set(self: *const @This(), comptime n: u4) void {
    210         const Crn = register(n);
    211 
    212         asm volatile ("MCR p14, 0, %[value], c0, " ++ Crn ++ ", 7"
    213             :
    214             : [value] "r" (@as(u32, @bitCast(self.*))),
    215         );
    216     }
    217     pub inline fn set_address(comptime n: u4, address: u32) void {
    218         const Crn = register(n);
    219 
    220         asm volatile ("MCR p14, 0, %[value], c0, " ++ Crn ++ ", 6"
    221             :
    222             : [value] "r" (address),
    223         );
    224     }
    225 };
    226 
    227 // # Watchpoint Fault Address Register
    228 // Reference: ARM1176JZF-S Technical Reference Manual - 13.3.5
    229 pub const WFAR = struct {
    230     pub inline fn get() u32 {
    231         return asm volatile ("MRC p14, 0, %[result], c0, c6, 0"
    232             : [result] "=r" (-> u32),
    233         );
    234     }
    235     // I don't know why you'd want to write
    236     // but it isn't disallowed
    237     pub inline fn set(address: u32) void {
    238         return asm volatile ("MCR p14, 0, %[value], c0, c6, 0"
    239             :
    240             : [value] "r" (address),
    241         );
    242     }
    243 };
    244 
    245 pub inline fn enable_monitor_mode() void {
    246     var dscr = DSCR.get();
    247 
    248     dscr.monitor_debug = true;
    249     dscr.mode_select = .Monitor;
    250     dscr.set();
    251     mem.barrier(.Instruction);
    252 }
    253 
    254 pub inline fn disable_monitor_mode() void {
    255     var dscr = DSCR.get();
    256     dscr.monitor_debug = false;
    257     dscr.set();
    258     mem.barrier(.Instruction);
    259 }
    260 
    261 // 13.14.2
    262 pub inline fn set_breakpoint(comptime n: u4, pc: usize, kind: BCR.BVRMeaning) void {
    263     // "Read the BCR"
    264     var bcr = BCR.get(n);
    265 
    266     // "Clear the BCR[0] enable breakpoint bit... write it back"
    267     bcr.enabled = false;
    268     bcr.set(n);
    269 
    270     // Write the IMVA to the BVR
    271     BCR.set_pc(n, pc);
    272 
    273     // Write to the BCR
    274     bcr.bvr_meaning = kind;
    275     bcr.linking = false;
    276     bcr.matches = .Both;
    277     bcr.byte_address_select = ByteAddressSelect.All;
    278     bcr.supervisor_access = .Either;
    279     bcr.enabled = true;
    280     bcr.set(n);
    281 
    282     // Sync
    283     mem.barrier(.Instruction);
    284 }
    285 
    286 pub inline fn clear_breakpoint(comptime n: u4) void {
    287     var bcr = BCR.get(n);
    288     bcr.enabled = false;
    289     bcr.set(n);
    290 
    291     // Sync
    292     mem.barrier(.Instruction);
    293 }
    294 
    295 // 13.14.2
    296 pub inline fn set_watchpoint(comptime n: u4, address: u32, kind: WCR.LoadStoreAccess) void {
    297     // "Read the WCR"
    298     var wcr = WCR.get(n);
    299 
    300     // "Clear the WCR[0] enable watchpoint bit... write it back"
    301     wcr.enabled = false;
    302     wcr.set(n);
    303 
    304     // Write the DMVA to the WVR
    305     WCR.set_address(n, address);
    306 
    307     // Write to the WCR
    308     wcr.linking = false;
    309     wcr.load_store_access = kind;
    310     wcr.enabled = true;
    311     wcr.set(n);
    312 
    313     // Sync
    314     mem.barrier(.Instruction);
    315 }
    316 
    317 pub inline fn clear_watchpoint(comptime n: u4) void {
    318     var wcr = WCR.get(n);
    319     wcr.enabled = false;
    320     wcr.set(n);
    321 
    322     // Sync
    323     mem.barrier(.Instruction);
    324 }