Commit 54f3b0a560
Changed files (10)
lib
src-self-hosted
test
stage2
lib/std/spu/defines.zig
@@ -1,158 +0,0 @@
-const std = @import("std");
-
-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,
-};
lib/std/spu.zig
@@ -1,3 +0,0 @@
-pub usingnamespace @import("spu/defines.zig");
-
-pub const interpreter = @import("spu/interpreter.zig").Interpreter;
lib/std/std.zig
@@ -80,9 +80,6 @@ pub const valgrind = @import("valgrind.zig");
pub const zig = @import("zig.zig");
pub const start = @import("start.zig");
-// TODO move this
-pub const spu = @import("spu.zig");
-
// This forces the start.zig file to be imported, and the comptime logic inside that
// file decides whether to export any appropriate start symbols.
comptime {
lib/std/target.zig
@@ -663,7 +663,8 @@ pub const Target = struct {
renderscript32,
renderscript64,
ve,
- // Non-LLVM targets go here
+ // Stage1 currently assumes that architectures above this comment
+ // map one-to-one with the ZigLLVM_ArchType enum.
spu_2,
pub fn isARM(arch: Arch) bool {
lib/std/spu/interpreter.zig → src-self-hosted/codegen/spu-mk2/interpreter.zig
@@ -1,6 +1,9 @@
const std = @import("std");
const log = std.log.scoped(.SPU_2_Interpreter);
-usingnamespace @import("defines.zig");
+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 {
@@ -32,7 +35,7 @@ pub fn Interpreter(comptime Bus: type) type {
.when_zero => self.fr.zero,
.overflow => self.fr.carry,
ExecutionCondition.greater_or_equal_zero => !self.fr.negative,
- else => return error.unimplemented,
+ else => return error.Unimplemented,
};
if (execute) {
@@ -134,7 +137,7 @@ pub fn Interpreter(comptime Bus: type) type {
(val0 & 0xFF) | 0xFF00
else
(val0 & 0xFF),
- else => return error.unimplemented,
+ else => return error.Unimplemented,
};
switch (instruction.output) {
@@ -146,7 +149,7 @@ pub fn Interpreter(comptime Bus: type) type {
.jump => {
self.ip = output;
},
- else => return error.unimplemented,
+ else => return error.Unimplemented,
}
if (instruction.modify_flags) {
self.fr.negative = (output & 0x8000) != 0;
src-self-hosted/codegen/spu-mk2.zig
@@ -1,4 +1,163 @@
-pub usingnamespace @import("std").spu;
+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,
src-self-hosted/link/Elf.zig
@@ -14,12 +14,10 @@ const leb128 = std.debug.leb;
const Package = @import("../Package.zig");
const Value = @import("../value.zig").Value;
const Type = @import("../type.zig").Type;
-const build_options = @import("build_options");
const link = @import("../link.zig");
const File = link.File;
const Elf = @This();
-const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
const default_entry_addr = 0x8000000;
// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
@@ -249,8 +247,8 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf {
.allocator = allocator,
},
.ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
- 16, 32 => .p32,
- 64 => .p64,
+ 0 ... 32 => .p32,
+ 33 ... 64 => .p64,
else => return error.UnsupportedELFArchitecture,
},
};
@@ -278,8 +276,8 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf
.file = file,
},
.ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
- 16, 32 => .p32,
- 64 => .p64,
+ 0 ... 32 => .p32,
+ 33 ... 64 => .p64,
else => return error.UnsupportedELFArchitecture,
},
.shdr_table_dirty = true,
@@ -346,7 +344,7 @@ fn getDebugLineProgramEnd(self: Elf) u32 {
/// Returns end pos of collision, if any.
fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
- const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32;
+ const small_ptr = self.ptr_width == .p32;
const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
if (start < ehdr_size)
return ehdr_size;
@@ -487,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
// TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
// we'll need to re-use that function anyway, in case the GOT grows and overlaps something
// else in virtual memory.
- const got_addr = if (self.base.options.target.cpu.arch.ptrBitWidth() == 16) @as(u32, 0x8000) else 0x4000000;
+ const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
try self.program_headers.append(self.base.allocator, .{
.p_type = elf.PT_LOAD,
.p_offset = off,
@@ -864,7 +862,7 @@ pub fn flush(self: *Elf, module: *Module) !void {
// Write the form for the compile unit, which must match the abbrev table above.
const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path);
const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path);
- const producer_strp = try self.makeDebugString(producer_string);
+ const producer_strp = try self.makeDebugString(link.producer_string);
// Currently only one compilation unit is supported, so the address range is simply
// identical to the main program header virtual address and memory size.
const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
@@ -2152,29 +2150,28 @@ pub fn deleteExport(self: *Elf, exp: Export) void {
fn writeProgHeader(self: *Elf, index: usize) !void {
const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
const offset = self.program_headers.items[index].p_offset;
- switch (self.base.options.target.cpu.arch.ptrBitWidth()) {
- 32 => {
+ switch (self.ptr_width) {
+ .p32 => {
var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};
if (foreign_endian) {
bswapAllFields(elf.Elf32_Phdr, &phdr[0]);
}
return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
},
- 64 => {
+ .p64 => {
var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};
if (foreign_endian) {
bswapAllFields(elf.Elf64_Phdr, &phdr[0]);
}
return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
},
- else => return error.UnsupportedArchitecture,
}
}
fn writeSectHeader(self: *Elf, index: usize) !void {
const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
- switch (self.base.options.target.cpu.arch.ptrBitWidth()) {
- 32 => {
+ switch (self.ptr_width) {
+ .p32 => {
var shdr: [1]elf.Elf32_Shdr = undefined;
shdr[0] = sectHeaderTo32(self.sections.items[index]);
if (foreign_endian) {
@@ -2183,7 +2180,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr);
return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
},
- 64 => {
+ .p64 => {
var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
if (foreign_endian) {
bswapAllFields(elf.Elf64_Shdr, &shdr[0]);
@@ -2191,14 +2188,13 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr);
return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
},
- else => return error.UnsupportedArchitecture,
}
}
fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
const shdr = &self.sections.items[self.got_section_index.?];
const phdr = &self.program_headers.items[self.phdr_got_index.?];
- const entry_size: u16 = self.base.options.target.cpu.arch.ptrBitWidth() / 8;
+ const entry_size: u16 = self.archPtrWidthBytes();
if (self.offset_table_count_dirty) {
// TODO Also detect virtual address collisions.
const allocated_size = self.allocatedSize(shdr.sh_offset);
@@ -2351,6 +2347,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {
}
}
+/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
fn ptrWidthBytes(self: Elf) u8 {
return switch (self.ptr_width) {
.p32 => 4,
@@ -2358,6 +2355,12 @@ fn ptrWidthBytes(self: Elf) u8 {
};
}
+/// Does not necessarily match `ptrWidthBytes` for example can be 2 bytes
+/// in a 32-bit ELF file.
+fn archPtrWidthBytes(self: Elf) u8 {
+ return @intCast(u8, self.base.options.target.cpu.arch.ptrBitWidth() / 8);
+}
+
/// The reloc offset for the virtual address of a function in its Line Number Program.
/// Size is a virtual address integer.
const dbg_line_vaddr_reloc_index = 3;
src-self-hosted/link.zig
@@ -7,7 +7,7 @@ const Package = @import("Package.zig");
const Type = @import("type.zig").Type;
const build_options = @import("build_options");
-const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
+pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
pub const Options = struct {
target: std.Target,
src-self-hosted/test.zig
@@ -571,95 +571,6 @@ pub const TestContext = struct {
std.debug.assert(!case.cbe);
update_node.estimated_total_items = 4;
- if (case.target.cpu_arch) |arch| {
- if (arch == .spu_2) {
- 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 = std.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", null);
- 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.readHeader(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});
- std.process.exit(1);
- }
- if (phdr.p_paddr != phdr.p_vaddr) {
- std.debug.print("Physical address does not match virtual address in ELF header!\n", .{});
- std.process.exit(1);
- }
- if (phdr.p_filesz != phdr.p_memsz) {
- std.debug.print("Physical size does not match virtual size in ELF header!\n", .{});
- std.process.exit(1);
- }
- 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!", .{});
- std.process.exit(1);
- }
- 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", .{});
- std.process.exit(1);
- }
- }
-
- var exec_node = update_node.start("execute", null);
- 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", .{});
- std.process.exit(1);
- }
- }
- }
- }
- }
var exec_result = x: {
var exec_node = update_node.start("execute", null);
exec_node.activate();
@@ -672,7 +583,10 @@ pub const TestContext = struct {
switch (case.target.getExternalExecutor()) {
.native => try argv.append(exe_path),
- .unavailable => return, // No executor available; pass test.
+ .unavailable => {
+ try self.runInterpreterIfAvailable(allocator, &exec_node, case, tmp.dir, bin_name);
+ return; // Pass test.
+ },
.qemu => |qemu_bin_name| if (enable_qemu) {
// TODO Ability for test cases to specify whether to link libc.
@@ -745,4 +659,115 @@ 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", null);
+ 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.readHeader(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});
+ std.process.exit(1);
+ }
+ if (phdr.p_paddr != phdr.p_vaddr) {
+ std.debug.print("Physical address does not match virtual address in ELF header!\n", .{});
+ std.process.exit(1);
+ }
+ if (phdr.p_filesz != phdr.p_memsz) {
+ std.debug.print("Physical size does not match virtual size in ELF header!\n", .{});
+ std.process.exit(1);
+ }
+ 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!", .{});
+ std.process.exit(1);
+ }
+ 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", .{});
+ std.process.exit(1);
+ }
+ }
+
+ var exec_node = update_node.start("execute", null);
+ 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", .{});
+ std.process.exit(1);
+ }
+ }
+ }
+ }
};
test/stage2/test.zig
@@ -26,6 +26,8 @@ const wasi = std.zig.CrossTarget{
pub fn addCases(ctx: *TestContext) !void {
try @import("zir.zig").addCases(ctx);
try @import("cbe.zig").addCases(ctx);
+ try @import("spu-ii.zig").addCases(ctx);
+
{
var case = ctx.exe("hello world with updates", linux_x64);
@@ -785,5 +787,4 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
\\extern var foo;
, &[_][]const u8{":4:1: error: unable to infer variable type"});
- try @import("spu-ii.zig").addCases(ctx);
}