diff --git a/build.zig b/build.zig index 95d3d18f..c3bc308a 100644 --- a/build.zig +++ b/build.zig @@ -230,16 +230,16 @@ pub fn build(b: *std.Build) void { }; const apps: []const AppDef = &.{ - .{ .name = "init.ashex", .exe = get_named_file(os_files, "apps/init.elf") }, - .{ .name = "hello-world.ashex", .exe = get_named_file(os_files, "apps/hello-world.elf") }, - .{ .name = "mtg-counter.ashex", .exe = get_named_file(os_files, "apps/mtg-counter.elf") }, - .{ .name = "hello-fb.ashex", .exe = get_named_file(os_files, "apps/hello-fb.elf") }, - .{ .name = "classic.ashex", .exe = get_named_file(os_files, "apps/desktop/classic.elf") }, - .{ .name = "dungeon.ashex", .exe = get_named_file(os_files, "apps/dungeon.elf") }, - .{ .name = "ntp-client.ashex", .exe = get_named_file(os_files, "apps/ntp-client.elf") }, - .{ .name = "i2c-scan.ashex", .exe = get_named_file(os_files, "apps/i2c-scan.elf") }, - .{ .name = "widgets.ashex", .exe = get_named_file(os_files, "apps/widgets.elf") }, - .{ .name = "2048.ashex", .exe = get_named_file(os_files, "apps/2048.elf") }, + // .{ .name = "init.ashex", .exe = get_named_file(os_files, "apps/init.elf") }, + // .{ .name = "hello-world.ashex", .exe = get_named_file(os_files, "apps/hello-world.elf") }, + // .{ .name = "mtg-counter.ashex", .exe = get_named_file(os_files, "apps/mtg-counter.elf") }, + // .{ .name = "hello-fb.ashex", .exe = get_named_file(os_files, "apps/hello-fb.elf") }, + // .{ .name = "classic.ashex", .exe = get_named_file(os_files, "apps/desktop/classic.elf") }, + // .{ .name = "dungeon.ashex", .exe = get_named_file(os_files, "apps/dungeon.elf") }, + // .{ .name = "ntp-client.ashex", .exe = get_named_file(os_files, "apps/ntp-client.elf") }, + // .{ .name = "i2c-scan.ashex", .exe = get_named_file(os_files, "apps/i2c-scan.elf") }, + // .{ .name = "widgets.ashex", .exe = get_named_file(os_files, "apps/widgets.elf") }, + // .{ .name = "2048.ashex", .exe = get_named_file(os_files, "apps/2048.elf") }, }; var variables = Variables{ @@ -410,6 +410,9 @@ const platform_info_map = std.EnumArray(Platform, PlatformStartupConfig).init(.{ .rv32 = .{ .qemu_exe = "qemu-system-riscv32", }, + .ppc = .{ + .qemu_exe = "qemu-system-ppc", + }, }); const machine_info_map = std.EnumArray(RunTarget, MachineStartupConfig).init(.{ @@ -535,6 +538,10 @@ const machine_info_map = std.EnumArray(RunTarget, MachineStartupConfig).init(.{ }), }, + .@"ppc-nintendo-gc" = .{ + // TODO + }, + // .@"pc-efi" = .{ // .qemu_cli = &.{ // "-cpu", "qemu64", @@ -637,6 +644,8 @@ pub const RunTarget = enum { @"x86-pc-generic-bios", @"x86-pc-generic-uefi", + @"ppc-nintendo-gc", + pub fn get_machine(rt: RunTarget) Machine { return switch (rt) { .@"x86-pc-generic-bios" => .@"x86-pc-generic", diff --git a/src/abi/src/platforms.zig b/src/abi/src/platforms.zig index 67267337..abdac1e2 100644 --- a/src/abi/src/platforms.zig +++ b/src/abi/src/platforms.zig @@ -4,6 +4,7 @@ pub const Platform = enum { x86, arm, rv32, + ppc, /// Returns the display name for the current platform. pub fn get_display_name(target: Platform) []const u8 { @@ -21,6 +22,7 @@ const app_display_name_map = std.EnumArray(Platform, []const u8).init(.{ .x86 = "Intel x86", .arm = "Arm 32-bit", .rv32 = "RISC-V 32-bit", + .ppc = "PowerPC 32-bit", }); const build = struct { @@ -90,5 +92,14 @@ const build = struct { .reserve_x4, // Don't allow LLVM to use the "tp" register. We want that for our own purposes }), }), + + .ppc = constructTargetQuery(.{ + .cpu_arch = .powerpc, + .abi = .eabihf, + .cpu_model = .{ .explicit = &std.Target.powerpc.cpu.generic }, + .cpu_features_add = std.Target.powerpc.featureSet(&.{ + .hard_float, + }), + }), }); }; diff --git a/src/kernel/build.zig b/src/kernel/build.zig index 546880a3..4364153f 100644 --- a/src/kernel/build.zig +++ b/src/kernel/build.zig @@ -403,6 +403,9 @@ const platform_info_map = std.EnumArray(Platform, PlatformConfig).init(.{ .rv32 = .{ .source_file = "port/platform/riscv.zig", }, + .ppc = .{ + .source_file = "port/platform/ppc.zig", + }, }); const machine_info_map = std.EnumArray(Machine, MachineConfig).init(.{ @@ -471,6 +474,21 @@ const machine_info_map = std.EnumArray(Machine, MachineConfig).init(.{ .source_file = "port/machine/x86/hosted-windows/hosted-windows.zig", .linker_script = "port/machine/x86/hosted-windows/linker.ld", }, + + .@"ppc-nintendo-gc" = .{ + .target = constructTargetQuery(.{ + .cpu_arch = .powerpc, + .abi = .eabihf, + .cpu_model = .{ .explicit = &std.Target.powerpc.cpu.@"750" }, + .cpu_features_add = std.Target.powerpc.featureSet(&.{ + .hard_float, + // .privileged, + }), + }), + + .source_file = "port/machine/ppc/nintendo-gc/nintendo-gc.zig", + .linker_script = "port/machine/ppc/nintendo-gc/linker.ld", + }, }); const generic_x86: std.Target.Query = .{ diff --git a/src/kernel/components/loader/ashex.zig b/src/kernel/components/loader/ashex.zig index 2807b7db..1f7aee39 100644 --- a/src/kernel/components/loader/ashex.zig +++ b/src/kernel/components/loader/ashex.zig @@ -247,6 +247,7 @@ fn parse_header(header_chunk: *const [512]u8) !ashex.Header { .riscv32 => .{ .machine32_le, .riscv32 }, .x86 => .{ .machine32_le, .x86 }, .arm, .thumb => .{ .machine32_le, .arm32 }, + .powerpc => .{ .machine32_be, .ppc }, else => @compileError("Unsupported machine type: " ++ @tagName(system_arch)), }; diff --git a/src/kernel/components/scheduler.zig b/src/kernel/components/scheduler.zig index 56cec635..2d729338 100644 --- a/src/kernel/components/scheduler.zig +++ b/src/kernel/components/scheduler.zig @@ -104,6 +104,7 @@ const scheduler_cc: std.builtin.CallingConvention = switch (builtin.cpu.arch) { .{ .x86_sysv = .{} }, .thumb => .{ .arm_aapcs = .{} }, .riscv32 => .{ .riscv32_ilp32 = .{} }, + .powerpc => .{ .powerpc_sysv = .{} }, else => @compileError("unsupported platform"), }; @@ -359,6 +360,10 @@ pub const Thread = struct { thread.push(@intFromPtr(arg)); // r0 }, + .powerpc => { + @panic("OH SHIT"); + }, + else => @compileError(std.fmt.comptimePrint("{s} is not a supported platform", .{@tagName(target)})), } @@ -1058,6 +1063,20 @@ comptime { \\ .word ashet_scheduler_restore_thread ), + .powerpc => ( + // TODO + \\ + \\.global ashet_scheduler_threadTrampoline + \\.type ashet_scheduler_threadTrampoline, %function + \\ashet_scheduler_threadTrampoline: + \\ trap + \\ + \\.global ashet_scheduler_switchTasks + \\.type ashet_scheduler_switchTasks, %function + \\ashet_scheduler_switchTasks: + \\ trap + ), + else => @compileError(std.fmt.comptimePrint("{s} is not a supported platform", .{@tagName(target)})), }; diff --git a/src/kernel/main.zig b/src/kernel/main.zig index 2649ee37..a4aec56c 100644 --- a/src/kernel/main.zig +++ b/src/kernel/main.zig @@ -41,6 +41,7 @@ else switch (platform_id) { .rv32 => @import("port/platform/rv32.zig"), .arm => @import("port/platform/arm.zig"), .x86 => @import("port/platform/x86.zig"), + .ppc => @import("port/platform/ppc.zig"), }; pub const machine = switch (machine_id) { @@ -50,6 +51,7 @@ pub const machine = switch (machine_id) { .@"arm-ashet-hc" => @import("port/machine/arm/ashet-hc/ashet-hc.zig"), .@"arm-ashet-vhc" => @import("port/machine/arm/ashet-vhc/ashet-vhc.zig"), .@"arm-qemu-virt" => @import("port/machine/arm/qemu-virt/arm-qemu-virt.zig"), + .@"ppc-nintendo-gc" => @import("port/machine/ppc/nintendo-gc/nintendo-gc.zig"), .@"x86-hosted-linux" => @import("port/machine/x86/hosted-linux/hosted-linux.zig"), .@"x86-hosted-windows" => @import("port/machine/x86/hosted-windows/hosted-windows.zig"), }; diff --git a/src/kernel/port/machine/ppc/nintendo-gc/linker.ld b/src/kernel/port/machine/ppc/nintendo-gc/linker.ld new file mode 100644 index 00000000..8ed30056 --- /dev/null +++ b/src/kernel/port/machine/ppc/nintendo-gc/linker.ld @@ -0,0 +1,120 @@ + +/* + * Linkscript for GC + * + */ + +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc"); +OUTPUT_ARCH(powerpc:common); +EXTERN(_start); +ENTRY(_start); + +PHDRS +{ + stub PT_LOAD FLAGS(5); + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(6); + bss PT_LOAD; +} + + +/* MEMORY +{ + sram (RWX) : ORIGIN = 0x00000000, LENGTH = 32M + dram (RWX) : ORIGIN = 0x80000000, LENGTH = 2M +} */ + +SECTIONS +{ + . = 0x80003100; + + __kernel_flash_start = .; + + /* Program */ + .init : + { + KEEP (*(.zgc_bootstrap)) + KEEP (*(.init)) + } :text = 0 + + .text : + { + *(.text*) + } :text = 0 + + . = ALIGN(4096); + + .rodata : + { + *(.rodata*) + *(.rodata1) + } :data + + __kernel_flash_end = .; + + . = ALIGN(4096); + + .data : + { + __kernel_data_start = .; + *(.data*) + __sdata_start = .; + *(.sdata) *(.sdata.*) + __sdata2_start = .; + *(.sdata2*) + *(.data1) + __kernel_data_end = .; + } + + .eh_frame : + { + KEEP (*(.eh_frame)) + } + + .got : + { + *(.got*) + } + + . = ALIGN(4096); + + .bss ALIGN(32) : + { + __kernel_bss_start = .; + *(.sbss2*) + *(.dynsbss) + *(.sbss) *(.sbss.*) + *(.scommon) + . = ALIGN(4); /* Ensure section size is multiple of 4 bytes */ + *(.dynbss) + *(.bss) *(.bss.*) + *(COMMON) + . = ALIGN(4096); + __kernel_bss_end = .; + } :bss + + . = ALIGN(4096); + + __kernel_stack_start = .; + . += 0x20000; + __kernel_stack_end = .; + + . = ALIGN(4096); + + __machine_linmem_start = .; + __machine_linmem_end = 0x817FE000; + + __machine_linmem_length = __machine_linmem_end - __machine_linmem_start; + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_str 0 : { *(.debug_str) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_line 0 : { *(.debug_line) } + /* These must appear regardless of . */ +} + diff --git a/src/kernel/port/machine/ppc/nintendo-gc/nintendo-gc.zig b/src/kernel/port/machine/ppc/nintendo-gc/nintendo-gc.zig new file mode 100644 index 00000000..c3a57016 --- /dev/null +++ b/src/kernel/port/machine/ppc/nintendo-gc/nintendo-gc.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const ashet = @import("../../../../main.zig"); +const ppc = ashet.ports.platforms.ppc; +const logger = std.log.scoped(.@"nintendo-gc"); + +pub const machine_config = ashet.ports.MachineConfig{ + .load_sections = .{ .data = false, .bss = false }, + .memory_protection = null, + .initialize = initialize, + .early_initialize = null, + .debug_write = debug_write, + .get_linear_memory_region = get_linear_memory_region, + .get_tick_count_ms = get_tick_count_ms, + .halt = null, +}; + +const hw = struct { + //! list of fixed hardware components + + var rtc: ashet.drivers.rtc.Dummy_RTC = undefined; +}; + +fn get_tick_count_ms() u64 { // return value in ms + return 0; // TODO +} + +fn initialize() !void { + // TODO: Setup machine + + hw.rtc = .init(1778338669 * std.time.ns_per_s); + + // Finally install all drivers: + ashet.drivers.install(&hw.rtc.driver); +} + +noinline fn debug_write(msg: []const u8) void { + for (msg) |c| { + _ = c; //TODO + } +} + +extern const __machine_linmem_start: anyopaque align(4); +extern const __machine_linmem_length: anyopaque align(4); + +fn get_linear_memory_region() ashet.memory.Range { + return .{ + .base = @intFromPtr(&__machine_linmem_start), + .length = @intFromPtr(&__machine_linmem_length), + }; +} diff --git a/src/kernel/port/machine_id.zig b/src/kernel/port/machine_id.zig index 4bf5bc78..6e4ee7ad 100644 --- a/src/kernel/port/machine_id.zig +++ b/src/kernel/port/machine_id.zig @@ -24,7 +24,7 @@ pub const MachineID = enum { @"x86-pc-generic", // @"x86-pc-uefi", // TODO: Find better name for the UEFI executable kernel - // @"ppc-nintendo-gamecube", + @"ppc-nintendo-gc", pub fn is_hosted(target: MachineID) bool { return switch (target) { @@ -34,6 +34,7 @@ pub const MachineID = enum { .@"rv32-qemu-virt", .@"rv32-ashet-base", .@"x86-pc-generic", + .@"ppc-nintendo-gc", => false, .@"x86-hosted-linux", @@ -52,6 +53,7 @@ pub const MachineID = enum { .@"x86-hosted-linux" => "OS Hosted (x86, Linux)", .@"x86-hosted-windows" => "OS Hosted (x86, Windows)", .@"x86-pc-generic" => "Generic PC (x86)", + .@"ppc-nintendo-gc" => "Nintendo GameCube", }; } @@ -70,6 +72,9 @@ pub const MachineID = enum { .@"x86-hosted-windows", .@"x86-pc-generic", => .x86, + + .@"ppc-nintendo-gc", + => .ppc, }; } diff --git a/src/kernel/port/platform/ppc.zig b/src/kernel/port/platform/ppc.zig new file mode 100644 index 00000000..bf30eed9 --- /dev/null +++ b/src/kernel/port/platform/ppc.zig @@ -0,0 +1,381 @@ +const std = @import("std"); + +const registers = @import("ppc/registers.zig"); +pub const cpu = @import("ppc/cpu.zig"); +pub const cache = @import("ppc/cache.zig"); +pub const memory = @import("ppc/memory.zig"); + +pub const page_size = 4096; + +pub const scheduler = struct { + // +}; + +pub const start = struct { + comptime { + // the startup routine must be written in assembler to + // guarantee that no stack and register is touched is used until + // we saved + asm ( + \\hang: + \\ trap + \\ + ); + + _ = kernel_startup; + _ = kernel_initBATS; + _ = kernel_configBATS; + _ = kernel_initGPRS; + _ = kernel_initHardware; + _ = kernel_initPS; + _ = kernel_initSystem; + } + + export fn _start() linksection(".zgc_bootstrap") callconv(.naked) noreturn { + asm volatile ("b kernel_startup"); + } + + export fn kernel_startup() callconv(.naked) noreturn { + asm volatile ( + \\bl kernel_initBATS # Initialize BATs to a clear and known state + \\bl kernel_initStack # Initialize Stack + \\bl kernel_initGPRS # Initialize the General Purpose Registers + \\bl kernel_initHardware # Initialize some aspects of the Hardware + \\bl kernel_initSystem # Initialize more cache aspects, clear a few SPR's, and disable interrupts. + \\ + \\b ashet_kernelMain # Branch to the user code! + ); + } + + /// Initializes the Block Address Translation subsystem. + /// This is done by turning BATs off, configuring it, and turning it back on. + export fn kernel_initBATS() callconv(.naked) noreturn { + asm volatile ( + \\# Store LR to r31 and add 0x8000000 + \\mflr %r31 + \\oris %r31, %r31, 0x8000 + \\// Write the address of configBATS to r3 + \\lis %r3, kernel_configBATS@h + \\ori %r3, %r3, kernel_configBATS@l + \\// Jump to configBATS in realmode + \\bl __realmode + \\// Restore LR + \\mtlr %r31 + \\blr + \\ + \\__realmode: + \\clrlwi %r3, %r3, 2 # Clear the 2 left most bits of r3 + \\mtsrr0 %r3 # Write r3 to srr0 + \\mfmsr %r3 # write MSR (Machine State Register) to r3 + \\rlwinm %r3, %r3, 0, 28, 25 # Clear bits 26 (instruction address translation) and 27 (data address translation) of the MSR (3) + \\mtsrr1 %r3 # Write MSR (r3) to srr1 + \\rfi # Return from Interop, which will set LR to the passed method originally in r3, and disable adress translation + ); + } + + /// Configures the Block Address Translation subsystem. + export fn kernel_configBATS() callconv(.naked) noreturn { + //@setOptimizeMode(.ReleaseSmall); + registers.HID0.write(.{ + .bht = true, //branch history table + .btic = true, //branch target instruction cache + .dcfa = true, //data cache flush assist + .dcfi = true, //date cache flash invalidate + .icfi = true, //instruction cache flash invalidate + .nhr = true, //not hard reset + .dpm = true, //dynamic power management + }); + cpu.isync(); + + // Clear all bits on all BATs + // This is REQUIRED before setting any values. + registers.IBAT0U.zero(); + registers.IBAT0L.zero(); + registers.IBAT1U.zero(); + registers.IBAT1L.zero(); + registers.IBAT2U.zero(); + registers.IBAT2L.zero(); + registers.IBAT3U.zero(); + registers.IBAT3L.zero(); + registers.DBAT0U.zero(); + registers.DBAT0L.zero(); + registers.DBAT1U.zero(); + registers.DBAT1L.zero(); + registers.DBAT2U.zero(); + registers.DBAT2L.zero(); + registers.DBAT3U.zero(); + registers.DBAT3L.zero(); + cpu.isync(); + + // Clear all Segment Registers + asm volatile ( + \\mtsr 0, %[v] + \\mtsr 1, %[v] + \\mtsr 2, %[v] + \\mtsr 3, %[v] + \\mtsr 4, %[v] + \\mtsr 5, %[v] + \\mtsr 6, %[v] + \\mtsr 7, %[v] + \\mtsr 8, %[v] + \\mtsr 9, %[v] + \\mtsr 10, %[v] + \\mtsr 11, %[v] + \\mtsr 12, %[v] + \\mtsr 13, %[v] + \\mtsr 14, %[v] + \\mtsr 15, %[v] + \\isync + : + : [v] "r" (0x80000000), + ); + + // set [DI]BAT0 for 256MB@80000000, + // real 00000000, R/W + // const bat0Upper = .{ + // .vp = true, + // .vs = true, + // .bl = .@"256Mbyte", + // .bepi = 0x8000 >> 1, + // }; + // const bat0Lower = .{ + // .pp = .readwrite, + // }; + + registers.IBAT0U.write(.{ + .vp = true, + .vs = true, + .bl = .@"256Mbyte", + .bepi = 0x8000 >> 1, + }); + registers.IBAT0L.write(.{ + .pp = .readwrite, + }); + registers.DBAT0U.write(.{ + .vp = true, + .vs = true, + .bl = .@"256Mbyte", + .bepi = 0x8000 >> 1, + }); + registers.DBAT0L.write(.{ + .pp = .readwrite, + }); + cpu.isync(); + + // set DBAT1 for 256MB@c0000000, + // real 00000000, R/W + registers.DBAT1U.write(.{ + .vp = true, + .vs = true, + .bl = .@"256Mbyte", + .bepi = 0xc000 >> 1, + }); + registers.DBAT1L.write(.{ + .brpn = 0x000, + .pp = .readwrite, + .wimg = .{ + .guarded = true, + .caching_inhibited = true, + }, + }); + cpu.isync(); + + // Jump back to the call site of what called into __realmode + // This is done by re-enabling address translation and setting SSR0 to the old LR, then "return from interrupt" + // var msr = registers.MSR.read(); + // msr.dataAddressTranslation = true; + // msr.instructionAddressTranslation = true; + // registers.SSR1.write(msr); + _ = asm volatile ( + \\mfmsr %[r] + \\ori %[r], %[r], 0x30 + \\mtsrr1 %[r] + : [r] "=r" (-> u32), + ); + + // const lr = registers.LR.read(); + // registers.SSR0.write(lr | 0x80000000); + // cpu.returnFromInterrupt(); + _ = asm volatile ( + \\mflr %[r] + \\oris %[r], %[r], 0x8000 + \\mtsrr0 %[r] + \\rfi + : [r] "=r" (-> u32), + ); + } + + // Zero out all registers + export fn kernel_initGPRS() callconv(.naked) noreturn { + // Clear all of the GPR's to 0 + asm volatile ( + \\li %r0, 0 + \\li %r3, 0 + \\li %r4, 0 + \\li %r5, 0 + \\li %r6, 0 + \\li %r7, 0 + \\li %r8, 0 + \\li %r9, 0 + \\li %r10, 0 + \\li %r11, 0 + \\li %r12, 0 + \\li %r14, 0 + \\li %r15, 0 + \\li %r16, 0 + \\li %r17, 0 + \\li %r18, 0 + \\li %r19, 0 + \\li %r20, 0 + \\li %r21, 0 + \\li %r22, 0 + \\li %r23, 0 + \\li %r24, 0 + \\li %r25, 0 + \\li %r26, 0 + \\li %r27, 0 + \\li %r28, 0 + \\li %r29, 0 + \\li %r30, 0 + \\li %r31, 0 + ); + + asm volatile ("blr"); + } + + export fn kernel_initHardware() void { + // Enable the Floating Point Registers + registers.MSR.modify(.{ + .floatingPoint = true, + }); + + kernel_initPS(); + kernel_initFPRS(); + cache.init(); + } + + noinline fn kernel_initPS() void { + registers.HID2.modify(.{ + .loadstore_quantize_enable = true, // Load/Store quantized enable for non-indexed format instructions + .paired_single_enable = true, // Paired single enabled + }); + cpu.isync(); + + cache.instructionCacheFlashInvalidate(); + cpu.sync(); + + registers.GQR0.write(.{}); + registers.GQR1.write(.{}); + registers.GQR2.write(.{}); + registers.GQR3.write(.{}); + registers.GQR4.write(.{}); + registers.GQR5.write(.{}); + registers.GQR6.write(.{}); + registers.GQR7.write(.{}); + cpu.isync(); + } + + noinline fn kernel_initFPRS() void { + // Enable Floating Point Registers + registers.MSR.modify(.{ + .floatingPoint = true, + }); + + // Clear FRP's + const code = comptime blk: { + @setEvalBranchQuota(10_000); + + var code: []const u8 = ""; + for (1..32) |i| { + code = code ++ std.fmt.comptimePrint("\nfmr {}, %f0", .{i}); + } + code = code ++ "\nmtfsf 255, %f0"; + break :blk code; + }; + asm volatile (code + : + : [in] "{f0}" (0), + ); + } + + export fn kernel_initSystem() void { + // Disable interrupts + registers.MSR.modify(.{ + .externalInterrupt = false, + .exceptionPrefix = false, + }); + + // Clear Special Registers + registers.MMCR0.write(.{}); + registers.MMCR1.write(.{}); + registers.PMC1.write(.{}); + registers.PMC2.write(.{}); + registers.PMC3.write(.{}); + registers.PMC4.write(.{}); + cpu.isync(); + + // Disable speculative cache accesses to non-guarded space from both D and I caches + registers.HID0.modify(.{ + .spd = true, + }); + + // Set the Non-IEEE mode in the FPSCR + asm volatile ("mtfsb1 29"); + + // Disable Write Pipe Enabled bit + registers.HID2.modify(.{ + .write_pipe_enable = false, + }); + + // system.init(); + } + + extern var __kernel_stack_start: anyopaque; + extern var __kernel_stack_end: anyopaque; + extern var __sdata_start: anyopaque; + extern var __sdata2_start: anyopaque; + + pub export fn kernel_initStack() callconv(.naked) noreturn { + // Setup stack + asm volatile ( + \\li %r0, 0 + \\stwu %r0, -4(%r1) + \\stwu %r1,-56(%r1) + \\blr + : + : [stack] "+{r1}" (&__kernel_stack_end), + [sdata2] "+{r2}" (&__sdata2_start), + [sdata] "+{r13}" (&__sdata_start), + ); + } +}; + +pub inline fn getStackPointer() usize { + return asm ("" + : [sp] "={r1}" (-> usize), + ); +} + +pub fn areInterruptsEnabled() bool { + return false; +} + +pub fn isInInterruptContext() bool { + return false; +} + +pub fn disableInterrupts() void { + // NAH +} + +pub fn enableInterrupts() void { + // NAH +} + +pub fn get_cpu_cycle_counter() u64 { + return 0; +} + +pub fn get_cpu_random_seed() ?u64 { + return null; +} diff --git a/src/kernel/port/platform/ppc/cache.zig b/src/kernel/port/platform/ppc/cache.zig new file mode 100644 index 00000000..aac4215c --- /dev/null +++ b/src/kernel/port/platform/ppc/cache.zig @@ -0,0 +1,173 @@ +const std = @import("std"); +const cpu = @import("cpu.zig"); +const registers = cpu.registers; + +const cache_line_size = 32; + +pub fn init() void { + if (!instructionCacheEnabled()) { + enableInstructionCache(); + } + + if (!dataCacheEnabled()) { + enableDataCache(); + } + + if (!level2CacheEnabled()) { + initializeLevel2Cache(); + enableLevel2Cache(); + } +} + +pub fn instructionCacheFlashInvalidate() void { + registers.HID0.modify(.{ + .icfi = true, + }); + cpu.isync(); +} + +pub inline fn instructionCacheEnabled() bool { + return registers.HID0.read().ice; +} + +pub fn enableInstructionCache() void { + registers.HID0.modify(.{ + .ice = true, + }); + cpu.isync(); +} + +pub fn disableInstructionCache() void { + registers.HID0.modify(.{ + .ice = false, + }); + cpu.isync(); +} + +pub fn invalidateInstructionCacheRange(memory: []align(cache_line_size) volatile u8) void { + const cache_lines = std.math.divCeil(usize, memory.len, cache_line_size) catch unreachable; + for (0..cache_lines) |i| { + asm volatile ( + \\icbi %[offset], %[address] + : + : [address] "r" (memory.ptr), + [offset] "r" (i * cache_line_size), + ); + } + + cpu.sync(); + cpu.isync(); +} + +pub inline fn dataCacheEnabled() bool { + return registers.HID0.read().dce; +} + +pub fn enableDataCache() void { + registers.HID0.modify(.{ + .dce = true, + }); + cpu.isync(); +} + +pub fn disableDataCache() void { + registers.HID0.modify(.{ + .dce = false, + }); + cpu.isync(); +} + +pub noinline fn flushDataCacheRange(memory: []align(cache_line_size) const volatile u8) void { + flushDataCacheRangeNoSync(memory); + cpu.systemCall(); +} + +pub noinline fn flushDataCacheRangeNoSync(memory: []align(cache_line_size) const volatile u8) void { + const cache_lines = std.math.divCeil(usize, memory.len, cache_line_size) catch unreachable; + for (0..cache_lines) |i| { + asm volatile ( + \\dcbf %[offset], %[address] + : + : [address] "r" (memory.ptr), + [offset] "r" (i * cache_line_size), + ); + } +} + +pub noinline fn invalidateDataCacheRange(memory: []align(cache_line_size) volatile u8) void { + const cache_lines = std.math.divCeil(usize, memory.len, cache_line_size) catch unreachable; + for (0..cache_lines) |i| { + asm volatile ( + \\dcbi %[offset], %[address] + : + : [address] "r" (memory.ptr), + [offset] "r" (i * cache_line_size), + ); + } +} + +pub inline fn level2CacheEnabled() bool { + return registers.L2CR.read().l2e; +} + +pub fn initializeLevel2Cache() void { + const msr = registers.MSR.read(); + cpu.sync(); + + // Enable Instruction and Data Address Translation + // TODO Isn't this enabled already? + // TODO This disables everything else, feels wrong + registers.MSR.write(.{ + .instructionAddressTranslation = true, + .dataAddressTranslation = true, + }); + cpu.sync(); + + invalidateLevel2Cache(); + + // Return to old MSR + registers.MSR.write(msr); +} + +pub fn enableLevel2Cache() void { + cpu.sync(); + + registers.L2CR.modify(.{ + .l2e = true, + .l2do = false, + .l2i = false, + }); + cpu.sync(); +} + +pub fn disableLevel2Cache() void { + cpu.sync(); + + // Clear L2E bit + registers.L2CR.modify(.{ + .l2e = false, + }); + + cpu.sync(); +} + +pub fn invalidateLevel2Cache() void { + disableLevel2Cache(); + + // Set L2I bit (global invalidate) + registers.L2CR.modify(.{ + .l2i = true, + }); + + // Wait for L2IP bit to be 0 (invalidate progress) + while (registers.L2CR.read().l2ip) {} + + // Clear L2DO and L2I bits + registers.L2CR.modify(.{ + .l2do = false, + .l2i = false, + }); + + // Wait for L2IP bit to be 0 (invalidate progress) + while (registers.L2CR.read().l2ip) {} +} diff --git a/src/kernel/port/platform/ppc/cpu.zig b/src/kernel/port/platform/ppc/cpu.zig new file mode 100644 index 00000000..9f10ebfc --- /dev/null +++ b/src/kernel/port/platform/ppc/cpu.zig @@ -0,0 +1,33 @@ +pub const registers = @import("registers.zig"); + +pub inline fn isync() void { + asm volatile ("isync"); +} + +pub inline fn sync() void { + asm volatile ("sync"); +} + +pub inline fn returnFromInterrupt() void { + asm volatile ("rfi"); +} + +pub inline fn systemCall() void { + asm volatile ("sc"); +} + +pub inline fn disableInterrupts() bool { + var msr = registers.MSR.read(); + const ee = msr.externalInterrupt; + msr.externalInterrupt = false; + registers.MSR.write(msr); + return ee; +} + +pub inline fn enableInterrupts(enable: bool) void { + if (enable) { + registers.MSR.modify(.{ + .externalInterrupt = true, + }); + } +} diff --git a/src/kernel/port/platform/ppc/memory.zig b/src/kernel/port/platform/ppc/memory.zig new file mode 100644 index 00000000..637fa5c7 --- /dev/null +++ b/src/kernel/port/platform/ppc/memory.zig @@ -0,0 +1,19 @@ +pub inline fn cachedFromPhysical(ptr: anytype) @TypeOf(ptr) { + const address: usize = @intFromPtr(ptr); + return @ptrFromInt(address + @as(usize, 0x80000000)); +} + +pub inline fn physicalFromPtr(ptr: anytype) @TypeOf(ptr) { + const address: usize = @intFromPtr(ptr); + return @ptrFromInt(address & ~@as(usize, 0xC0000000)); +} + +pub inline fn uncachedFromCached(ptr: anytype) @TypeOf(ptr) { + const address: usize = @intFromPtr(ptr); + return @ptrFromInt(address + @as(usize, 0xC0000000 - 0x80000000)); +} + +pub inline fn cachedFromUncached(ptr: anytype) @TypeOf(ptr) { + const address: usize = @intFromPtr(ptr); + return @ptrFromInt(address - @as(usize, 0xC0000000 - 0x80000000)); +} diff --git a/src/kernel/port/platform/ppc/registers.zig b/src/kernel/port/platform/ppc/registers.zig new file mode 100644 index 00000000..0f7af517 --- /dev/null +++ b/src/kernel/port/platform/ppc/registers.zig @@ -0,0 +1,459 @@ +// pub const audio = @import("registers/audio.zig"); +// pub const dsp = @import("registers/dsp.zig"); +pub const memory = @import("registers/memory.zig"); +pub const processor = @import("registers/processor.zig"); +// pub const video = @import("registers/video.zig"); +// pub const exi = @import("registers/exi.zig"); +// pub const pe = @import("registers/pe.zig"); +pub const cp = @import("registers/cp.zig"); +pub const timebase = @import("registers/timebase.zig"); + +pub const HID0 = SpecialRegister(1008, packed struct(u32) { + noopti: bool = false, + reserved1: u1 = 0, + bht: bool = false, + abe: bool = false, + reserved2: u1 = 0, + btic: bool = false, + dcfa: bool = false, + sge: bool = false, + ifem: bool = false, + spd: bool = false, + dcfi: bool = false, + icfi: bool = false, + dlock: bool = false, + ilock: bool = false, + dce: bool = false, + ice: bool = false, + nhr: bool = false, + reserved3: u3 = 0, + dpm: bool = false, + sleep: bool = false, + nap: bool = false, + doze: bool = false, + par: bool = false, + eclk: bool = false, + reserved4: u1 = 0, + bclk: bool = false, + ebd: bool = false, + eba: bool = false, + dbp: bool = false, + emcp: bool = false, +}); + +pub const HID1 = SpecialRegister(1009, packed struct(u32) { + reserved1: u28 = 0, + pcr3: u1, + pcr2: u1, + pcr1: u1, + pcr0: u1, +}); + +pub const HID2 = SpecialRegister(920, packed struct(u32) { + reserved1: u16 = 0, + dqoee: bool = false, + dcmee: bool = false, + dncee: bool = false, + dchee: bool = false, + dqoerr: bool = false, + dcmerr: bool = false, + dncerr: bool = false, + dcherr: bool = false, + dma_queue_len: u4 = 0, // TODO Double check + locked_cache_enable: bool = false, + paired_single_enable: bool = false, + write_pipe_enable: bool = false, + loadstore_quantize_enable: bool = false, +}); + +pub const WPAR = SpecialRegister(921, packed struct(u32) { + bne: bool = false, + reserved: u5 = 0, + address: u26 = 0, // shift away the lowest 6 bits to get the cache line +}); + +pub const L2CR = SpecialRegister(1017, packed struct(u32) { + l2ip: bool = false, + reserved1: u17 = 0, + l2ts: bool = false, + l2wt: bool = false, + reserved2: u1 = 0, + l2i: bool = false, + l2do: bool = false, + reserved3: u7 = 0, + l2ce: bool = false, + l2e: bool = false, +}); + +const BATBlockLength = enum(u11) { + @"128Kbytes" = 0b0, + @"256Kbytes" = 0b1, + @"512Kbytes" = 0b11, + @"1Mbyte" = 0b111, + @"2Mbyte" = 0b1111, + @"4Mbyte" = 0b11111, + @"8Mbyte" = 0b111111, + @"16Mbyte" = 0b1111111, + @"32Mbyte" = 0b11111111, + @"64Mbyte" = 0b111111111, + @"128Mbyte" = 0b1111111111, + @"256Mbyte" = 0b11111111111, +}; + +pub const BATU = packed struct(u32) { + /// Problem state valid bit + vp: bool = false, + /// Supervisor state valid bit + vs: bool = false, + /// Block-length Mask + bl: BATBlockLength = .@"128Kbytes", + reserved1: u4 = 0, + /// Block Effective Page Index + bepi: u15 = 0, +}; + +const WIMG = packed struct(u4) { + guarded: bool = false, + memory_coherence: bool = false, + caching_inhibited: bool = false, + write_through: bool = false, +}; + +const PP = enum(u2) { + noaccess = 0, + readonly = 1, + readwrite = 2, +}; + +pub const BATL = packed struct(u32) { + /// Protection bits + pp: PP = .noaccess, + reserved1: u1 = 0, + /// Storage Access Controls + wimg: WIMG = .{}, + reserved2: u10 = 0, + /// Block Real Page Number + brpn: u15 = 0, +}; + +pub const IBAT0U = SpecialRegister(528, BATU); +pub const IBAT0L = SpecialRegister(529, BATL); +pub const IBAT1U = SpecialRegister(530, BATU); +pub const IBAT1L = SpecialRegister(531, BATL); +pub const IBAT2U = SpecialRegister(532, BATU); +pub const IBAT2L = SpecialRegister(533, BATL); +pub const IBAT3U = SpecialRegister(534, BATU); +pub const IBAT3L = SpecialRegister(535, BATL); + +pub const DBAT0U = SpecialRegister(536, BATU); +pub const DBAT0L = SpecialRegister(537, BATL); +pub const DBAT1U = SpecialRegister(538, BATU); +pub const DBAT1L = SpecialRegister(539, BATL); +pub const DBAT2U = SpecialRegister(540, BATU); +pub const DBAT2L = SpecialRegister(541, BATL); +pub const DBAT3U = SpecialRegister(542, BATU); +pub const DBAT3L = SpecialRegister(543, BATL); + +const LDType = enum(u3) { + noconversion = 0, + unsigned8bit = 4, + unsigned16bit = 5, + signed8bit = 6, + signed16bit = 7, +}; + +const GQR = packed struct(u32) { + st_type: LDType = .noconversion, + reserved1: u5 = 0, + /// Twos complement scale from -32 to 31 + st_scale: u6 = 0, + reserved2: u2 = 0, + ld_type: LDType = .noconversion, + reserved3: u5 = 0, + /// Twos complement scale from -32 to 31 + ld_scale: u6 = 0, + reserved4: u2 = 0, +}; + +pub const GQR0 = SpecialRegister(912, GQR); +pub const GQR1 = SpecialRegister(913, GQR); +pub const GQR2 = SpecialRegister(914, GQR); +pub const GQR3 = SpecialRegister(915, GQR); +pub const GQR4 = SpecialRegister(916, GQR); +pub const GQR5 = SpecialRegister(917, GQR); +pub const GQR6 = SpecialRegister(918, GQR); +pub const GQR7 = SpecialRegister(919, GQR); + +const RTCSelect = enum(u2) { + @"31" = 0, + @"23" = 1, + @"19" = 2, + @"15" = 3, +}; + +const PMC1Events = enum(u7) { + none = 0, + processor_cycles = 1, + instructions = 2, + tbl_bittransitions = 3, + instruction_dispatch = 4, + eieio_instruction = 5, + tablesearch_cycles = 6, + l2cache_hit = 7, + validea_instruction = 8, // TODO Better name + breakpoint_hit = 9, + l1cache_latency_miss = 10, + branch_unresolved = 11, + dispatcher_stall_cycles = 12, +}; + +const PMC2Events = enum(u6) { + none = 0, + processor_cycles = 1, + instructions = 2, + tbl_bittransitions = 3, + instruction_dispatch = 4, + l1cache_miss = 5, + itbl_miss = 6, + l2cache_i_miss = 7, + branches_fallthrough = 8, + reserved_loads = 10, + loads_and_stores = 11, + snoops = 12, + l1cache_castouts = 13, + systemunit_instructions = 14, + first_speculative_branch_resolved_correctly = 15, +}; + +/// Monitor Mode Control 0 +pub const MMCR0 = SpecialRegister(952, packed struct(u32) { + pmc2select: PMC2Events = .none, + pmc1select: PMC1Events = .none, + pmctrigger: bool = false, + pmcintcontrol: bool = false, + pmc1intcontrol: bool = false, + threshold: u6 = 0, + intonbittrans: bool = false, + rtcselect: RTCSelect = .@"31", + discount: bool = false, + enint: bool = false, + dmr: bool = false, + dms: bool = false, + du: bool = false, + dp: bool = false, + dis: bool = false, +}); + +const PMC3Events = enum(u5) { + none = 0, + processor_cycles = 1, + instructions = 2, + tbl_bittransitions = 3, + instruction_dispatch = 4, + l1cache_miss = 5, + dtbl_miss = 6, + l2cache_d_miss = 7, + branches_predicted = 8, + conditional_store_instructions = 10, + fpu_instructions = 11, + l2cache_castout_snoops = 12, + l2cache_hits = 13, + l1cache_miss_cycles = 15, + second_speculative_branch_resolved_correctly = 16, + bpu_stalls = 17, +}; + +const PMC4Events = enum(u5) { + none = 0, + processor_cycles = 1, + instructions = 2, + tbl_bittransitions = 3, + instruction_dispatch = 4, + l2cache_castouts = 5, + dtbl_cycles = 6, + branches_mispredicted = 8, + conditional_store_instuctions_with_reservation = 10, + sync_instuction = 11, + snoop_retries = 12, + integer_operations = 13, + bpu_unresolved_cycles = 14, +}; + +/// Monitor Mode Control 1 +pub const MMCR1 = SpecialRegister(956, packed struct(u32) { + reserved: u22 = 0, + pmc4select: PMC4Events = .none, + pmc3select: PMC3Events = .none, +}); + +const PMC = packed struct(u32) { + counter: u31 = 0, + overflow: bool = false, +}; + +/// Performance Monitor Counter 1 +pub const PMC1 = SpecialRegister(953, PMC); +/// Performance Monitor Counter 2 +pub const PMC2 = SpecialRegister(954, PMC); +/// Performance Monitor Counter 3 +pub const PMC3 = SpecialRegister(957, PMC); +/// Performance Monitor Counter 4 +pub const PMC4 = SpecialRegister(958, PMC); + +/// User Performance Monitor Counter 1 +pub const UPMC1 = SpecialRegister(937, PMC); +/// User Performance Monitor Counter 2 +pub const UPMC2 = SpecialRegister(938, PMC); +/// User Performance Monitor Counter 3 +pub const UPMC3 = SpecialRegister(941, PMC); +/// User Performance Monitor Counter 4 +pub const UPMC4 = SpecialRegister(942, PMC); +/// Sampled Instruction Address +pub const SIA = SpecialRegister(955, u32); +/// User Sampled Instruction Address +pub const USIA = SpecialRegister(939, u32); + +pub const IRQN = SpecialRegister(272, u32); +pub const IRQSP = SpecialRegister(273, u32); +pub const SPRG2 = SpecialRegister(274, u32); +pub const SPRG3 = SpecialRegister(275, u32); + +pub const DSISR = SpecialRegister(18, u32); +pub const DAR = SpecialRegister(19, u32); + +pub const MSR = packed struct(u32) { + littleEndian: bool = false, + resumeInterrupt: bool = false, + reserved4: u2 = 0, + dataAddressTranslation: bool = false, + instructionAddressTranslation: bool = false, + exceptionPrefix: bool = false, + reserved3: u1 = 0, + fpExceptionMode1: bool = false, + branchTrace: bool = false, + singlestepTrace: bool = false, + fpExceptionMode0: bool = false, + machineCheck: bool = false, + floatingPoint: bool = false, + privilegeLevel: bool = false, + externalInterrupt: bool = false, + exceptionLittleEndian: bool = false, + reserved2: u1 = 0, + powerManagement: bool = false, + reserved1: u13 = 0, + + pub inline fn read() MSR { + return asm volatile ("mfmsr %[r]" + : [r] "=r" (-> MSR), + ); + } + + pub inline fn write(msr: MSR) void { + asm volatile ("mtmsr %[r]" + : + : [r] "r" (msr), + ); + } + + pub inline fn modify(fields: anytype) void { + var val = read(); + inline for (@typeInfo(@TypeOf(fields)).@"struct".fields) |field| { + @field(val, field.name) = @field(fields, field.name); + } + write(val); + } +}; + +pub const SSR0 = struct { + pub inline fn read() u32 { + return asm volatile ("mfsrr0 %[r]" + : [r] "=r" (-> u32), + ); + } + + pub inline fn write(value: u32) void { + asm volatile ("mtsrr0 %[r]" + : + : [r] "r" (value), + ); + } + + pub inline fn modify(fields: anytype) void { + var val = read(); + inline for (@typeInfo(@TypeOf(fields)).@"struct".fields) |field| { + @field(val, field.name) = @field(fields, field.name); + } + write(val); + } +}; + +pub const SSR1 = struct { + pub inline fn read() MSR { + return asm volatile ("mfsrr1 %[r]" + : [r] "=r" (-> MSR), + ); + } + + pub inline fn write(msr: MSR) void { + asm volatile ("mtsrr1 %[r]" + : + : [r] "r" (msr), + ); + } + + pub inline fn modify(fields: anytype) void { + var val = read(); + inline for (@typeInfo(@TypeOf(fields)).@"struct".fields) |field| { + @field(val, field.name) = @field(fields, field.name); + } + write(val); + } +}; + +pub const LR = struct { + pub inline fn read() u32 { + return asm volatile ("mflr %[r]" + : [r] "=r" (-> u32), + ); + } +}; + +fn SpecialRegister(register: u10, backingType: type) type { + return struct { + // HACK: Force to u16 to avoid but with numbers turning negative in asm + pub const registerId: u16 = register; + pub const BackingType = backingType; + pub const IntegerType = @typeInfo(backingType).@"struct".backing_integer.?; + + pub inline fn read() BackingType { + return asm volatile ("mfspr %[r], %[reg]" + : [r] "=r" (-> BackingType), + : [reg] "i" (registerId), + ); + } + + pub inline fn write(value: BackingType) void { + asm volatile ("mtspr %[reg], %[value]" + : + : [reg] "i" (registerId), + [value] "r" (value), + ); + } + + pub inline fn zero() void { + asm volatile ("mtspr %[reg], %[value]" + : + : [reg] "i" (registerId), + [value] "r" (0), + ); + } + + pub inline fn modify(fields: anytype) void { + var val = read(); + inline for (@typeInfo(@TypeOf(fields)).@"struct".fields) |field| { + @field(val, field.name) = @field(fields, field.name); + } + write(val); + } + }; +} diff --git a/src/kernel/port/platform/ppc/registers/audio.zig b/src/kernel/port/platform/ppc/registers/audio.zig new file mode 100644 index 00000000..1fce0d57 --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/audio.zig @@ -0,0 +1,49 @@ +/// Control Status Register +pub const control_status: *volatile ControlStatus = @ptrFromInt(0xCC006C00); +pub const ControlStatus = packed struct(u32) { + pub const SampleRate = enum(u1) { + @"48kHz" = 0, + @"32kHz" = 1, + }; + + playing_status: bool = false, + aux_frequency: SampleRate = .@"48kHz", + interrupt_mask: bool = false, + interrupt_status: bool = false, + interrupt_valid: bool = false, + sample_cntr_reset: bool = false, + dsp_sample_rate: SampleRate = .@"48kHz", + reserved: u25 = 0, +}; + +/// Volume Register +pub const volume: *volatile Volume = @ptrFromInt(0xCC006C04); +pub const Volume = packed struct(u32) { + left: u8 = 0, + right: u8 = 0, + reserved: u16 = 0, +}; + +/// Sample Counter +pub const sample_counter: *volatile u32 = @ptrFromInt(0xCC006C08); + +/// Interrupt Timing +pub const interrupt_timing: *volatile u32 = @ptrFromInt(0xCC006C0C); + +// TODO Are these really 16 bits? or can they be combined +// TODO These 4 below are TECHNICALLY in dsp memory space, likely why it's 16bit! +// DMA High address +pub const dma_address_high: *volatile u16 = @ptrFromInt(0xCC005030); + +// DMA Low address +pub const dma_address_low: *volatile u16 = @ptrFromInt(0xCC005032); + +// DMA Control and Sample Count +pub const dma_control_count: *volatile ControlSampleCount = @ptrFromInt(0xCC005036); +pub const ControlSampleCount = packed struct(u16) { + length: u15 = 0, + enabled: bool = false, +}; + +// DMA Control Length +pub const dma_samples_remaining: *volatile u16 = @ptrFromInt(0xCC00503A); diff --git a/src/kernel/port/platform/ppc/registers/cp.zig b/src/kernel/port/platform/ppc/registers/cp.zig new file mode 100644 index 00000000..6e0c0c6b --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/cp.zig @@ -0,0 +1,85 @@ +/// Status Register +pub const status: *volatile Status = @ptrFromInt(0xCC000000); +pub const Status = packed struct(u16) { + overflow: bool, + underflow: bool, + idle_reading: bool, + idle_commands: bool, + breakpoint: bool, + reserved: u11 = 0, +}; + +/// Control Register +pub const control: *volatile Control = @ptrFromInt(0xCC000002); +const Control = packed struct(u16) { + read: bool, + interrupt: bool, + overflow: bool, + underflow: bool, + /// link cp/pe fifo + link: bool, + breakpoint: bool, + reserved: u10 = 0, +}; + +/// Clear Register +/// set to true to clear +pub const clear: *volatile Clear = @ptrFromInt(0xCC000004); +const Clear = packed struct(u16) { + overflow: bool, + underflow: bool, + reserved: u14 = 0, +}; + +/// Unknown register (perf?) +pub const unknown1: *volatile u16 = @ptrFromInt(0xCC000006); + +/// Token Register +pub const token: *volatile u16 = @ptrFromInt(0xCC00000E); + +/// Bounding Box left Register +pub const bb_left: *volatile u16 = @ptrFromInt(0xCC000010); + +/// Bounding Box right Register +pub const bb_right: *volatile u16 = @ptrFromInt(0xCC000012); + +/// Bounding Box top Register +pub const bb_top: *volatile u16 = @ptrFromInt(0xCC000014); + +/// Bounding Box bottom Register +pub const bb_bottom: *volatile u16 = @ptrFromInt(0xCC000016); + +/// FIFO base lo +pub const fifo_base: *volatile u16 = @ptrFromInt(0xCC000020); +pub const fifo_base_lo: *volatile u16 = @ptrFromInt(0xCC000020); +pub const fifo_base_hi: *volatile u16 = @ptrFromInt(0xCC000022); + +/// FIFO end lo +pub const fifo_end_lo: *volatile u16 = @ptrFromInt(0xCC000024); +pub const fifo_end_hi: *volatile u16 = @ptrFromInt(0xCC000026); + +/// FIFO high watermark +/// Used for overflow interrupt +pub const fifo_watermark_high_lo: *volatile u16 = @ptrFromInt(0xCC000028); +pub const fifo_watermark_high_hi: *volatile u16 = @ptrFromInt(0xCC00002A); + +/// FIFO low watermark +/// Used for underflow interrupt +pub const fifo_watermark_low_lo: *volatile u16 = @ptrFromInt(0xCC00002C); +pub const fifo_watermark_low_hi: *volatile u16 = @ptrFromInt(0xCC00002E); + +/// FIFO RW distance +pub const fifo_rw_distance_lo: *volatile u16 = @ptrFromInt(0xCC000030); +pub const fifo_rw_distance_hi: *volatile u16 = @ptrFromInt(0xCC000032); + +/// FIFO write pointer +pub const fifo_write_ptr_lo: *volatile u16 = @ptrFromInt(0xCC000034); +pub const fifo_write_ptr_hi: *volatile u16 = @ptrFromInt(0xCC000036); + +/// FIFO read pointer +pub const fifo_read_ptr_lo: *volatile u16 = @ptrFromInt(0xCC000038); +pub const fifo_read_ptr_hi: *volatile u16 = @ptrFromInt(0xCC00003A); + +/// FIFO breakpoint +pub const fifo_breakpoint_lo: *volatile u16 = @ptrFromInt(0xCC00003C); +pub const fifo_breakpoint_hi: *volatile u16 = @ptrFromInt(0xCC00003E); diff --git a/src/kernel/port/platform/ppc/registers/dsp.zig b/src/kernel/port/platform/ppc/registers/dsp.zig new file mode 100644 index 00000000..4f8c287e --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/dsp.zig @@ -0,0 +1,17 @@ +/// Control Status Register +pub const control_status: *volatile ControlStatus = @ptrFromInt(0xCC00500A); +pub const ControlStatus = packed struct(u16) { + reset: bool = false, + interrupt_assert: bool = false, + halt: bool, + ai_interrupt_status: bool = false, + ai_interrupt_mask: bool = false, + aram_interrupt_status: bool = false, + aram_interrupt_mask: bool = false, + dsp_interrupt_status: bool = false, + dsp_interrupt_mask: bool = false, + dsp_dma_status: bool = false, + reserved1: u1 = 0, + dsp_reset: bool = false, + reserved2: u4 = 0, +}; diff --git a/src/kernel/port/platform/ppc/registers/exi.zig b/src/kernel/port/platform/ppc/registers/exi.zig new file mode 100644 index 00000000..d292853b --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/exi.zig @@ -0,0 +1,91 @@ +pub const Frequency = enum(u3) { + @"1MHz" = 0, + @"2MHz" = 1, + @"4MHz" = 2, + @"8MHz" = 3, + @"16MHz" = 4, + @"32MHz" = 5, +}; + +pub const DeviceID = enum(u3) { + none = 0b000, + device0 = 0b001, + device1 = 0b010, + device2 = 0b100, +}; + +pub const Parameter = packed struct(u32) { + interrupt_mask: bool, + interrupt_status: bool, + transfer_interrupt_mask: bool, + transfer_interrupt_status: bool, + clock: Frequency, + select: DeviceID, + ext_interrupt_mask: bool, + ext_interrupt_status: bool, + ext_connected: bool, + /// Only valid on EXI0 + rom_descramble: bool, + reserved: u18 = 0, +}; + +/// EXI Channel 0 Parameter +pub const parameter0: *volatile Parameter = @ptrFromInt(0xCC006800); +/// EXI Channel 1 Parameter +pub const parameter1: *volatile Parameter = @ptrFromInt(0xCC006814); +/// EXI Channel 2 Parameter +pub const parameter2: *volatile Parameter = @ptrFromInt(0xCC006828); + +/// EXI Channel 0 DMA Start Address +/// value must be 32 bytes aligned +pub const dma_start_address0: *volatile [*]align(32) u8 = @ptrFromInt(0xCC006804); +/// EXI Channel 1 DMA Start Address +/// value must be 32 bytes aligned +pub const dma_start_address1: *volatile [*]align(32) u8 = @ptrFromInt(0xCC006818); +/// EXI Channel 2 DMA Start Address +/// value must be 32 bytes aligned +pub const dma_start_address2: *volatile [*]align(32) u8 = @ptrFromInt(0xCC00682C); + +/// EXI Channel 0 DMA Length +pub const dma_length0: *volatile u32 = @ptrFromInt(0xCC006808); +/// EXI Channel 1 DMA Length +pub const dma_length1: *volatile u32 = @ptrFromInt(0xCC00681C); +/// EXI Channel 2 DMA Length +pub const dma_length2: *volatile u32 = @ptrFromInt(0xCC006830); + +pub const ImmediateTransferLength = enum(u2) { + @"1byte" = 0, + @"2byte" = 1, + @"3byte" = 2, + @"4byte" = 3, +}; + +pub const Control = packed struct(u32) { + transfer_start: bool, + mode: enum(u1) { + immediate = 0, + dma = 1, + }, + readwrite: enum(u2) { + read = 0, + write = 1, + /// Invalid for DMA + readwrite = 2, + }, + immediate_length: ImmediateTransferLength = .@"1byte", + reserved: u26 = 0, +}; + +/// EXI Channel 0 Control Register +pub const control0: *volatile Control = @ptrFromInt(0xCC00680C); +/// EXI Channel 1 Control Register +pub const control1: *volatile Control = @ptrFromInt(0xCC006820); +/// EXI Channel 2 Control Register +pub const control2: *volatile Control = @ptrFromInt(0xCC006834); + +/// EXI Channel 0 Immediate data +pub const immediate_data0: *volatile u32 = @ptrFromInt(0xCC006810); +/// EXI Channel 1 Immediate data +pub const immediate_data1: *volatile u32 = @ptrFromInt(0xCC006824); +/// EXI Channel 2 Immediate data +pub const immediate_data2: *volatile u32 = @ptrFromInt(0xCC006838); diff --git a/src/kernel/port/platform/ppc/registers/gx.zig b/src/kernel/port/platform/ppc/registers/gx.zig new file mode 100644 index 00000000..fb604fad --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/gx.zig @@ -0,0 +1,5 @@ +/// GX Fifo buffer, 32 bytes +pub const fifo: *volatile u32 = @ptrFromInt(0xCC008000); +pub const fifo_f32: *volatile f32 = @ptrFromInt(0xCC008000); +pub const fifo_u8: *volatile u8 = @ptrFromInt(0xCC008000); +pub const fifo_u16: *volatile u16 = @ptrFromInt(0xCC008000); diff --git a/src/kernel/port/platform/ppc/registers/memory.zig b/src/kernel/port/platform/ppc/registers/memory.zig new file mode 100644 index 00000000..961ad31e --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/memory.zig @@ -0,0 +1,60 @@ +/// Protected Memory Region 0 +pub const protected_region0: *volatile u32 = @ptrFromInt(0xCC004000); +/// Protected Memory Region 1 +pub const protected_region1: *volatile u32 = @ptrFromInt(0xCC004004); +/// Protected Memory Region 2 +pub const protected_region2: *volatile u32 = @ptrFromInt(0xCC004008); +/// Protected Memory Region 3 +pub const protected_region3: *volatile u32 = @ptrFromInt(0xCC00400c); + +/// Protected Config +pub const protection_config: *volatile Config = @ptrFromInt(0xCC004010); +const Flags = enum(u2) { + denied = 0, + read = 1, + write = 2, + all = 3, +}; +const Config = packed struct(u16) { + channel0: Flags = .denied, + channel1: Flags = .denied, + channel2: Flags = .denied, + channel3: Flags = .denied, + reserved: u8 = 0, +}; + +/// MI Interrupt mask +pub const interrupt_mask: *volatile InterruptMask = @ptrFromInt(0xCC00401C); +pub const InterruptMask = packed struct(u16) { + mem0: bool = false, + mem1: bool = false, + mem2: bool = false, + mem3: bool = false, + all: bool = false, + reserved: u11 = 0, +}; + +/// MI Interrupt cause +pub const interrupt_cause: *volatile InterruptCause = @ptrFromInt(0xCC00401e); +pub const InterruptCause = packed struct(u16) { + mem0: bool = false, + mem1: bool = false, + mem2: bool = false, + mem3: bool = false, + memaddress: bool = false, + reserved: u11 = 0, +}; + +/// MI Interrupt signal +pub const interrupt_signal: *volatile InterruptSignal = @ptrFromInt(0xCC004020); +pub const InterruptSignal = packed struct(u16) { + reserved1: u1 = 0, + asserted: bool = false, + reserved2: u14 = 0, +}; + +/// MI Fault Address Low +pub const fail_address_low: *volatile u32 = @ptrFromInt(0xCC004022); + +/// MI Fault Address High +pub const fail_address_high: *volatile u32 = @ptrFromInt(0xCC004024); diff --git a/src/kernel/port/platform/ppc/registers/pe.zig b/src/kernel/port/platform/ppc/registers/pe.zig new file mode 100644 index 00000000..377f9fb0 --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/pe.zig @@ -0,0 +1,65 @@ +const common = @import("../gx/common.zig"); + +pub const z_config: *volatile ZConfig = @ptrFromInt(0xCC001000); +const ZConfig = packed struct(u16) { + comperator_enabled: bool, + function: common.Compare, + update_enabled: bool, + reserved: u11 = 0, +}; + +pub const color_config: *volatile ColorConfig = @ptrFromInt(0xCC001002); +const ColorConfig = packed struct(u16) { + boolean_blending: bool, + arithmetic_blending: bool, + dither: bool, + color_update: bool, + alpha_update: bool, + dst_factor: u3, + src_factor: u3, + subtractive: bool, + blend_operator: common.BlendLogic, +}; + +/// Destination Alpha +pub const destination_alpha: *volatile DestinationAlpha = @ptrFromInt(0xCC001004); +pub const DestinationAlpha = packed struct(u16) { + alpha: u8, + enable: bool, + reserved: u7 = 0, +}; + +/// Alpha Mode +pub const alpha_mode: *volatile AlphaMode = @ptrFromInt(0xCC001006); +pub const AlphaMode = packed struct(u16) { + threshold: u8, + mode: common.Compare, + padding: u5 = 0, +}; + +/// Alpha Read +pub const alpha_read: *volatile AlphaRead = @ptrFromInt(0xCC001008); +pub const AlphaRead = packed struct(u16) { + pub const Mode = enum(u2) { + always_00 = 0, + always_ff = 1, + value = 2, + }; + + mode: Mode = .always_00, + unknown: bool = true, // must be true + padding: u13 = 0, +}; + +/// Interrupt Status +pub const interrupt_status: *volatile InterruptStatus = @ptrFromInt(0xCC00100A); +const InterruptStatus = packed struct(u16) { + token_enable: bool = false, + finish_enable: bool = false, + token_acknowledge: bool = false, + finish_acknowledge: bool = false, + reserved: u12 = 0, +}; + +/// PE Token +pub const pe_token: *volatile u16 = @ptrFromInt(0xCC00100E); diff --git a/src/kernel/port/platform/ppc/registers/processor.zig b/src/kernel/port/platform/ppc/registers/processor.zig new file mode 100644 index 00000000..d3af8fb1 --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/processor.zig @@ -0,0 +1,51 @@ +/// Interrupt cause +pub const interrupt_cause: *volatile InterruptCause = @ptrFromInt(0xCC003000); +// TODO: Make this an enum? +pub const InterruptCause = packed struct(u32) { + gp_error: bool, + reset_switch: bool, + dvd: bool, + serial: bool, + exi: bool, + streaming: bool, + dsp: bool, + memory: bool, + video: bool, + pe_token: bool, + pe_finish: bool, + cp: bool, + debug: bool, + hsp: bool, + reserved1: u2 = 0, + reset_switch_state: bool, + reserved2: u15 = 0, +}; + +/// Interrupt mask +pub const interrupt_mask: *volatile InterruptMask = @ptrFromInt(0xCC003004); +pub const InterruptMask = packed struct(u32) { + gp_error: bool = false, + reset_switch: bool = false, + dvd: bool = false, + serial: bool = false, + exi: bool = false, + streaming: bool = false, + dsp: bool = false, + memory: bool = false, + video: bool = false, + pe_token: bool = false, + pe_finish: bool = false, + cp: bool = false, + debug: bool = false, + hsp: bool = false, + reserved: u18 = 0, +}; + +/// FIFO Base Start +pub const fifo_start: *volatile [*]u32 align(32) = @ptrFromInt(0xCC00300c); + +/// FIFO Base End TODO: Unsure +pub const fifo_end: *volatile [*]u32 align(32) = @ptrFromInt(0xCC003010); + +/// FIFO Base End TODO: Unsure +pub const fifo_write_ptr: *volatile [*]u32 align(32) = @ptrFromInt(0xCC003014); diff --git a/src/kernel/port/platform/ppc/registers/timebase.zig b/src/kernel/port/platform/ppc/registers/timebase.zig new file mode 100644 index 00000000..01977c3b --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/timebase.zig @@ -0,0 +1,24 @@ +pub const TB_CLOCK: u64 = 40_500_000; + +pub inline fn readLower() u32 { + return asm volatile ("mftb %[value]" + : [value] "=r" (-> u32), + ); +} + +pub inline fn read() u64 { + while (true) { + const upper_before = asm volatile ("mftbu %[value]" + : [value] "=r" (-> u32), + ); + const lower = asm volatile ("mftb %[value]" + : [value] "=r" (-> u32), + ); + const upper_after = asm volatile ("mftbu %[value]" + : [value] "=r" (-> u32), + ); + if (upper_before == upper_after) { + return (@as(u64, upper_after) << 32) | lower; + } + } +} diff --git a/src/kernel/port/platform/ppc/registers/video.zig b/src/kernel/port/platform/ppc/registers/video.zig new file mode 100644 index 00000000..65b43d7f --- /dev/null +++ b/src/kernel/port/platform/ppc/registers/video.zig @@ -0,0 +1,286 @@ +pub const VideoFormat = enum(u2) { + ntsc = 0, + pal = 1, + mpal = 2, + debug = 3, +}; + +pub const VideoMode = enum { + interlaced, + doublestrike, + progressive, +}; + +/// Vertical Timing Register +pub const vtr: *volatile VTR = @ptrFromInt(0xCC002000); +pub const VTR = packed struct(u16) { + equalization: u4, + active_video: u10, + reserved: u2 = 0, +}; + +pub const Interlaced = enum(u1) { + interlaced = 0, + non_interlaced = 1, +}; + +/// Display Configuration Register +pub const dcr: *volatile DCR = @ptrFromInt(0xCC002002); +pub const DCR = packed struct(u16) { + const LatchMode = enum(u2) { + off = 0, + on1 = 1, + on2 = 2, + always = 3, + }; + + enable: bool = false, + reset: bool = false, + interlaced: Interlaced = .interlaced, + dlr: bool = false, // 3d + display_latch0: LatchMode = .off, + display_latch1: LatchMode = .off, + video_format: VideoFormat = .ntsc, + reserved: u6 = 0, +}; + +/// Horizontal Timing 0 +pub const htr0: *volatile HTR0 = @ptrFromInt(0xCC002004); +pub const HTR0 = packed struct(u32) { + hlw: u9, + reserved1: u7 = 0, + hce: u7, + reserved2: u1 = 0, + hcs: u7, + reserved3: u1 = 0, +}; + +/// Horizontal Timing 1 +pub const htr1: *volatile HTR1 = @ptrFromInt(0xCC002008); +pub const HTR1 = packed struct(u32) { + hsy: u7, + hbe: u10, + hbs: u10, + reserved: u5 = 0, +}; + +/// Odd Field Vertical Timing Register +pub const vto: *volatile FVTR = @ptrFromInt(0xCC00200c); + +/// Even Field Vertical Timing Register +pub const vte: *volatile FVTR = @ptrFromInt(0xCC002010); +pub const FVTR = packed struct(u32) { + prb: u10, + reserved1: u6 = 0, + psb: u10, + reserved2: u6 = 0, +}; + +// Odd Field Burst Blanking Interval Register +pub const bboi: *volatile BBOI = @ptrFromInt(0xCC002014); +pub const BBOI = packed struct(u32) { + bs1: u5, + be1: u11, + bs3: u5, + be3: u11, +}; + +// Even Field Burst Blanking Interval Register +pub const bbei: *volatile BBEI = @ptrFromInt(0xCC002018); +pub const BBEI = packed struct(u32) { + bs2: u5, + be2: u11, + bs4: u5, + be4: u11, +}; + +/// Top Field Base Register (L) (External Framebuffer Half 1) +pub const tfbl: *volatile FBR = @ptrFromInt(0xCC00201c); + +/// Top Field Base Register (R) (Only valid in 3D Mode) +pub const tfbr: *volatile FBR = @ptrFromInt(0xCC002020); + +/// Bottom Field Base Register (L) (External Framebuffer Half 2) +pub const bfbl: *volatile FBR = @ptrFromInt(0xCC002024); + +/// Bottom Field Base Register (R) (Only valid in 3D Mode) +pub const bfbr: *volatile FBR = @ptrFromInt(0xCC002028); + +// TODO: Double check comments +/// Field Base Register +pub const FBR = packed struct(u32) { + fbb: u24, // 0x80000000 | (fbb << 9) or 0x80000000 | (fbb << 5) if xof is set? + xof: u4, + po: bool, + unknown2: u3 = 0, +}; + +/// Current Vertical Position +pub const dpv: *volatile RBP = @ptrFromInt(0xCC00202c); + +/// Current Horizontal Position +pub const dph: *volatile RBP = @ptrFromInt(0xCC00202e); +pub const RBP = packed struct(u16) { + value: u11, + reserved1: u5, +}; + +/// Display Interrupt 0 +pub const di0: *volatile DI = @ptrFromInt(0xCC002030); + +/// Display Interrupt 1 +pub const di1: *volatile DI = @ptrFromInt(0xCC002034); + +/// Display Interrupt 2 +pub const di2: *volatile DI = @ptrFromInt(0xCC002038); + +/// Display Interrupt 3 +pub const di3: *volatile DI = @ptrFromInt(0xCC00203C); +pub const DI = packed struct(u32) { + hct: u10, + reserved1: u6 = 0, + vct: u10, + reserved2: u2 = 0, + interrupt_enabled: bool, + reserved3: u2 = 0, + interrupt_status: bool, +}; + +/// Display Latch 0 +pub const dl0: *volatile DL = @ptrFromInt(0xCC002040); + +/// Display Latch 1 +pub const dl1: *volatile DL = @ptrFromInt(0xCC002044); +pub const DL = packed struct(u32) { + hct: u11, + reserved1: u5 = 0, + vct: u11, + reserved2: u4 = 0, + trg: bool, +}; + +/// Scaling Width Register +pub const hsw: *volatile HSW = @ptrFromInt(0xCC002048); + +// TODO: The docs for this make no sense +pub const HSW = packed struct(u16) { + halfWidthWords: u8 = 40, + unknown1: u8 = 40, +}; + +/// Horizontal Scaling Register +pub const hsr: *volatile HSR = @ptrFromInt(0xCC00204A); +pub const HSR = packed struct(u16) { + stp: u9, + reserved1: u3 = 0, + enabled: bool, + reserved2: u3 = 0, +}; + +/// Filter Coefficient Table 0 +pub const ftc0: *volatile FCT0 = @ptrFromInt(0xCC00204C); +pub const FCT0 = packed struct(u32) { + tap0: u10 = 496, + tap1: u10 = 476, + tap2: u10 = 430, + reserved: u2 = 0, +}; + +/// Filter Coefficient Table 1 +pub const ftc1: *volatile FCT1 = @ptrFromInt(0xCC002050); +pub const FCT1 = packed struct(u32) { + tap3: u10 = 372, + tap4: u10 = 297, + tap5: u10 = 219, + reserved: u2 = 0, +}; + +/// Filter Coefficient Table 2 +pub const ftc2: *volatile FCT2 = @ptrFromInt(0xCC002054); +pub const FCT2 = packed struct(u32) { + tap6: u10 = 142, + tap7: u10 = 70, + tap8: u10 = 193, + reserved: u2 = 0, +}; + +/// Filter Coefficient Table 3 +pub const ftc3: *volatile FCT3 = @ptrFromInt(0xCC002058); +pub const FCT3 = packed struct(u32) { + tap9: u8 = 226, + tap10: u8 = 203, + tap11: u8 = 192, + tap12: u8 = 196, +}; + +/// Filter Coefficient Table 4 +pub const ftc4: *volatile FCT4 = @ptrFromInt(0xCC00205C); +pub const FCT4 = packed struct(u32) { + tap13: u8 = 207, + tap14: u8 = 222, + tap15: u8 = 236, + tap16: u8 = 252, +}; + +/// Filter Coefficient Table 5 +pub const ftc5: *volatile FCT5 = @ptrFromInt(0xCC002060); +pub const FCT5 = packed struct(u32) { + tap17: u8 = 8, + tap18: u8 = 15, + tap19: u8 = 19, + tap20: u8 = 19, +}; + +/// Filter Coefficient Table 6 +pub const ftc6: *volatile FCT6 = @ptrFromInt(0xCC002064); +pub const FCT6 = packed struct(u32) { + tap21: u8 = 15, + tap22: u8 = 12, + tap23: u8 = 8, + tap24zero: u8 = 0, +}; + +/// Unkown Lowpass Register +// TODO: Name +pub const ftc7: *volatile FTC7 = @ptrFromInt(0xCC002068); +pub const FTC7 = packed struct(u32) { + unknown: u32 = 0x00FF0000, +}; + +/// VI Clock Select Register +pub const viclk: *volatile VICLK = @ptrFromInt(0xCC00206C); +pub const VICLK = packed struct(u16) { + clock: enum(u1) { + @"27MHz" = 0, + @"54MHz" = 1, + } = .@"27MHz", + reserved: u15 = 0, +}; + +/// VI DTV Status Register +pub const visel: *volatile VISEL = @ptrFromInt(0xCC00206e); +pub const VISEL = packed struct(u16) { + enabled: u1, + unknown: u15 = 0, +}; + +/// Unknown +pub const ukn1: *volatile UNKNOWN1 = @ptrFromInt(0xCC002070); +pub const UNKNOWN1 = packed struct(u16) { + unknown: u16 = 640, +}; + +/// Border HBE +pub const hbe: *volatile HBE = @ptrFromInt(0xCC002072); +pub const HBE = packed struct(u16) { + hbe656: u10, + reserved: u5 = 0, + enabled: bool, +}; + +/// Border HBS +pub const hbs: *volatile HBS = @ptrFromInt(0xCC002074); +pub const HBS = packed struct(u16) { + HBS656: u10, + reserved: u6 = 0, +}; diff --git a/src/os/build.zig b/src/os/build.zig index 50c135ae..04335c93 100644 --- a/src/os/build.zig +++ b/src/os/build.zig @@ -7,21 +7,21 @@ const kernel_package = @import("kernel"); const Machine = kernel_package.Machine; const app_packages = [_][]const u8{ - "init", - "hello_world", - "hello_gui", - "gui_debugger", - "clock", - "paint", - "test_behaviour", - "desktop_classic", - "dungeon", - "ntp_client", - "i2c_scan", - "widgets", - "slideshow", - "2048", - "revision2026", + // "init", + // "hello_world", + // "hello_gui", + // "gui_debugger", + // "clock", + // "paint", + // "test_behaviour", + // "desktop_classic", + // "dungeon", + // "ntp_client", + // "i2c_scan", + // "widgets", + // "slideshow", + // "2048", + // "revision2026", // TODO: Include "wiki" again, }; @@ -374,6 +374,10 @@ const machine_info_map = std.EnumArray(Machine, MachineDependentOsConfig).init(. .disk_size = 0x0080_0000, // 4 MB, we store the disk inside the system image (upper half of the flash) .rom_size = 0x0080_0000, // 4 MB, we store the kernel inside the system image (lower half of the flash) }, + .@"ppc-nintendo-gc" = .{ + .disk_size = 0x0400_0000, + .rom_size = null, + }, }); const InstallBootloaderStep = struct { diff --git a/src/tools/exe-tool/src/ashex.zig b/src/tools/exe-tool/src/ashex.zig index bea07e45..049e07d4 100644 --- a/src/tools/exe-tool/src/ashex.zig +++ b/src/tools/exe-tool/src/ashex.zig @@ -4,10 +4,12 @@ pub const Platform = enum(u8) { riscv32 = 0, arm32 = 1, x86 = 2, + ppc = 3, }; pub const FileType = enum(u8) { machine32_le = 0, + machine32_be = 1, }; pub const file_magic: [4]u8 = .{ 'A', 'S', 'H', 'X' }; diff --git a/src/tools/exe-tool/src/exe-tool.zig b/src/tools/exe-tool/src/exe-tool.zig index 91f6ea91..5fda522a 100644 --- a/src/tools/exe-tool/src/exe-tool.zig +++ b/src/tools/exe-tool/src/exe-tool.zig @@ -663,6 +663,7 @@ fn parse_elf_file( .RISCV => .riscv32, .@"386" => .x86, .ARM => .arm32, + .PPC => .ppc, else => return error.UnsupportedMachine, }; diff --git a/src/userland/libs/libAshetOS/build.zig b/src/userland/libs/libAshetOS/build.zig index 6139ba37..39890388 100644 --- a/src/userland/libs/libAshetOS/build.zig +++ b/src/userland/libs/libAshetOS/build.zig @@ -337,6 +337,7 @@ pub fn build(b: *std.Build) void { .arm => sub_build.addArg("-DPLATFORM_THUMB"), .rv32 => sub_build.addArg("-DPLATFORM_RISCV32"), .x86 => sub_build.addArg("-DPLATFORM_X86"), + .ppc => sub_build.addArg("-DPLATFORM_PPC"), } sub_build.addPrefixedFileArg("@", lib_build_dir.path(b, "assembly-files.rsp")); diff --git a/src/userland/libs/libAshetOS/src/binding-template.S b/src/userland/libs/libAshetOS/src/binding-template.S index 92ca5057..27642c42 100644 --- a/src/userland/libs/libAshetOS/src/binding-template.S +++ b/src/userland/libs/libAshetOS/src/binding-template.S @@ -45,6 +45,9 @@ SYMBOL_NAME: .align 2 // align word to to 4 so we have sane pointer semantics: .set .syscall_address, SYMBOL_NAME + 1 +#elif defined(PLATFORM_PPC) + trap // TODO: Implement this + #else #error "Unsupported Platform!" #endif