From d057a31269b9f1c373260c2e293d94d5cd96d497 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 13 May 2026 17:46:37 +0200 Subject: [PATCH] xfb loop copy finished --- core/broadway.cpp | 36 +++++++- core/broadway.hpp | 24 +++++- core/broadway/instructions.cpp | 151 ++++++++++++++++++++++++++------- core/broadway/mmio/vi.cpp | 25 ++++++ core/broadway/mmio/vi.hpp | 56 ++++++++++++ core/broadway/utils.hpp | 3 + 6 files changed, 257 insertions(+), 38 deletions(-) diff --git a/core/broadway.cpp b/core/broadway.cpp index d61ff8d..fb2fd32 100644 --- a/core/broadway.cpp +++ b/core/broadway.cpp @@ -28,8 +28,27 @@ ircolib::u32 broadway::fetch(mem &mem) { return val; } +void broadway::decode_special(ircolib::u32 instr, mem &mem) { + switch (utils::secondary(instr)) { + case 0x153: + mfspr(instr); + break; + case 0x1D3: + mtspr(instr); + break; + case 0x10A: + add(instr); + break; + default: + ircolib::panic("broadway unknown special 0x{:04X}", utils::secondary(instr)); + } +} + void broadway::execute(ircolib::u32 instr, mem &mem) { switch (utils::primary(instr)) { + case 11: // cmpi crfD, L, rA, simm + cmpi(instr); + break; case 14: // addi rd, ra, simm addi(instr); break; @@ -42,15 +61,24 @@ void broadway::execute(ircolib::u32 instr, mem &mem) { case 18: // bx target bx(instr); break; + case 19: + bclrx(instr); + break; + case 21: + rlwinm(instr); + break; case 24: // ori ra, rs, uimm ori(instr); break; - case 31: // mfspr rd, spr - move_spr(instr); + case 31: + decode_special(instr, mem); break; - case 32: // mfspr rd, spr + case 32: // lwz rd, d(ra) lwz(instr, mem); break; + case 33: // lwz rd, d(ra) + lwzu(instr, mem); + break; case 36: // stw rs, d(ra) stw(instr, mem); break; @@ -80,7 +108,7 @@ void broadway::print_disasm(ircolib::u32 instr) { size_t j; for (j = 0; j < count; j++) { - printf("0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + std::println("\t0x{:x}:\t{}\t\t{}", insn[j].address, insn[j].mnemonic, insn[j].op_str); } cs_free(insn, count); diff --git a/core/broadway.hpp b/core/broadway.hpp index dafb379..b206333 100644 --- a/core/broadway.hpp +++ b/core/broadway.hpp @@ -17,22 +17,42 @@ struct broadway { void execute(ircolib::u32, mem &); bool disasm_available = true; - ircolib::u32 pc = 0, lr = 0, ctr = 0; + ircolib::u32 pc = 0, lr = 0, ctr = 0, cr = 0; + union { + struct { + unsigned bytecount : 7; + unsigned : 22; + unsigned ca : 1; + unsigned ov : 1; + unsigned so : 1; + }; + + ircolib::u32 raw; + } xer; + std::array gpr{}; // ircolib::u32 const_gpr_lookup{}; csh capstone; // Xbyak::CodeGenerator code; // instructions + void decode_special(ircolib::u32, mem &); + + void add(ircolib::u32); void addis(ircolib::u32); void addi(ircolib::u32); void ori(ircolib::u32); void bx(ircolib::u32); void bcx(ircolib::u32); - void move_spr(ircolib::u32); + void mtspr(ircolib::u32); + void mfspr(ircolib::u32); void stw(ircolib::u32, mem &); void stwu(ircolib::u32, mem &); void sth(ircolib::u32, mem &); void lwz(ircolib::u32, mem &); + void bclrx(ircolib::u32); + void cmpi(ircolib::u32); + void rlwinm(ircolib::u32); + void lwzu(ircolib::u32, mem &); }; } // namespace weee::core diff --git a/core/broadway/instructions.cpp b/core/broadway/instructions.cpp index e9422f7..b8643c7 100644 --- a/core/broadway/instructions.cpp +++ b/core/broadway/instructions.cpp @@ -3,6 +3,8 @@ #include namespace weee::core { +void broadway::add(ircolib::u32 instr) { gpr[utils::RD(instr)] = gpr[utils::RA(instr)] + gpr[utils::RB(instr)]; } + void broadway::addi(ircolib::u32 instr) { if (utils::RA(instr) == 0) { // lis gpr[utils::RD(instr)] = ircolib::s32(utils::SIMM(instr)); @@ -77,41 +79,38 @@ void broadway::bcx(ircolib::u32 instr) { pc = bd; } -void broadway::move_spr(ircolib::u32 instr) { - const size_t spr_field = (instr >> 12) & 0x3FF; - const size_t direction = (instr >> 1) & 0x3FF; - - if (direction == 339) { - switch (spr_field) { - case 0x80: - gpr[utils::RD(instr)] = lr; - break; - case 0x90: - gpr[utils::RD(instr)] = ctr; - break; - default: - ircolib::panic("broadway::mfspr with unimplemented spr field of value {}", spr_field); - } - - return; +void broadway::mfspr(ircolib::u32 instr) { + const size_t spr_field = (instr >> 11) & 0x3FF; + switch (spr_field) { + case 0b0000100000: + gpr[utils::RD(instr)] = xer.raw; + break; + case 0b0100000000: + gpr[utils::RD(instr)] = lr; + break; + case 0b0100100000: + gpr[utils::RD(instr)] = ctr; + break; + default: + ircolib::panic("broadway::mfspr with unimplemented spr field of value 0x{:04X}", spr_field); } +} - if (direction == 467) { - switch (spr_field) { - case 0x80: - lr = gpr[utils::RS(instr)]; - break; - case 0x90: - ctr = gpr[utils::RS(instr)]; - break; - default: - ircolib::panic("broadway::mtspr with unimplemented spr field of value {}", spr_field); - } - - return; +void broadway::mtspr(ircolib::u32 instr) { + const size_t spr_field = (instr >> 11) & 0x3FF; + switch (spr_field) { + case 0b0000100000: + xer.raw = gpr[utils::RS(instr)]; + break; + case 0b0100000000: + lr = gpr[utils::RS(instr)]; + break; + case 0b0100100000: + ctr = gpr[utils::RS(instr)]; + break; + default: + ircolib::panic("broadway::mtspr with unimplemented spr field of value 0x{:04X}", spr_field); } - - ircolib::panic("broadway::move_spr with unknown sub op {}", direction); } void broadway::stwu(ircolib::u32 instr, mem &mem) { @@ -151,4 +150,92 @@ void broadway::lwz(ircolib::u32 instr, mem &mem) { ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr); gpr[utils::RD(instr)] = mem.read32(ea); } + +void broadway::bclrx(ircolib::u32 instr) { + const bool link = instr & 1; + + ircolib::s32 bd = lr & 0xFFFFFFFC; + + if (!ircolib::is_bit_set(instr)) { + if (!ircolib::is_bit_set(instr)) + ircolib::panic("broadway::bclrx unimplemented variants with bit 24 == 0"); + + if (!ircolib::is_bit_set(instr)) + ircolib::panic("broadway::bclrx unimplemented variants with bit 23 == 0"); + + const ircolib::u8 bi = (instr >> 16) & 0x1f; + + if (ircolib::is_bit_set(cr, 32 - bi)) { + if (link) + lr = pc; + + pc = bd; + } + + return; + } + + if (ircolib::is_bit_set(instr)) { // always + if (link) + lr = pc; + + pc = bd; + return; + } + + if (ircolib::is_bit_set(instr)) { // --ctr == 0 + if (--ctr != 0) + return; + + if (link) + lr = pc; + + pc = bd; + return; + } + + // --ctr != 0 + if (--ctr == 0) + return; + + if (link) + lr = pc; + + pc = bd; +} + +void broadway::cmpi(ircolib::u32 instr) { + const ircolib::s32 a = gpr[utils::RA(instr)]; + const ircolib::s32 simm = utils::SIMM(instr); + ircolib::u8 c; + if (a < simm) + c = 0b001; + else if (a > simm) + c = 0b010; + else + c = 0b100; + + const ircolib::u32 result = ((xer.so << 3) | c) << (28 - 4 * utils::crfD(instr)); + cr &= ~(0xffff << (28 - 4 * utils::crfD(instr))); + cr |= result; +} + +void broadway::rlwinm(ircolib::u32 instr) { + const ircolib::u8 sh = (instr >> 11) & 0x1f; + ircolib::u32 r = std::rotl(gpr[utils::RS(instr)], sh); + const ircolib::u8 mb = (instr >> 6) & 0x1f; + const ircolib::u8 me = (instr >> 1) & 0x1f; + + r &= ~((0xFFFF'FFFF >> mb) << me); + gpr[utils::RA(instr)] = r; +} + +void broadway::lwzu(ircolib::u32 instr, mem &mem) { + if (utils::RA(instr) == 0 || utils::RA(instr) == utils::RD(instr)) + ircolib::panic("broadway::lwzu with ra == 0"); + + const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr); + gpr[utils::RD(instr)] = mem.read32(EA); + gpr[utils::RA(instr)] = EA; +} } // namespace weee::core diff --git a/core/broadway/mmio/vi.cpp b/core/broadway/mmio/vi.cpp index eaa1283..40b2a74 100644 --- a/core/broadway/mmio/vi.cpp +++ b/core/broadway/mmio/vi.cpp @@ -18,6 +18,14 @@ void video_interface::write16(ircolib::u32 addr, ircolib::u16 value) { case 0x02: dcr.raw = value; break; + case 0x4a: + hsr.raw = value; + break; + case 0x6c: + viclk = value & 1; + break; + case 0x70: + break; default: ircolib::panic("video_interface::write16 to unimplemented addr 0x{:04X} with value 0x{:04X}", addr, value); } @@ -46,6 +54,23 @@ void video_interface::write32(ircolib::u32 addr, ircolib::u32 value) { case 0x18: bboi.raw = value; break; + case 0x1c: + tfbl.raw = value; + break; + case 0x24: + bfbl.raw = value; + break; + case 0x4c: + case 0x50: + case 0x54: + fct0[addr - 0x4c].raw = value; + break; + case 0x58: + case 0x5c: + case 0x60: + case 0x64: + fct1[addr - 0x58].raw = value; + break; default: ircolib::panic("video_interface::write32 to unimplemented addr 0x{:04X} with value 0x{:08X}", addr, value); } diff --git a/core/broadway/mmio/vi.hpp b/core/broadway/mmio/vi.hpp index 4828af7..3e6defb 100644 --- a/core/broadway/mmio/vi.hpp +++ b/core/broadway/mmio/vi.hpp @@ -79,5 +79,61 @@ struct video_interface { ircolib::u32 raw; } bbei, bboi; + + union TFBL { + struct { + unsigned : 9; + unsigned fbb : 15; + unsigned xof : 4; + unsigned : 4; + }; + + ircolib::u32 raw; + } tfbl; + + union BFBL { + struct { + unsigned : 9; + unsigned fbb : 15; + unsigned y : 8; + }; + + ircolib::u32 raw; + } bfbl; + + union FCT012 { + struct { + unsigned tap0 : 10; + unsigned tap1 : 10; + unsigned tap2 : 10; + unsigned : 2; + }; + + ircolib::u32 raw; + } fct0[3]; + + union FCT3456 { + struct { + unsigned tap0 : 8; + unsigned tap1 : 8; + unsigned tap2 : 8; + unsigned tap3 : 8; + }; + + ircolib::u32 raw; + } fct1[4]; + + union HSR { + struct { + unsigned stp : 9; + unsigned : 3; + unsigned hs_en : 1; + unsigned : 3; + }; + + ircolib::u16 raw; + } hsr; + + bool viclk; }; } // namespace weee::core diff --git a/core/broadway/utils.hpp b/core/broadway/utils.hpp index 365442c..017785f 100644 --- a/core/broadway/utils.hpp +++ b/core/broadway/utils.hpp @@ -3,9 +3,12 @@ namespace weee::core::utils { static inline ircolib::u8 primary(ircolib::u32 instr) { return (instr >> 26) & 0x3f; } +static inline ircolib::u16 secondary(ircolib::u32 instr) { return (instr >> 1) & 0x1ff; } static inline ircolib::u8 RD(ircolib::u32 instr) { return (instr >> 21) & 0x1f; } +static inline ircolib::u8 RB(ircolib::u32 instr) { return (instr >> 11) & 0x1f; } static inline ircolib::u8 RS(ircolib::u32 instr) { return RD(instr); } static inline ircolib::u8 RA(ircolib::u32 instr) { return (instr >> 16) & 0x1f; } static inline ircolib::u16 UIMM(ircolib::u32 instr) { return instr & 0xffff; } static inline ircolib::s16 SIMM(ircolib::u32 instr) { return UIMM(instr); } +static inline ircolib::u8 crfD(ircolib::u32 instr) { return (instr >> 23) & 7; } } // namespace weee::core::utils