diff --git a/core/broadway.cpp b/core/broadway.cpp index 028d3d2..785e924 100644 --- a/core/broadway.cpp +++ b/core/broadway.cpp @@ -36,6 +36,9 @@ void broadway::execute(ircolib::u32 instr, mem &mem) { case 15: // addis rd, ra, simm addis(instr); break; + case 16: // bcx BO, BI, target + bcx(instr); + break; case 18: // bx target bx(instr); break; diff --git a/core/broadway.hpp b/core/broadway.hpp index 9dab31b..c754e82 100644 --- a/core/broadway.hpp +++ b/core/broadway.hpp @@ -28,6 +28,7 @@ struct broadway { void addi(ircolib::u32); void ori(ircolib::u32); void bx(ircolib::u32); + void bcx(ircolib::u32); void move_spr(ircolib::u32); void stwu(ircolib::u32, mem &); void sth(ircolib::u32, mem &); diff --git a/core/broadway/instructions.cpp b/core/broadway/instructions.cpp index 159b043..1188a01 100644 --- a/core/broadway/instructions.cpp +++ b/core/broadway/instructions.cpp @@ -27,14 +27,54 @@ void broadway::bx(ircolib::u32 instr) { const bool link = instr & 1; const bool absolute = instr & 2; - ircolib::s32 LI = (ircolib::s32(instr << 6) >> 6) & 0x03FFFFFC; + ircolib::s32 li = (ircolib::s32(instr << 6) >> 6) & 0xFFFFFFFC; if (!absolute) - LI += pc - 4; + li += pc - 4; if (link) lr = pc; - pc = LI; + pc = li; +} + +void broadway::bcx(ircolib::u32 instr) { + const bool link = instr & 1; + const bool absolute = instr & 2; + + ircolib::s32 bd = (ircolib::s32(instr << 16) >> 16) & 0xFFFFFFFC; + if (!absolute) + bd += pc - 4; + + if (!ircolib::is_bit_set(instr)) + ircolib::panic("broadway::bcx unimplemented variants with bit 25 == 0"); + + 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::move_spr(ircolib::u32 instr) {