Commit 07606d12da
Changed files (7)
src
test
stage2
src/codegen/spu-mk2/interpreter.zig
@@ -1,166 +0,0 @@
-const std = @import("std");
-const log = std.log.scoped(.SPU_2_Interpreter);
-const spu = @import("../spu-mk2.zig");
-const FlagRegister = spu.FlagRegister;
-const Instruction = spu.Instruction;
-const ExecutionCondition = spu.ExecutionCondition;
-
-pub fn Interpreter(comptime Bus: type) type {
- return struct {
- ip: u16 = 0,
- sp: u16 = undefined,
- bp: u16 = undefined,
- fr: FlagRegister = @bitCast(FlagRegister, @as(u16, 0)),
- /// This is set to true when we hit an undefined0 instruction, allowing it to
- /// be used as a trap for testing purposes
- undefined0: bool = false,
- /// This is set to true when we hit an undefined1 instruction, allowing it to
- /// be used as a trap for testing purposes. undefined1 is used as a breakpoint.
- undefined1: bool = false,
- bus: Bus,
-
- pub fn ExecuteBlock(self: *@This(), comptime size: ?u32) !void {
- var count: usize = 0;
- while (size == null or count < size.?) {
- count += 1;
- var instruction = @bitCast(Instruction, self.bus.read16(self.ip));
-
- log.debug("Executing {}\n", .{instruction});
-
- self.ip +%= 2;
-
- const execute = switch (instruction.condition) {
- .always => true,
- .not_zero => !self.fr.zero,
- .when_zero => self.fr.zero,
- .overflow => self.fr.carry,
- ExecutionCondition.greater_or_equal_zero => !self.fr.negative,
- else => return error.Unimplemented,
- };
-
- if (execute) {
- const val0 = switch (instruction.input0) {
- .zero => @as(u16, 0),
- .immediate => i: {
- const val = self.bus.read16(@intCast(u16, self.ip));
- self.ip +%= 2;
- break :i val;
- },
- else => |e| e: {
- // peek or pop; show value at current SP, and if pop, increment sp
- const val = self.bus.read16(self.sp);
- if (e == .pop) {
- self.sp +%= 2;
- }
- break :e val;
- },
- };
- const val1 = switch (instruction.input1) {
- .zero => @as(u16, 0),
- .immediate => i: {
- const val = self.bus.read16(@intCast(u16, self.ip));
- self.ip +%= 2;
- break :i val;
- },
- else => |e| e: {
- // peek or pop; show value at current SP, and if pop, increment sp
- const val = self.bus.read16(self.sp);
- if (e == .pop) {
- self.sp +%= 2;
- }
- break :e val;
- },
- };
-
- const output: u16 = switch (instruction.command) {
- .get => self.bus.read16(self.bp +% (2 *% val0)),
- .set => a: {
- self.bus.write16(self.bp +% 2 *% val0, val1);
- break :a val1;
- },
- .load8 => self.bus.read8(val0),
- .load16 => self.bus.read16(val0),
- .store8 => a: {
- const val = @truncate(u8, val1);
- self.bus.write8(val0, val);
- break :a val;
- },
- .store16 => a: {
- self.bus.write16(val0, val1);
- break :a val1;
- },
- .copy => val0,
- .add => a: {
- var val: u16 = undefined;
- self.fr.carry = @addWithOverflow(u16, val0, val1, &val);
- break :a val;
- },
- .sub => a: {
- var val: u16 = undefined;
- self.fr.carry = @subWithOverflow(u16, val0, val1, &val);
- break :a val;
- },
- .spset => a: {
- self.sp = val0;
- break :a val0;
- },
- .bpset => a: {
- self.bp = val0;
- break :a val0;
- },
- .frset => a: {
- const val = (@bitCast(u16, self.fr) & val1) | (val0 & ~val1);
- self.fr = @bitCast(FlagRegister, val);
- break :a val;
- },
- .bswap => (val0 >> 8) | (val0 << 8),
- .bpget => self.bp,
- .spget => self.sp,
- .ipget => self.ip +% (2 *% val0),
- .lsl => val0 << 1,
- .lsr => val0 >> 1,
- .@"and" => val0 & val1,
- .@"or" => val0 | val1,
- .xor => val0 ^ val1,
- .not => ~val0,
- .undefined0 => {
- self.undefined0 = true;
- // Break out of the loop, and let the caller decide what to do
- return;
- },
- .undefined1 => {
- self.undefined1 = true;
- // Break out of the loop, and let the caller decide what to do
- return;
- },
- .signext => if ((val0 & 0x80) != 0)
- (val0 & 0xFF) | 0xFF00
- else
- (val0 & 0xFF),
- else => return error.Unimplemented,
- };
-
- switch (instruction.output) {
- .discard => {},
- .push => {
- self.sp -%= 2;
- self.bus.write16(self.sp, output);
- },
- .jump => {
- self.ip = output;
- },
- else => return error.Unimplemented,
- }
- if (instruction.modify_flags) {
- self.fr.negative = (output & 0x8000) != 0;
- self.fr.zero = (output == 0x0000);
- }
- } else {
- if (instruction.input0 == .immediate) self.ip +%= 2;
- if (instruction.input1 == .immediate) self.ip +%= 2;
- break;
- }
- }
- }
- };
-}
src/codegen/spu-mk2.zig
@@ -1,170 +0,0 @@
-const std = @import("std");
-
-pub const Interpreter = @import("spu-mk2/interpreter.zig").Interpreter;
-
-pub const ExecutionCondition = enum(u3) {
- always = 0,
- when_zero = 1,
- not_zero = 2,
- greater_zero = 3,
- less_than_zero = 4,
- greater_or_equal_zero = 5,
- less_or_equal_zero = 6,
- overflow = 7,
-};
-
-pub const InputBehaviour = enum(u2) {
- zero = 0,
- immediate = 1,
- peek = 2,
- pop = 3,
-};
-
-pub const OutputBehaviour = enum(u2) {
- discard = 0,
- push = 1,
- jump = 2,
- jump_relative = 3,
-};
-
-pub const Command = enum(u5) {
- copy = 0,
- ipget = 1,
- get = 2,
- set = 3,
- store8 = 4,
- store16 = 5,
- load8 = 6,
- load16 = 7,
- undefined0 = 8,
- undefined1 = 9,
- frget = 10,
- frset = 11,
- bpget = 12,
- bpset = 13,
- spget = 14,
- spset = 15,
- add = 16,
- sub = 17,
- mul = 18,
- div = 19,
- mod = 20,
- @"and" = 21,
- @"or" = 22,
- xor = 23,
- not = 24,
- signext = 25,
- rol = 26,
- ror = 27,
- bswap = 28,
- asr = 29,
- lsl = 30,
- lsr = 31,
-};
-
-pub const Instruction = packed struct {
- condition: ExecutionCondition,
- input0: InputBehaviour,
- input1: InputBehaviour,
- modify_flags: bool,
- output: OutputBehaviour,
- command: Command,
- reserved: u1 = 0,
-
- pub fn format(instr: Instruction, comptime fmt: []const u8, options: std.fmt.FormatOptions, out: anytype) !void {
- try std.fmt.format(out, "0x{x:0<4} ", .{@bitCast(u16, instr)});
- try out.writeAll(switch (instr.condition) {
- .always => " ",
- .when_zero => "== 0",
- .not_zero => "!= 0",
- .greater_zero => " > 0",
- .less_than_zero => " < 0",
- .greater_or_equal_zero => ">= 0",
- .less_or_equal_zero => "<= 0",
- .overflow => "ovfl",
- });
- try out.writeAll(" ");
- try out.writeAll(switch (instr.input0) {
- .zero => "zero",
- .immediate => "imm ",
- .peek => "peek",
- .pop => "pop ",
- });
- try out.writeAll(" ");
- try out.writeAll(switch (instr.input1) {
- .zero => "zero",
- .immediate => "imm ",
- .peek => "peek",
- .pop => "pop ",
- });
- try out.writeAll(" ");
- try out.writeAll(switch (instr.command) {
- .copy => "copy ",
- .ipget => "ipget ",
- .get => "get ",
- .set => "set ",
- .store8 => "store8 ",
- .store16 => "store16 ",
- .load8 => "load8 ",
- .load16 => "load16 ",
- .undefined0 => "undefined",
- .undefined1 => "undefined",
- .frget => "frget ",
- .frset => "frset ",
- .bpget => "bpget ",
- .bpset => "bpset ",
- .spget => "spget ",
- .spset => "spset ",
- .add => "add ",
- .sub => "sub ",
- .mul => "mul ",
- .div => "div ",
- .mod => "mod ",
- .@"and" => "and ",
- .@"or" => "or ",
- .xor => "xor ",
- .not => "not ",
- .signext => "signext ",
- .rol => "rol ",
- .ror => "ror ",
- .bswap => "bswap ",
- .asr => "asr ",
- .lsl => "lsl ",
- .lsr => "lsr ",
- });
- try out.writeAll(" ");
- try out.writeAll(switch (instr.output) {
- .discard => "discard",
- .push => "push ",
- .jump => "jmp ",
- .jump_relative => "rjmp ",
- });
- try out.writeAll(" ");
- try out.writeAll(if (instr.modify_flags)
- "+ flags"
- else
- " ");
- }
-};
-
-pub const FlagRegister = packed struct {
- zero: bool,
- negative: bool,
- carry: bool,
- carry_enabled: bool,
- interrupt0_enabled: bool,
- interrupt1_enabled: bool,
- interrupt2_enabled: bool,
- interrupt3_enabled: bool,
- reserved: u8 = 0,
-};
-
-pub const Register = enum {
- dummy,
-
- pub fn allocIndex(self: Register) ?u4 {
- return null;
- }
-};
-
-pub const callee_preserved_regs = [_]Register{};
src/codegen.zig
@@ -117,7 +117,6 @@ pub fn generateSymbol(
//.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
//.sparcel => return Function(.sparcel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
//.s390x => return Function(.s390x).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
- .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
//.tce => return Function(.tce).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
//.tcele => return Function(.tcele).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
//.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 {
.riscv64 => {
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ebreak.toU32());
},
- .spu_2 => {
- try self.code.resize(self.code.items.len + 2);
- var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined1 };
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr));
- },
.arm, .armeb => {
writeInt(u32, try self.code.addManyAsArray(4), Instruction.bkpt(0).toU32());
},
@@ -2317,53 +2311,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
}
},
- .spu_2 => {
- if (inst.func.value()) |func_value| {
- if (info.args.len != 0) {
- return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{});
- }
- if (func_value.castTag(.function)) |func_payload| {
- const func = func_payload.data;
- const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
- const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
- break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2);
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file|
- @intCast(u16, coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * 2)
- else
- unreachable;
-
- assert(func.owner_decl.has_tv);
- const return_type = func.owner_decl.ty.fnReturnType();
- // First, push the return address, then jump; if noreturn, don't bother with the first step
- // TODO: implement packed struct -> u16 at comptime and move the bitcast here
- var instr = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .jump, .command = .load16 };
- if (return_type.zigTypeTag() == .NoReturn) {
- try self.code.resize(self.code.items.len + 4);
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr));
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr);
- return MCValue.unreach;
- } else {
- try self.code.resize(self.code.items.len + 8);
- var push = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .push, .command = .ipget };
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 8 ..][0..2], @bitCast(u16, push));
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 6 ..][0..2], @as(u16, 4));
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr));
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr);
- switch (return_type.zigTypeTag()) {
- .Void => return MCValue{ .none = {} },
- .NoReturn => unreachable,
- else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}),
- }
- }
- } else if (func_value.castTag(.extern_fn)) |_| {
- return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
- } else {
- return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
- }
- } else {
- return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
- }
- },
.arm, .armeb => {
for (info.args) |mc_arg, arg_i| {
const arg = inst.args[arg_i];
@@ -3176,19 +3123,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
if (!inst.is_volatile and inst.base.isUnused())
return MCValue.dead;
switch (arch) {
- .spu_2 => {
- if (inst.inputs.len > 0 or inst.output_constraint != null) {
- return self.fail(inst.base.src, "TODO implement inline asm inputs / outputs for SPU Mark II", .{});
- }
- if (mem.eql(u8, inst.asm_source, "undefined0")) {
- try self.code.resize(self.code.items.len + 2);
- var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined0 };
- mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr));
- return MCValue.none;
- } else {
- return self.fail(inst.base.src, "TODO implement support for more SPU II assembly instructions", .{});
- }
- },
.arm, .armeb => {
for (inst.inputs) |input, i| {
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 {
.i386 => @import("codegen/x86.zig"),
.x86_64 => @import("codegen/x86_64.zig"),
.riscv64 => @import("codegen/riscv64.zig"),
- .spu_2 => @import("codegen/spu-mk2.zig"),
.arm, .armeb => @import("codegen/arm.zig"),
.aarch64, .aarch64_be, .aarch64_32 => @import("codegen/aarch64.zig"),
else => struct {
src/test.zig
@@ -862,10 +862,7 @@ pub const TestContext = struct {
});
} else switch (case.target.getExternalExecutor()) {
.native => try argv.append(exe_path),
- .unavailable => {
- try self.runInterpreterIfAvailable(allocator, &exec_node, case, tmp.dir, bin_name);
- return; // Pass test.
- },
+ .unavailable => return, // Pass test.
.qemu => |qemu_bin_name| if (enable_qemu) {
// TODO Ability for test cases to specify whether to link libc.
@@ -953,116 +950,6 @@ pub const TestContext = struct {
}
}
- fn runInterpreterIfAvailable(
- self: *TestContext,
- gpa: *Allocator,
- node: *std.Progress.Node,
- case: Case,
- tmp_dir: std.fs.Dir,
- bin_name: []const u8,
- ) !void {
- const arch = case.target.cpu_arch orelse return;
- switch (arch) {
- .spu_2 => return self.runSpu2Interpreter(gpa, node, case, tmp_dir, bin_name),
- else => return,
- }
- }
-
- fn runSpu2Interpreter(
- self: *TestContext,
- gpa: *Allocator,
- update_node: *std.Progress.Node,
- case: Case,
- tmp_dir: std.fs.Dir,
- bin_name: []const u8,
- ) !void {
- const spu = @import("codegen/spu-mk2.zig");
- if (case.target.os_tag) |os| {
- if (os != .freestanding) {
- std.debug.panic("Only freestanding makes sense for SPU-II tests!", .{});
- }
- } else {
- std.debug.panic("SPU_2 has no native OS, check the test!", .{});
- }
-
- var interpreter = spu.Interpreter(struct {
- RAM: [0x10000]u8 = undefined,
-
- pub fn read8(bus: @This(), addr: u16) u8 {
- return bus.RAM[addr];
- }
- pub fn read16(bus: @This(), addr: u16) u16 {
- return std.mem.readIntLittle(u16, bus.RAM[addr..][0..2]);
- }
-
- pub fn write8(bus: *@This(), addr: u16, val: u8) void {
- bus.RAM[addr] = val;
- }
-
- pub fn write16(bus: *@This(), addr: u16, val: u16) void {
- std.mem.writeIntLittle(u16, bus.RAM[addr..][0..2], val);
- }
- }){
- .bus = .{},
- };
-
- {
- var load_node = update_node.start("load", 0);
- load_node.activate();
- defer load_node.end();
-
- var file = try tmp_dir.openFile(bin_name, .{ .read = true });
- defer file.close();
-
- const header = try std.elf.Header.read(&file);
- var iterator = header.program_header_iterator(&file);
-
- var none_loaded = true;
-
- while (try iterator.next()) |phdr| {
- if (phdr.p_type != std.elf.PT_LOAD) {
- std.debug.print("Encountered unexpected ELF program header: type {}\n", .{phdr.p_type});
- return error.UnexpectedElfProgramHeader;
- }
- if (phdr.p_paddr != phdr.p_vaddr) {
- std.debug.print("Physical address does not match virtual address in ELF header!\n", .{});
- return error.PhysicalAddressMismatchVirt;
- }
- if (phdr.p_filesz != phdr.p_memsz) {
- std.debug.print("Physical size does not match virtual size in ELF header!\n", .{});
- return error.PhysicalSizeMismatchVirt;
- }
- if ((try file.pread(interpreter.bus.RAM[phdr.p_paddr .. phdr.p_paddr + phdr.p_filesz], phdr.p_offset)) != phdr.p_filesz) {
- std.debug.print("Read less than expected from ELF file!", .{});
- return error.ElfFileEof;
- }
- std.log.scoped(.spu2_test).debug("Loaded 0x{x} bytes to 0x{x:0<4}\n", .{ phdr.p_filesz, phdr.p_paddr });
- none_loaded = false;
- }
- if (none_loaded) {
- std.debug.print("No data found in ELF file!\n", .{});
- return error.EmptyElfFile;
- }
- }
-
- var exec_node = update_node.start("execute", 0);
- exec_node.activate();
- defer exec_node.end();
-
- var blocks: u16 = 1000;
- const block_size = 1000;
- while (!interpreter.undefined0) {
- const pre_ip = interpreter.ip;
- if (blocks > 0) {
- blocks -= 1;
- try interpreter.ExecuteBlock(block_size);
- if (pre_ip == interpreter.ip) {
- std.debug.print("Infinite loop detected in SPU II test!\n", .{});
- return error.InfiniteLoop;
- }
- }
- }
- }
};
fn dumpArgs(argv: []const []const u8) void {
test/stage2/spu-ii.zig
@@ -1,23 +0,0 @@
-const std = @import("std");
-const TestContext = @import("../../src/test.zig").TestContext;
-
-const spu = std.zig.CrossTarget{
- .cpu_arch = .spu_2,
- .os_tag = .freestanding,
-};
-
-pub fn addCases(ctx: *TestContext) !void {
- {
- var case = ctx.exe("SPU-II Basic Test", spu);
- case.addCompareOutput(
- \\fn killEmulator() noreturn {
- \\ asm volatile ("undefined0");
- \\ unreachable;
- \\}
- \\
- \\pub export fn _start() noreturn {
- \\ killEmulator();
- \\}
- , "");
- }
-}
test/stage2/test.zig
@@ -13,7 +13,6 @@ const linux_x64 = std.zig.CrossTarget{
pub fn addCases(ctx: *TestContext) !void {
try @import("cbe.zig").addCases(ctx);
- try @import("spu-ii.zig").addCases(ctx);
try @import("arm.zig").addCases(ctx);
try @import("aarch64.zig").addCases(ctx);
try @import("llvm.zig").addCases(ctx);
BRANCH_TODO
@@ -1,5 +1,3 @@
- * get stage2 tests passing
- - spu-ii test is saying "unimplemented" for some reason
* modify stage2 tests so that only 1 uses _start and the rest use
pub fn main
* modify stage2 CBE tests so that only 1 uses pub export main and the