| author | |
| committer | |
| log | 07606d12daabe8c201dba3d5b27e702ce58d0ffb |
| tree | e19a4fb6d5d5859e0378212d9ec9e92b704b98d7 |
| parent | 7cd94d212361bc5662e8cc6959cd32edca1df03a |
As it stands, the backend is incomplete, and there is no active contributor,
making it dead weight.
However, anyone is free to resurrect this backend at any time.7 files changed, 1 insertions(+), 543 deletions(-)
BRANCH_TODO-2| ... | ... | @@ -1,5 +1,3 @@ |
| 1 | * get stage2 tests passing | |
| 2 | - spu-ii test is saying "unimplemented" for some reason | |
| 3 | 1 | * modify stage2 tests so that only 1 uses _start and the rest use |
| 4 | 2 | pub fn main |
| 5 | 3 | * modify stage2 CBE tests so that only 1 uses pub export main and the |
src/codegen.zig-67| ... | ... | @@ -117,7 +117,6 @@ pub fn generateSymbol( |
| 117 | 117 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 118 | 118 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 119 | 119 | //.s390x => return Function(.s390x).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 120 | .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | |
| 121 | 120 | //.tce => return Function(.tce).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 122 | 121 | //.tcele => return Function(.tcele).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 123 | 122 | //.thumb => return Function(.thumb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| ... | ... | @@ -2204,11 +2203,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2204 | 2203 | .riscv64 => { |
| 2205 | 2204 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ebreak.toU32()); |
| 2206 | 2205 | }, |
| 2207 | .spu_2 => { | |
| 2208 | try self.code.resize(self.code.items.len + 2); | |
| 2209 | var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined1 }; | |
| 2210 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr)); | |
| 2211 | }, | |
| 2212 | 2206 | .arm, .armeb => { |
| 2213 | 2207 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.bkpt(0).toU32()); |
| 2214 | 2208 | }, |
| ... | ... | @@ -2317,53 +2311,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2317 | 2311 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); |
| 2318 | 2312 | } |
| 2319 | 2313 | }, |
| 2320 | .spu_2 => { | |
| 2321 | if (inst.func.value()) |func_value| { | |
| 2322 | if (info.args.len != 0) { | |
| 2323 | return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{}); | |
| 2324 | } | |
| 2325 | if (func_value.castTag(.function)) |func_payload| { | |
| 2326 | const func = func_payload.data; | |
| 2327 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { | |
| 2328 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | |
| 2329 | break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2); | |
| 2330 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| | |
| 2331 | @intCast(u16, coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * 2) | |
| 2332 | else | |
| 2333 | unreachable; | |
| 2334 | ||
| 2335 | assert(func.owner_decl.has_tv); | |
| 2336 | const return_type = func.owner_decl.ty.fnReturnType(); | |
| 2337 | // First, push the return address, then jump; if noreturn, don't bother with the first step | |
| 2338 | // TODO: implement packed struct -> u16 at comptime and move the bitcast here | |
| 2339 | var instr = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .jump, .command = .load16 }; | |
| 2340 | if (return_type.zigTypeTag() == .NoReturn) { | |
| 2341 | try self.code.resize(self.code.items.len + 4); | |
| 2342 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr)); | |
| 2343 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr); | |
| 2344 | return MCValue.unreach; | |
| 2345 | } else { | |
| 2346 | try self.code.resize(self.code.items.len + 8); | |
| 2347 | var push = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .push, .command = .ipget }; | |
| 2348 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 8 ..][0..2], @bitCast(u16, push)); | |
| 2349 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 6 ..][0..2], @as(u16, 4)); | |
| 2350 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr)); | |
| 2351 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr); | |
| 2352 | switch (return_type.zigTypeTag()) { | |
| 2353 | .Void => return MCValue{ .none = {} }, | |
| 2354 | .NoReturn => unreachable, | |
| 2355 | else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), | |
| 2356 | } | |
| 2357 | } | |
| 2358 | } else if (func_value.castTag(.extern_fn)) |_| { | |
| 2359 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | |
| 2360 | } else { | |
| 2361 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | |
| 2362 | } | |
| 2363 | } else { | |
| 2364 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | |
| 2365 | } | |
| 2366 | }, | |
| 2367 | 2314 | .arm, .armeb => { |
| 2368 | 2315 | for (info.args) |mc_arg, arg_i| { |
| 2369 | 2316 | const arg = inst.args[arg_i]; |
| ... | ... | @@ -3176,19 +3123,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3176 | 3123 | if (!inst.is_volatile and inst.base.isUnused()) |
| 3177 | 3124 | return MCValue.dead; |
| 3178 | 3125 | switch (arch) { |
| 3179 | .spu_2 => { | |
| 3180 | if (inst.inputs.len > 0 or inst.output_constraint != null) { | |
| 3181 | return self.fail(inst.base.src, "TODO implement inline asm inputs / outputs for SPU Mark II", .{}); | |
| 3182 | } | |
| 3183 | if (mem.eql(u8, inst.asm_source, "undefined0")) { | |
| 3184 | try self.code.resize(self.code.items.len + 2); | |
| 3185 | var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined0 }; | |
| 3186 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr)); | |
| 3187 | return MCValue.none; | |
| 3188 | } else { | |
| 3189 | return self.fail(inst.base.src, "TODO implement support for more SPU II assembly instructions", .{}); | |
| 3190 | } | |
| 3191 | }, | |
| 3192 | 3126 | .arm, .armeb => { |
| 3193 | 3127 | for (inst.inputs) |input, i| { |
| 3194 | 3128 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { |
| ... | ... | @@ -4503,7 +4437,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 4503 | 4437 | .i386 => @import("codegen/x86.zig"), |
| 4504 | 4438 | .x86_64 => @import("codegen/x86_64.zig"), |
| 4505 | 4439 | .riscv64 => @import("codegen/riscv64.zig"), |
| 4506 | .spu_2 => @import("codegen/spu-mk2.zig"), | |
| 4507 | 4440 | .arm, .armeb => @import("codegen/arm.zig"), |
| 4508 | 4441 | .aarch64, .aarch64_be, .aarch64_32 => @import("codegen/aarch64.zig"), |
| 4509 | 4442 | else => struct { |
src/codegen/spu-mk2.zig deleted-170| ... | ... | @@ -1,170 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub const Interpreter = @import("spu-mk2/interpreter.zig").Interpreter; | |
| 4 | ||
| 5 | pub const ExecutionCondition = enum(u3) { | |
| 6 | always = 0, | |
| 7 | when_zero = 1, | |
| 8 | not_zero = 2, | |
| 9 | greater_zero = 3, | |
| 10 | less_than_zero = 4, | |
| 11 | greater_or_equal_zero = 5, | |
| 12 | less_or_equal_zero = 6, | |
| 13 | overflow = 7, | |
| 14 | }; | |
| 15 | ||
| 16 | pub const InputBehaviour = enum(u2) { | |
| 17 | zero = 0, | |
| 18 | immediate = 1, | |
| 19 | peek = 2, | |
| 20 | pop = 3, | |
| 21 | }; | |
| 22 | ||
| 23 | pub const OutputBehaviour = enum(u2) { | |
| 24 | discard = 0, | |
| 25 | push = 1, | |
| 26 | jump = 2, | |
| 27 | jump_relative = 3, | |
| 28 | }; | |
| 29 | ||
| 30 | pub const Command = enum(u5) { | |
| 31 | copy = 0, | |
| 32 | ipget = 1, | |
| 33 | get = 2, | |
| 34 | set = 3, | |
| 35 | store8 = 4, | |
| 36 | store16 = 5, | |
| 37 | load8 = 6, | |
| 38 | load16 = 7, | |
| 39 | undefined0 = 8, | |
| 40 | undefined1 = 9, | |
| 41 | frget = 10, | |
| 42 | frset = 11, | |
| 43 | bpget = 12, | |
| 44 | bpset = 13, | |
| 45 | spget = 14, | |
| 46 | spset = 15, | |
| 47 | add = 16, | |
| 48 | sub = 17, | |
| 49 | mul = 18, | |
| 50 | div = 19, | |
| 51 | mod = 20, | |
| 52 | @"and" = 21, | |
| 53 | @"or" = 22, | |
| 54 | xor = 23, | |
| 55 | not = 24, | |
| 56 | signext = 25, | |
| 57 | rol = 26, | |
| 58 | ror = 27, | |
| 59 | bswap = 28, | |
| 60 | asr = 29, | |
| 61 | lsl = 30, | |
| 62 | lsr = 31, | |
| 63 | }; | |
| 64 | ||
| 65 | pub const Instruction = packed struct { | |
| 66 | condition: ExecutionCondition, | |
| 67 | input0: InputBehaviour, | |
| 68 | input1: InputBehaviour, | |
| 69 | modify_flags: bool, | |
| 70 | output: OutputBehaviour, | |
| 71 | command: Command, | |
| 72 | reserved: u1 = 0, | |
| 73 | ||
| 74 | pub fn format(instr: Instruction, comptime fmt: []const u8, options: std.fmt.FormatOptions, out: anytype) !void { | |
| 75 | try std.fmt.format(out, "0x{x:0<4} ", .{@bitCast(u16, instr)}); | |
| 76 | try out.writeAll(switch (instr.condition) { | |
| 77 | .always => " ", | |
| 78 | .when_zero => "== 0", | |
| 79 | .not_zero => "!= 0", | |
| 80 | .greater_zero => " > 0", | |
| 81 | .less_than_zero => " < 0", | |
| 82 | .greater_or_equal_zero => ">= 0", | |
| 83 | .less_or_equal_zero => "<= 0", | |
| 84 | .overflow => "ovfl", | |
| 85 | }); | |
| 86 | try out.writeAll(" "); | |
| 87 | try out.writeAll(switch (instr.input0) { | |
| 88 | .zero => "zero", | |
| 89 | .immediate => "imm ", | |
| 90 | .peek => "peek", | |
| 91 | .pop => "pop ", | |
| 92 | }); | |
| 93 | try out.writeAll(" "); | |
| 94 | try out.writeAll(switch (instr.input1) { | |
| 95 | .zero => "zero", | |
| 96 | .immediate => "imm ", | |
| 97 | .peek => "peek", | |
| 98 | .pop => "pop ", | |
| 99 | }); | |
| 100 | try out.writeAll(" "); | |
| 101 | try out.writeAll(switch (instr.command) { | |
| 102 | .copy => "copy ", | |
| 103 | .ipget => "ipget ", | |
| 104 | .get => "get ", | |
| 105 | .set => "set ", | |
| 106 | .store8 => "store8 ", | |
| 107 | .store16 => "store16 ", | |
| 108 | .load8 => "load8 ", | |
| 109 | .load16 => "load16 ", | |
| 110 | .undefined0 => "undefined", | |
| 111 | .undefined1 => "undefined", | |
| 112 | .frget => "frget ", | |
| 113 | .frset => "frset ", | |
| 114 | .bpget => "bpget ", | |
| 115 | .bpset => "bpset ", | |
| 116 | .spget => "spget ", | |
| 117 | .spset => "spset ", | |
| 118 | .add => "add ", | |
| 119 | .sub => "sub ", | |
| 120 | .mul => "mul ", | |
| 121 | .div => "div ", | |
| 122 | .mod => "mod ", | |
| 123 | .@"and" => "and ", | |
| 124 | .@"or" => "or ", | |
| 125 | .xor => "xor ", | |
| 126 | .not => "not ", | |
| 127 | .signext => "signext ", | |
| 128 | .rol => "rol ", | |
| 129 | .ror => "ror ", | |
| 130 | .bswap => "bswap ", | |
| 131 | .asr => "asr ", | |
| 132 | .lsl => "lsl ", | |
| 133 | .lsr => "lsr ", | |
| 134 | }); | |
| 135 | try out.writeAll(" "); | |
| 136 | try out.writeAll(switch (instr.output) { | |
| 137 | .discard => "discard", | |
| 138 | .push => "push ", | |
| 139 | .jump => "jmp ", | |
| 140 | .jump_relative => "rjmp ", | |
| 141 | }); | |
| 142 | try out.writeAll(" "); | |
| 143 | try out.writeAll(if (instr.modify_flags) | |
| 144 | "+ flags" | |
| 145 | else | |
| 146 | " "); | |
| 147 | } | |
| 148 | }; | |
| 149 | ||
| 150 | pub const FlagRegister = packed struct { | |
| 151 | zero: bool, | |
| 152 | negative: bool, | |
| 153 | carry: bool, | |
| 154 | carry_enabled: bool, | |
| 155 | interrupt0_enabled: bool, | |
| 156 | interrupt1_enabled: bool, | |
| 157 | interrupt2_enabled: bool, | |
| 158 | interrupt3_enabled: bool, | |
| 159 | reserved: u8 = 0, | |
| 160 | }; | |
| 161 | ||
| 162 | pub const Register = enum { | |
| 163 | dummy, | |
| 164 | ||
| 165 | pub fn allocIndex(self: Register) ?u4 { | |
| 166 | return null; | |
| 167 | } | |
| 168 | }; | |
| 169 | ||
| 170 | pub const callee_preserved_regs = [_]Register{}; |
src/codegen/spu-mk2/interpreter.zig deleted-166| ... | ... | @@ -1,166 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const log = std.log.scoped(.SPU_2_Interpreter); | |
| 3 | const spu = @import("../spu-mk2.zig"); | |
| 4 | const FlagRegister = spu.FlagRegister; | |
| 5 | const Instruction = spu.Instruction; | |
| 6 | const ExecutionCondition = spu.ExecutionCondition; | |
| 7 | ||
| 8 | pub fn Interpreter(comptime Bus: type) type { | |
| 9 | return struct { | |
| 10 | ip: u16 = 0, | |
| 11 | sp: u16 = undefined, | |
| 12 | bp: u16 = undefined, | |
| 13 | fr: FlagRegister = @bitCast(FlagRegister, @as(u16, 0)), | |
| 14 | /// This is set to true when we hit an undefined0 instruction, allowing it to | |
| 15 | /// be used as a trap for testing purposes | |
| 16 | undefined0: bool = false, | |
| 17 | /// This is set to true when we hit an undefined1 instruction, allowing it to | |
| 18 | /// be used as a trap for testing purposes. undefined1 is used as a breakpoint. | |
| 19 | undefined1: bool = false, | |
| 20 | bus: Bus, | |
| 21 | ||
| 22 | pub fn ExecuteBlock(self: *@This(), comptime size: ?u32) !void { | |
| 23 | var count: usize = 0; | |
| 24 | while (size == null or count < size.?) { | |
| 25 | count += 1; | |
| 26 | var instruction = @bitCast(Instruction, self.bus.read16(self.ip)); | |
| 27 | ||
| 28 | log.debug("Executing {}\n", .{instruction}); | |
| 29 | ||
| 30 | self.ip +%= 2; | |
| 31 | ||
| 32 | const execute = switch (instruction.condition) { | |
| 33 | .always => true, | |
| 34 | .not_zero => !self.fr.zero, | |
| 35 | .when_zero => self.fr.zero, | |
| 36 | .overflow => self.fr.carry, | |
| 37 | ExecutionCondition.greater_or_equal_zero => !self.fr.negative, | |
| 38 | else => return error.Unimplemented, | |
| 39 | }; | |
| 40 | ||
| 41 | if (execute) { | |
| 42 | const val0 = switch (instruction.input0) { | |
| 43 | .zero => @as(u16, 0), | |
| 44 | .immediate => i: { | |
| 45 | const val = self.bus.read16(@intCast(u16, self.ip)); | |
| 46 | self.ip +%= 2; | |
| 47 | break :i val; | |
| 48 | }, | |
| 49 | else => |e| e: { | |
| 50 | // peek or pop; show value at current SP, and if pop, increment sp | |
| 51 | const val = self.bus.read16(self.sp); | |
| 52 | if (e == .pop) { | |
| 53 | self.sp +%= 2; | |
| 54 | } | |
| 55 | break :e val; | |
| 56 | }, | |
| 57 | }; | |
| 58 | const val1 = switch (instruction.input1) { | |
| 59 | .zero => @as(u16, 0), | |
| 60 | .immediate => i: { | |
| 61 | const val = self.bus.read16(@intCast(u16, self.ip)); | |
| 62 | self.ip +%= 2; | |
| 63 | break :i val; | |
| 64 | }, | |
| 65 | else => |e| e: { | |
| 66 | // peek or pop; show value at current SP, and if pop, increment sp | |
| 67 | const val = self.bus.read16(self.sp); | |
| 68 | if (e == .pop) { | |
| 69 | self.sp +%= 2; | |
| 70 | } | |
| 71 | break :e val; | |
| 72 | }, | |
| 73 | }; | |
| 74 | ||
| 75 | const output: u16 = switch (instruction.command) { | |
| 76 | .get => self.bus.read16(self.bp +% (2 *% val0)), | |
| 77 | .set => a: { | |
| 78 | self.bus.write16(self.bp +% 2 *% val0, val1); | |
| 79 | break :a val1; | |
| 80 | }, | |
| 81 | .load8 => self.bus.read8(val0), | |
| 82 | .load16 => self.bus.read16(val0), | |
| 83 | .store8 => a: { | |
| 84 | const val = @truncate(u8, val1); | |
| 85 | self.bus.write8(val0, val); | |
| 86 | break :a val; | |
| 87 | }, | |
| 88 | .store16 => a: { | |
| 89 | self.bus.write16(val0, val1); | |
| 90 | break :a val1; | |
| 91 | }, | |
| 92 | .copy => val0, | |
| 93 | .add => a: { | |
| 94 | var val: u16 = undefined; | |
| 95 | self.fr.carry = @addWithOverflow(u16, val0, val1, &val); | |
| 96 | break :a val; | |
| 97 | }, | |
| 98 | .sub => a: { | |
| 99 | var val: u16 = undefined; | |
| 100 | self.fr.carry = @subWithOverflow(u16, val0, val1, &val); | |
| 101 | break :a val; | |
| 102 | }, | |
| 103 | .spset => a: { | |
| 104 | self.sp = val0; | |
| 105 | break :a val0; | |
| 106 | }, | |
| 107 | .bpset => a: { | |
| 108 | self.bp = val0; | |
| 109 | break :a val0; | |
| 110 | }, | |
| 111 | .frset => a: { | |
| 112 | const val = (@bitCast(u16, self.fr) & val1) | (val0 & ~val1); | |
| 113 | self.fr = @bitCast(FlagRegister, val); | |
| 114 | break :a val; | |
| 115 | }, | |
| 116 | .bswap => (val0 >> 8) | (val0 << 8), | |
| 117 | .bpget => self.bp, | |
| 118 | .spget => self.sp, | |
| 119 | .ipget => self.ip +% (2 *% val0), | |
| 120 | .lsl => val0 << 1, | |
| 121 | .lsr => val0 >> 1, | |
| 122 | .@"and" => val0 & val1, | |
| 123 | .@"or" => val0 | val1, | |
| 124 | .xor => val0 ^ val1, | |
| 125 | .not => ~val0, | |
| 126 | .undefined0 => { | |
| 127 | self.undefined0 = true; | |
| 128 | // Break out of the loop, and let the caller decide what to do | |
| 129 | return; | |
| 130 | }, | |
| 131 | .undefined1 => { | |
| 132 | self.undefined1 = true; | |
| 133 | // Break out of the loop, and let the caller decide what to do | |
| 134 | return; | |
| 135 | }, | |
| 136 | .signext => if ((val0 & 0x80) != 0) | |
| 137 | (val0 & 0xFF) | 0xFF00 | |
| 138 | else | |
| 139 | (val0 & 0xFF), | |
| 140 | else => return error.Unimplemented, | |
| 141 | }; | |
| 142 | ||
| 143 | switch (instruction.output) { | |
| 144 | .discard => {}, | |
| 145 | .push => { | |
| 146 | self.sp -%= 2; | |
| 147 | self.bus.write16(self.sp, output); | |
| 148 | }, | |
| 149 | .jump => { | |
| 150 | self.ip = output; | |
| 151 | }, | |
| 152 | else => return error.Unimplemented, | |
| 153 | } | |
| 154 | if (instruction.modify_flags) { | |
| 155 | self.fr.negative = (output & 0x8000) != 0; | |
| 156 | self.fr.zero = (output == 0x0000); | |
| 157 | } | |
| 158 | } else { | |
| 159 | if (instruction.input0 == .immediate) self.ip +%= 2; | |
| 160 | if (instruction.input1 == .immediate) self.ip +%= 2; | |
| 161 | break; | |
| 162 | } | |
| 163 | } | |
| 164 | } | |
| 165 | }; | |
| 166 | } |
src/test.zig+1-114| ... | ... | @@ -862,10 +862,7 @@ pub const TestContext = struct { |
| 862 | 862 | }); |
| 863 | 863 | } else switch (case.target.getExternalExecutor()) { |
| 864 | 864 | .native => try argv.append(exe_path), |
| 865 | .unavailable => { | |
| 866 | try self.runInterpreterIfAvailable(allocator, &exec_node, case, tmp.dir, bin_name); | |
| 867 | return; // Pass test. | |
| 868 | }, | |
| 865 | .unavailable => return, // Pass test. | |
| 869 | 866 | |
| 870 | 867 | .qemu => |qemu_bin_name| if (enable_qemu) { |
| 871 | 868 | // TODO Ability for test cases to specify whether to link libc. |
| ... | ... | @@ -953,116 +950,6 @@ pub const TestContext = struct { |
| 953 | 950 | } |
| 954 | 951 | } |
| 955 | 952 | |
| 956 | fn runInterpreterIfAvailable( | |
| 957 | self: *TestContext, | |
| 958 | gpa: *Allocator, | |
| 959 | node: *std.Progress.Node, | |
| 960 | case: Case, | |
| 961 | tmp_dir: std.fs.Dir, | |
| 962 | bin_name: []const u8, | |
| 963 | ) !void { | |
| 964 | const arch = case.target.cpu_arch orelse return; | |
| 965 | switch (arch) { | |
| 966 | .spu_2 => return self.runSpu2Interpreter(gpa, node, case, tmp_dir, bin_name), | |
| 967 | else => return, | |
| 968 | } | |
| 969 | } | |
| 970 | ||
| 971 | fn runSpu2Interpreter( | |
| 972 | self: *TestContext, | |
| 973 | gpa: *Allocator, | |
| 974 | update_node: *std.Progress.Node, | |
| 975 | case: Case, | |
| 976 | tmp_dir: std.fs.Dir, | |
| 977 | bin_name: []const u8, | |
| 978 | ) !void { | |
| 979 | const spu = @import("codegen/spu-mk2.zig"); | |
| 980 | if (case.target.os_tag) |os| { | |
| 981 | if (os != .freestanding) { | |
| 982 | std.debug.panic("Only freestanding makes sense for SPU-II tests!", .{}); | |
| 983 | } | |
| 984 | } else { | |
| 985 | std.debug.panic("SPU_2 has no native OS, check the test!", .{}); | |
| 986 | } | |
| 987 | ||
| 988 | var interpreter = spu.Interpreter(struct { | |
| 989 | RAM: [0x10000]u8 = undefined, | |
| 990 | ||
| 991 | pub fn read8(bus: @This(), addr: u16) u8 { | |
| 992 | return bus.RAM[addr]; | |
| 993 | } | |
| 994 | pub fn read16(bus: @This(), addr: u16) u16 { | |
| 995 | return std.mem.readIntLittle(u16, bus.RAM[addr..][0..2]); | |
| 996 | } | |
| 997 | ||
| 998 | pub fn write8(bus: *@This(), addr: u16, val: u8) void { | |
| 999 | bus.RAM[addr] = val; | |
| 1000 | } | |
| 1001 | ||
| 1002 | pub fn write16(bus: *@This(), addr: u16, val: u16) void { | |
| 1003 | std.mem.writeIntLittle(u16, bus.RAM[addr..][0..2], val); | |
| 1004 | } | |
| 1005 | }){ | |
| 1006 | .bus = .{}, | |
| 1007 | }; | |
| 1008 | ||
| 1009 | { | |
| 1010 | var load_node = update_node.start("load", 0); | |
| 1011 | load_node.activate(); | |
| 1012 | defer load_node.end(); | |
| 1013 | ||
| 1014 | var file = try tmp_dir.openFile(bin_name, .{ .read = true }); | |
| 1015 | defer file.close(); | |
| 1016 | ||
| 1017 | const header = try std.elf.Header.read(&file); | |
| 1018 | var iterator = header.program_header_iterator(&file); | |
| 1019 | ||
| 1020 | var none_loaded = true; | |
| 1021 | ||
| 1022 | while (try iterator.next()) |phdr| { | |
| 1023 | if (phdr.p_type != std.elf.PT_LOAD) { | |
| 1024 | std.debug.print("Encountered unexpected ELF program header: type {}\n", .{phdr.p_type}); | |
| 1025 | return error.UnexpectedElfProgramHeader; | |
| 1026 | } | |
| 1027 | if (phdr.p_paddr != phdr.p_vaddr) { | |
| 1028 | std.debug.print("Physical address does not match virtual address in ELF header!\n", .{}); | |
| 1029 | return error.PhysicalAddressMismatchVirt; | |
| 1030 | } | |
| 1031 | if (phdr.p_filesz != phdr.p_memsz) { | |
| 1032 | std.debug.print("Physical size does not match virtual size in ELF header!\n", .{}); | |
| 1033 | return error.PhysicalSizeMismatchVirt; | |
| 1034 | } | |
| 1035 | if ((try file.pread(interpreter.bus.RAM[phdr.p_paddr .. phdr.p_paddr + phdr.p_filesz], phdr.p_offset)) != phdr.p_filesz) { | |
| 1036 | std.debug.print("Read less than expected from ELF file!", .{}); | |
| 1037 | return error.ElfFileEof; | |
| 1038 | } | |
| 1039 | std.log.scoped(.spu2_test).debug("Loaded 0x{x} bytes to 0x{x:0<4}\n", .{ phdr.p_filesz, phdr.p_paddr }); | |
| 1040 | none_loaded = false; | |
| 1041 | } | |
| 1042 | if (none_loaded) { | |
| 1043 | std.debug.print("No data found in ELF file!\n", .{}); | |
| 1044 | return error.EmptyElfFile; | |
| 1045 | } | |
| 1046 | } | |
| 1047 | ||
| 1048 | var exec_node = update_node.start("execute", 0); | |
| 1049 | exec_node.activate(); | |
| 1050 | defer exec_node.end(); | |
| 1051 | ||
| 1052 | var blocks: u16 = 1000; | |
| 1053 | const block_size = 1000; | |
| 1054 | while (!interpreter.undefined0) { | |
| 1055 | const pre_ip = interpreter.ip; | |
| 1056 | if (blocks > 0) { | |
| 1057 | blocks -= 1; | |
| 1058 | try interpreter.ExecuteBlock(block_size); | |
| 1059 | if (pre_ip == interpreter.ip) { | |
| 1060 | std.debug.print("Infinite loop detected in SPU II test!\n", .{}); | |
| 1061 | return error.InfiniteLoop; | |
| 1062 | } | |
| 1063 | } | |
| 1064 | } | |
| 1065 | } | |
| 1066 | 953 | }; |
| 1067 | 954 | |
| 1068 | 955 | fn dumpArgs(argv: []const []const u8) void { |
test/stage2/spu-ii.zig deleted-23| ... | ... | @@ -1,23 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const TestContext = @import("../../src/test.zig").TestContext; | |
| 3 | ||
| 4 | const spu = std.zig.CrossTarget{ | |
| 5 | .cpu_arch = .spu_2, | |
| 6 | .os_tag = .freestanding, | |
| 7 | }; | |
| 8 | ||
| 9 | pub fn addCases(ctx: *TestContext) !void { | |
| 10 | { | |
| 11 | var case = ctx.exe("SPU-II Basic Test", spu); | |
| 12 | case.addCompareOutput( | |
| 13 | \\fn killEmulator() noreturn { | |
| 14 | \\ asm volatile ("undefined0"); | |
| 15 | \\ unreachable; | |
| 16 | \\} | |
| 17 | \\ | |
| 18 | \\pub export fn _start() noreturn { | |
| 19 | \\ killEmulator(); | |
| 20 | \\} | |
| 21 | , ""); | |
| 22 | } | |
| 23 | } |
test/stage2/test.zig-1| ... | ... | @@ -13,7 +13,6 @@ const linux_x64 = std.zig.CrossTarget{ |
| 13 | 13 | |
| 14 | 14 | pub fn addCases(ctx: *TestContext) !void { |
| 15 | 15 | try @import("cbe.zig").addCases(ctx); |
| 16 | try @import("spu-ii.zig").addCases(ctx); | |
| 17 | 16 | try @import("arm.zig").addCases(ctx); |
| 18 | 17 | try @import("aarch64.zig").addCases(ctx); |
| 19 | 18 | try @import("llvm.zig").addCases(ctx); |