| author | |
| committer | |
| log | 1c53c070535c519cbdc39a2094a24723f5245799 |
| tree | 3eda4394f30e67286e229c43d956e1dcb2cd9585 |
| parent | f31cee5393bbfd29883a7b253cd518db145b8b19 |
2 files changed, 49 insertions(+), 3 deletions(-)
src-self-hosted/codegen.zig+10-3| ... | ... | @@ -76,8 +76,8 @@ pub fn generateSymbol( |
| 76 | 76 | switch (bin_file.options.target.cpu.arch) { |
| 77 | 77 | .wasm32 => unreachable, // has its own code path |
| 78 | 78 | .wasm64 => unreachable, // has its own code path |
| 79 | //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | |
| 80 | //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | |
| 79 | .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | |
| 80 | .armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | |
| 81 | 81 | //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), |
| 82 | 82 | //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), |
| 83 | 83 | //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), |
| ... | ... | @@ -1270,8 +1270,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1270 | 1270 | var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined1 }; |
| 1271 | 1271 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr)); |
| 1272 | 1272 | }, |
| 1273 | .arm => { | |
| 1274 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bkpt(0).toU32()); | |
| 1275 | }, | |
| 1276 | .armeb => { | |
| 1277 | mem.writeIntBig(u32, try self.code.addManyAsArray(4), Instruction.bkpt(0).toU32()); | |
| 1278 | }, | |
| 1273 | 1279 | else => return self.fail(src, "TODO implement @breakpoint() for {}", .{self.target.cpu.arch}), |
| 1274 | } | |
| 1280 | } | |
| 1275 | 1281 | return .none; |
| 1276 | 1282 | } |
| 1277 | 1283 | |
| ... | ... | @@ -2373,6 +2379,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2373 | 2379 | .riscv64 => @import("codegen/riscv64.zig"), |
| 2374 | 2380 | .spu_2 => @import("codegen/spu-mk2.zig"), |
| 2375 | 2381 | .arm => @import("codegen/arm.zig"), |
| 2382 | .armeb => @import("codegen/arm.zig"), | |
| 2376 | 2383 | else => struct { |
| 2377 | 2384 | pub const Register = enum { |
| 2378 | 2385 | dummy, |
src-self-hosted/codegen/arm.zig+39| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const DW = std.dwarf; | |
| 2 | 3 | const testing = std.testing; |
| 3 | 4 | |
| 4 | 5 | /// The condition field specifies the flags neccessary for an |
| ... | ... | @@ -93,6 +94,18 @@ pub const Register = enum(u5) { |
| 93 | 94 | pub fn id(self: Register) u4 { |
| 94 | 95 | return @truncate(u4, @enumToInt(self)); |
| 95 | 96 | } |
| 97 | ||
| 98 | /// Returns the index into `callee_preserved_regs`. | |
| 99 | pub fn allocIndex(self: Register) ?u4 { | |
| 100 | inline for (callee_preserved_regs) |cpreg, i| { | |
| 101 | if (self.id() == cpreg.id()) return i; | |
| 102 | } | |
| 103 | return null; | |
| 104 | } | |
| 105 | ||
| 106 | pub fn dwarfLocOp(self: Register) u8 { | |
| 107 | return @as(u8, self.id()) + DW.OP_reg0; | |
| 108 | } | |
| 96 | 109 | }; |
| 97 | 110 | |
| 98 | 111 | test "Register.id" { |
| ... | ... | @@ -149,6 +162,12 @@ pub const Instruction = union(enum) { |
| 149 | 162 | fixed: u4 = 0b1111, |
| 150 | 163 | cond: u4, |
| 151 | 164 | }, |
| 165 | Breakpoint: packed struct { | |
| 166 | imm4: u4, | |
| 167 | fixed_1: u4 = 0b0111, | |
| 168 | imm12: u12, | |
| 169 | fixed_2_and_cond: u12 = 0b1110_0001_0010, | |
| 170 | }, | |
| 152 | 171 | |
| 153 | 172 | /// Represents the possible operations which can be performed by a |
| 154 | 173 | /// DataProcessing instruction |
| ... | ... | @@ -326,6 +345,7 @@ pub const Instruction = union(enum) { |
| 326 | 345 | .Branch => |v| @bitCast(u32, v), |
| 327 | 346 | .BranchExchange => |v| @bitCast(u32, v), |
| 328 | 347 | .SoftwareInterrupt => |v| @bitCast(u32, v), |
| 348 | .Breakpoint => |v| @intCast(u32, v.imm4) | (@intCast(u32, v.fixed_1) << 4) | (@intCast(u32, v.imm12) << 8) | (@intCast(u32, v.fixed_2_and_cond) << 20), | |
| 329 | 349 | }; |
| 330 | 350 | } |
| 331 | 351 | |
| ... | ... | @@ -408,6 +428,15 @@ pub const Instruction = union(enum) { |
| 408 | 428 | }; |
| 409 | 429 | } |
| 410 | 430 | |
| 431 | fn breakpoint(imm: u16) Instruction { | |
| 432 | return Instruction{ | |
| 433 | .Breakpoint = .{ | |
| 434 | .imm12 = @truncate(u12, imm >> 4), | |
| 435 | .imm4 = @truncate(u4, imm), | |
| 436 | }, | |
| 437 | }; | |
| 438 | } | |
| 439 | ||
| 411 | 440 | // Public functions replicating assembler syntax as closely as |
| 412 | 441 | // possible |
| 413 | 442 | |
| ... | ... | @@ -512,6 +541,12 @@ pub const Instruction = union(enum) { |
| 512 | 541 | pub fn swi(cond: Condition, comment: u24) Instruction { |
| 513 | 542 | return softwareInterrupt(cond, comment); |
| 514 | 543 | } |
| 544 | ||
| 545 | // Breakpoint | |
| 546 | ||
| 547 | pub fn bkpt(imm: u16) Instruction { | |
| 548 | return breakpoint(imm); | |
| 549 | } | |
| 515 | 550 | }; |
| 516 | 551 | |
| 517 | 552 | test "serialize instructions" { |
| ... | ... | @@ -557,6 +592,10 @@ test "serialize instructions" { |
| 557 | 592 | .inst = Instruction.swi(.al, 0), |
| 558 | 593 | .expected = 0b1110_1111_0000_0000_0000_0000_0000_0000, |
| 559 | 594 | }, |
| 595 | .{ // bkpt #42 | |
| 596 | .inst = Instruction.bkpt(42), | |
| 597 | .expected = 0b1110_0001_0010_000000000010_0111_1010, | |
| 598 | }, | |
| 560 | 599 | }; |
| 561 | 600 | |
| 562 | 601 | for (testcases) |case| { |