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 }