Compare commits

...

30 Commits

Author SHA1 Message Date
iris 35f20a16b8 i should implement DSP DMA... 2026-05-20 17:55:07 +02:00
iris f9ab690ccd i need to start caring about carry >.< 2026-05-19 12:26:51 +02:00
iris 8824b6b75a Merge commit 'f070e484cdac8a6d6a2e6f039aa69555e0739133' 2026-05-19 08:51:06 +02:00
iris f070e484cd Squashed 'external/ircolib/' changes from bb3f168e1..d611a21e5
d611a21e5 imma stop using size_t

git-subtree-dir: external/ircolib
git-subtree-split: d611a21e50fcfdfb5f34a7f79c4c690c50d85c5f
2026-05-19 08:51:06 +02:00
iris 7d706e703f sdf 2026-05-19 08:48:58 +02:00
iris 03a6a9b383 ok imma stop using size_t at this point 2026-05-19 08:48:52 +02:00
iris 8d6d6c0672 Merge commit 'a8099e3aeafb464445d1c3ee3a852697d37a1e69' 2026-05-19 08:43:09 +02:00
iris a8099e3aea Squashed 'external/ircolib/' changes from 7df4ec224..bb3f168e1
bb3f168e1 fix compilation on windows

git-subtree-dir: external/ircolib
git-subtree-split: bb3f168e134aee5dd5460e57b43d06ef84a06092
2026-05-19 08:43:08 +02:00
iris 2f0c837464 cool 2026-05-19 00:11:48 +02:00
iris e265677727 Squashed 'external/ircolib/' changes from ec06dab..7df4ec2
7df4ec2 clear bit

git-subtree-dir: external/ircolib
git-subtree-split: 7df4ec22463394c2763fef61b581b3d2980778ef
2026-05-19 00:06:03 +02:00
iris f375b9c0ee Merge commit 'e26567772789c28c79920624e1622a7a3306c560' 2026-05-19 00:06:03 +02:00
iris 59b6c70c3f booogs 2026-05-19 00:04:56 +02:00
iris 0754d52d67 Squashed 'external/ircolib/' changes from cf68f4c..ec06dab
ec06dab logging

git-subtree-dir: external/ircolib
git-subtree-split: ec06dab96452fb0d3b4c93e71dbdf9869e39f7e5
2026-05-18 23:29:31 +02:00
iris b50e0a529d Merge commit '0754d52d67766f39276ae32771bca3f28b1ac3dc' 2026-05-18 23:29:31 +02:00
iris 74b13b4d70 Squashed 'external/ircolib/' changes from 8cb69c8..cf68f4c
cf68f4c improvements

git-subtree-dir: external/ircolib
git-subtree-split: cf68f4c385c6f2def0e359c3c2a7621ce78062a8
2026-05-18 23:28:07 +02:00
iris 8c0b0bfc1b Merge commit '74b13b4d7049f9181b1241195324e85af2d9653a' 2026-05-18 23:28:07 +02:00
iris 5024d45e58 Squashed 'external/ircolib/' changes from ce3cd72..8cb69c8
8cb69c8 Merge commit '634f6ff006c8811c47a7a07356f46214f5d8a736' as 'external/ircolib'
2230d4c dhjkfhsdf
c2e22fb better logs
eee9fcf there might be an off by 1 error...
aeb5094 getting floating point stuff now
b13161f Branches simplified, and working!
e48f6a6 trying to simplify branches
b2f415a start crediting people <3
723e668 rfi
9a2d437 oris
7c456e5 rendering Panda correctly
df6f382 Merge commit '4870214d575293257604fa75a6458f0f0a7ea083' as 'external/yuv2rgb'
4870214 Squashed 'external/yuv2rgb/' content from commit ee78934c8
8bd3935 YUV
9df9eda almost rendering correctly
c8d2b36 Merge commit '411251c6242b04119edc41ce83f09f0714e2d32b' as 'external/SDL'
411251c Squashed 'external/SDL/' content from commit 716c767b7
d057a31 xfb loop copy finished
9c3a678 getting closer and closer to the xfb copy loop in panda
fc26f75 bcx partially implemented
df68e42 getting conditional branch now
2be9570 getting to my first branch now
e598f02 Merge commit '2201a0227297b9251717e44adc32554a51ca0ed6' as 'external/xbyak'
2201a02 Squashed 'external/xbyak/' content from commit 431abd86
fc5beeb start executing
0b1d14b loading dols
5f1e3aa asdfasfd
be41857 todo list in readme
93cab1e we load the ELF correctly it seems!
831e03e Merge commit '884e597e3572c5a47c15270649c1e0c24fae3a18' as 'external/cflags'
884e597 Squashed 'external/cflags/' content from commit cc3ea1b
cc2dfc0 do not care about sections as hazel teaches
2b01767 cool
f563827 Merge commit '44fea07a8bae832d53bfdcec3b4cfbf0b60f987d' as 'external/ircolib'
44fea07 Squashed 'external/ircolib/' content from commit ce3cd726
1803ee7 ok
e5413f9 introduce capstone
c0de074 Merge commit '802798ce3c8baa4697120580f87bc1ee377306d3' as 'external/capstone'
802798c Squashed 'external/capstone/' content from commit e46f64fa
ef8e742 read ELF
fede961 Merge commit 'a67f311330461cf90801a74fe351a4a80a5abb11' as 'external/ELFIO'
a67f311 Squashed 'external/ELFIO/' content from commit 94f7706
ad83dec gitignore
9130ede first commit

git-subtree-dir: external/ircolib
git-subtree-split: 8cb69c875cb5e3e3a8f18204ed88ea73de456df6
2026-05-18 23:22:33 +02:00
iris 83e3f5423f Merge commit '5024d45e589ebd708e2d5091632197235a1b1e23' 2026-05-18 23:22:33 +02:00
iris bb54f0c15b sadfasdf 2026-05-18 23:22:30 +02:00
iris 634f6ff006 Squashed 'external/ircolib/' content from commit ce3cd72
git-subtree-dir: external/ircolib
git-subtree-split: ce3cd726c8df8388d554abf8bb55d55020eb4450
2026-05-18 23:13:51 +02:00
iris f72110272d Merge commit '634f6ff006c8811c47a7a07356f46214f5d8a736' as 'external/ircolib' 2026-05-18 23:13:51 +02:00
iris 2230d4c662 dhjkfhsdf 2026-05-18 23:13:35 +02:00
iris c2e22fb742 better logs 2026-05-18 23:00:43 +02:00
iris eee9fcfb17 there might be an off by 1 error... 2026-05-18 17:42:02 +02:00
iris aeb5094b05 getting floating point stuff now 2026-05-18 12:06:03 +02:00
iris b13161f9c2 Branches simplified, and working! 2026-05-18 09:56:15 +02:00
iris e48f6a6402 trying to simplify branches 2026-05-15 18:11:07 +02:00
iris b2f415a6ea start crediting people <3 2026-05-15 09:57:57 +02:00
iris 723e66871d rfi 2026-05-15 09:45:26 +02:00
iris 9a2d437b24 oris 2026-05-14 16:49:10 +02:00
31 changed files with 1671 additions and 255 deletions
+8 -1
View File
@@ -17,6 +17,7 @@ if(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(NOMINMAX)
endif()
add_compile_options(-fno-operator-names)
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
set(CAPSTONE_PPC_SUPPORT ON)
@@ -27,6 +28,12 @@ add_executable(weee main.cpp core/mem.cpp core/loaders/elf.cpp
core/loaders/dol.cpp
core/broadway.cpp
core/broadway/instructions.cpp
core/broadway/mmio/vi.cpp)
core/broadway/mmio/vi.cpp
core/broadway/mmio/pi.cpp
core/broadway/mmio/mi.cpp
core/broadway/mmio/dsp.cpp
core/broadway/mmio/ai.cpp
core/broadway/mmio/exi.cpp
core/broadway/mmio/si.cpp)
target_link_libraries(weee PUBLIC SDL3::SDL3 capstone)
target_include_directories(weee PUBLIC core)
+4 -1
View File
@@ -3,4 +3,7 @@
- [x] ELF
- [x] DOL
- [x] panda.dol
- [ ] libogc simple examples
- [ ] libogc simple examples
## Cool people
- [layle](https://github.com/ioncodes/), thanks for the IDA plugins and resources. Check out [*his* Wii emulator](https://github.com/ioncodes/gecko)
+197 -28
View File
@@ -16,83 +16,252 @@ broadway::broadway() {
void broadway::set_pc(ircolib::u32 value) { pc = value; }
void broadway::run(mem &mem) {
for (int i = 0; i < 12150000; i++) {
execute(fetch(mem), mem);
std::println("pc: 0x{:08X}", pc);
for (int i = 0; i < 1000000; i++) {
ircolib::u32 instr = fetch(mem);
execute(instr, mem);
}
}
ircolib::u32 broadway::fetch(mem &mem) {
ircolib::u32 val = mem.read32(pc);
ircolib::u32 val = mem.read32(pc)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("broadway read failed. Reason {} (pc: 0x{:08X})", e, pc);
return std::expected<ircolib::u32, std::string>();
})
.value();
pc += 4;
return val;
}
void broadway::decode_special(ircolib::u32 instr, mem &mem) {
switch (utils::secondary(instr)) {
case 0x153:
mfspr(instr);
void broadway::decode_special3(ircolib::u32 instr, mem &mem) {
auto secondary = utils::secondary(instr);
switch (secondary) {
case 38:
mtfsb1(instr);
break;
case 711:
mtfsf(instr);
break;
default:
std::println("broadway unknown special3 {} (0x{:04X}) (pc 0x{:08X})", secondary, secondary, pc - 4);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::decode_special2(ircolib::u32 instr, mem &mem) {
auto secondary = utils::secondary(instr);
switch (secondary) {
case 0x000:
cmp(instr);
break;
case 0x008:
subfc(instr);
break;
case 0x00A:
addc(instr);
break;
case 0x013:
mfcr(instr);
break;
case 0x017:
lwzx(instr, mem);
break;
case 0x01C:
and(instr);
break;
case 0x020:
cmpl(instr);
break;
case 0x028:
subf(instr);
break;
case 0x053:
mfmsr(instr);
break;
case 0x088:
subfe(instr);
break;
case 0x08A:
adde(instr);
break;
case 0x090:
mtcrf(instr);
break;
case 0x092:
mtmsr(instr);
break;
case 0x097:
stwx(instr, mem);
break;
case 0x0CA:
addze(instr);
break;
case 0x0D2:
ircolib::warn("broadway TODO mtsr (pc 0x{:08X})", pc - 4);
break;
case 0x0EB:
mullw(instr);
break;
case 0x117:
lhzx(instr, mem);
break;
case 0x173:
mftb(instr);
break;
case 0x1BC:
or (instr);
break;
case 0x153:
case 0x1D3:
mtspr(instr);
mftspr(ircolib::is_bit_set<ircolib::u32, 7>(secondary), instr);
break;
case 0x1DC:
nand(instr);
break;
case 0x10A:
add(instr);
break;
case 0x1CB:
divwu(instr);
break;
case 0x256: // sync
break;
case 0x318:
sraw(instr);
break;
default:
ircolib::panic("broadway unknown special 0x{:04X}", utils::secondary(instr));
std::println("broadway unknown special2 {} (0x{:04X}) (pc 0x{:08X})", secondary, secondary, pc - 4);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::decode_special1(ircolib::u32 instr, mem &mem) {
switch (utils::secondary(instr)) {
case 0x10:
bclrx(instr);
break;
case 0x32:
rfi(instr);
break;
case 0x96: // isync
break;
default:
std::println("broadway unknown special1 {} (0x{:04X}) (pc 0x{:08X})", utils::secondary(instr),
utils::secondary(instr), pc - 4);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("LR: 0x{:08X}", lr);
}
}
void broadway::execute(ircolib::u32 instr, mem &mem) {
switch (utils::primary(instr)) {
case 11: // cmpi crfD, L, rA, simm
const auto primary = utils::primary(instr);
switch (primary) {
case 7:
mulli(instr);
break;
case 8:
subfic(instr);
break;
case 10:
cmpli(instr);
break;
case 11:
cmpi(instr);
break;
case 14: // addi rd, ra, simm
case 12:
addic(instr);
break;
case 13:
addicr(instr);
break;
case 14:
addi(instr);
break;
case 15: // addis rd, ra, simm
case 15:
addis(instr);
break;
case 16: // bcx BO, BI, target
case 16:
bcx(instr);
break;
case 18: // bx target
case 18:
bx(instr);
break;
case 19:
bclrx(instr);
decode_special1(instr, mem);
break;
case 20:
rlwimi(instr);
break;
case 21:
rlwinm(instr);
break;
case 24: // ori ra, rs, uimm
case 24:
ori(instr);
break;
case 31:
decode_special(instr, mem);
case 25:
oris(instr);
break;
case 32: // lwz rd, d(ra)
case 26:
xori(instr);
break;
case 28:
andi(instr);
break;
case 29:
andis(instr);
break;
case 31:
decode_special2(instr, mem);
break;
case 32:
lwz(instr, mem);
break;
case 33: // lwz rd, d(ra)
case 33:
lwzu(instr, mem);
break;
case 36: // stw rs, d(ra)
case 34:
lbz(instr, mem);
break;
case 36:
stw(instr, mem);
break;
case 37: // stwu rs, d(ra)
case 37:
stwu(instr, mem);
break;
case 44: // stwu rs, d(ra)
case 38:
stb(instr, mem);
break;
case 39:
stbu(instr, mem);
break;
case 40:
lhz(instr, mem);
break;
case 44:
sth(instr, mem);
break;
case 45:
sthu(instr, mem);
break;
case 50:
lfd(instr, mem);
break;
case 63:
decode_special3(instr, mem);
break;
default:
std::println("broadway::execute unimplemented instruction 0x{:08X} / 0b{:032b}", instr, instr);
std::println("broadway::execute unimplemented instruction 0x{:08X} / 0b{:032b} ({})", instr, instr, primary);
std::println("disassembly:");
print_disasm(instr);
ircolib::panic("");
ircolib::panic("LR: 0x{:08X}", lr);
}
}
@@ -102,11 +271,11 @@ void broadway::print_disasm(ircolib::u32 instr) {
cs_insn *insn;
auto instr_buff = ircolib::integral_to_slice(std::byteswap(instr));
size_t count = cs_disasm(capstone, instr_buff.data(), instr_buff.size(), pc - 4, 1, &insn);
ircolib::u32 count = cs_disasm(capstone, instr_buff.data(), instr_buff.size(), pc - 4, 1, &insn);
if (count <= 0)
return;
size_t j;
ircolib::u32 j;
for (j = 0; j < count; j++) {
std::println("\t0x{:x}:\t{}\t\t{}", insn[j].address, insn[j].mnemonic, insn[j].op_str);
}
+86 -4
View File
@@ -17,7 +17,7 @@ struct broadway {
void execute(ircolib::u32, mem &);
bool disasm_available = true;
ircolib::u32 pc = 0, lr = 0, ctr = 0, cr = 0;
ircolib::u32 pc = 0, lr = 0, ctr = 0, cr = 0, srr0 = 0, fpscr = 0, msr = 0, tbl = 0, tbu = 0;
union {
struct {
unsigned bytecount : 7;
@@ -30,29 +30,111 @@ struct broadway {
ircolib::u32 raw;
} xer;
void set_cr(ircolib::u8 value, ircolib::u8 index) {
cr &= ~(0xffff << index * 4);
cr |= (value << index * 4);
}
bool get_cr_bit(ircolib::u8 index, ircolib::u8 bit) { return (cr >> index * 4) & (1 << (4 - bit)); }
// bat registers indexes
static constexpr ircolib::u32 BAT_LOWER_OFFSET = 0;
static constexpr ircolib::u32 BAT_UPPER_OFFSET = 8;
std::array<ircolib::u32, 16> ibat, dbat;
std::array<ircolib::u32, 32> gpr{};
struct Fgr {
ircolib::u64 ps0, ps1;
};
std::array<Fgr, 32> fgrs{};
// ircolib::u32 const_gpr_lookup{};
csh capstone;
// Xbyak::CodeGenerator code;
// instructions
void decode_special(ircolib::u32, mem &);
void decode_special1(ircolib::u32, mem &);
void decode_special2(ircolib::u32, mem &);
void decode_special3(ircolib::u32, mem &);
void branch(bool, bool, ircolib::u32);
bool test_cond_and_ctr(ircolib::u32);
void andi(ircolib::u32);
void andis(ircolib::u32);
void and(ircolib::u32);
void add(ircolib::u32);
void addc(ircolib::u32);
void adde(ircolib::u32);
void addze(ircolib::u32);
void addis(ircolib::u32);
void addi(ircolib::u32);
void addic(ircolib::u32);
void addicr(ircolib::u32);
void ori(ircolib::u32);
void oris(ircolib::u32);
void bx(ircolib::u32);
void bcx(ircolib::u32);
void mtspr(ircolib::u32);
void mfspr(ircolib::u32);
void mftspr(bool, ircolib::u32);
void mtcrf(ircolib::u32);
void stw(ircolib::u32, mem &);
void stb(ircolib::u32, mem &);
void stwu(ircolib::u32, mem &);
void sthu(ircolib::u32, mem &);
void stwx(ircolib::u32, mem &);
void stbu(ircolib::u32, mem &);
void sth(ircolib::u32, mem &);
void lbz(ircolib::u32, mem &);
void lwz(ircolib::u32, mem &);
void lwzx(ircolib::u32, mem &);
void lhz(ircolib::u32, mem &);
void lhzx(ircolib::u32, mem &);
void lfd(ircolib::u32, mem &);
void bclrx(ircolib::u32);
void cmpi(ircolib::u32);
void cmpli(ircolib::u32);
void cmp(ircolib::u32);
void cmpl(ircolib::u32);
void rlwinm(ircolib::u32);
void rlwimi(ircolib::u32);
void lwzu(ircolib::u32, mem &);
void rfi(ircolib::u32);
void mfcr(ircolib::u32);
void mtfsf(ircolib::u32);
void mtfsb1(ircolib::u32);
void mtfsb0(ircolib::u32);
void mfmsr(ircolib::u32);
void mtmsr(ircolib::u32);
void mullw(ircolib::u32);
void mulli(ircolib::u32);
void nand(ircolib::u32);
void subf(ircolib::u32);
void subfc(ircolib::u32);
void subfic(ircolib::u32);
void subfe(ircolib::u32);
void or (ircolib::u32);
void xori(ircolib::u32);
void divwu(ircolib::u32);
void mftb(ircolib::u32);
void sraw(ircolib::u32);
inline void cr0_update(bool condition, ircolib::s32 result) {
if (condition) {
const bool b0 = result < 0;
const bool b1 = result >= 0;
const bool b2 = result == 0;
const bool b3 = xer.so;
set_cr((b0 << 3) | (b1 << 2) | (b2 << 1) | (b3 << 0), 0);
}
}
inline void cr1_update(bool condition) {
if (condition) {
const ircolib::u8 field = (fpscr >> 28) & 0xf;
set_cr(field, 1);
}
}
};
} // namespace weee::core
+540 -121
View File
@@ -1,12 +1,40 @@
#include <broadway/utils.hpp>
#include "ircolib/log.hpp"
#include <broadway/utils.hpp>
#include <mem.hpp>
namespace weee::core {
void broadway::add(ircolib::u32 instr) { gpr[utils::RD(instr)] = gpr[utils::RA(instr)] + gpr[utils::RB(instr)]; }
void broadway::add(ircolib::u32 instr) {
gpr[utils::RD(instr)] = gpr[utils::RA(instr)] + gpr[utils::RB(instr)];
cr0_update(instr & 1, gpr[utils::RD(instr)]);
}
void broadway::addc(ircolib::u32 instr) {
ircolib::u32 sum;
bool carry = __builtin_add_overflow(gpr[utils::RA(instr)], gpr[utils::RB(instr)], &sum);
cr0_update(instr & 1, sum);
xer.ca = carry;
gpr[utils::RD(instr)] = sum;
}
void broadway::adde(ircolib::u32 instr) {
ircolib::u32 sum;
bool c0 = __builtin_add_overflow(gpr[utils::RA(instr)], gpr[utils::RB(instr)], &sum);
bool c1 = __builtin_add_overflow(sum, xer.ca, &sum);
cr0_update(instr & 1, sum);
xer.ca = c0 | c1;
gpr[utils::RD(instr)] = sum;
}
void broadway::addze(ircolib::u32 instr) {
ircolib::u32 sum;
bool c1 = __builtin_add_overflow(gpr[utils::RA(instr)], xer.ca, &sum);
cr0_update(instr & 1, sum);
xer.ca = c1;
gpr[utils::RD(instr)] = sum;
}
void broadway::addi(ircolib::u32 instr) {
if (utils::RA(instr) == 0) { // lis
if (utils::RA(instr) == 0) { // li
gpr[utils::RD(instr)] = ircolib::s32(utils::SIMM(instr));
return;
}
@@ -14,6 +42,21 @@ void broadway::addi(ircolib::u32 instr) {
gpr[utils::RD(instr)] = gpr[utils::RA(instr)] + (ircolib::s32(utils::SIMM(instr)));
}
void broadway::addic(ircolib::u32 instr) {
ircolib::u32 sum;
bool carry = __builtin_add_overflow(gpr[utils::RA(instr)], ircolib::s32(utils::SIMM(instr)), &sum);
gpr[utils::RD(instr)] = sum;
xer.ca = carry;
}
void broadway::addicr(ircolib::u32 instr) {
ircolib::u32 sum;
bool carry = __builtin_add_overflow(gpr[utils::RA(instr)], ircolib::s32(utils::SIMM(instr)), &sum);
cr0_update(true, sum);
gpr[utils::RD(instr)] = sum;
xer.ca = carry;
}
void broadway::addis(ircolib::u32 instr) {
if (utils::RA(instr) == 0) { // lis
gpr[utils::RD(instr)] = ircolib::s32(utils::SIMM(instr)) << 16;
@@ -24,19 +67,36 @@ void broadway::addis(ircolib::u32 instr) {
}
void broadway::ori(ircolib::u32 instr) { gpr[utils::RA(instr)] = gpr[utils::RS(instr)] | utils::UIMM(instr); }
void broadway::oris(ircolib::u32 instr) {
gpr[utils::RA(instr)] = gpr[utils::RS(instr)] | ((ircolib::u32)utils::UIMM(instr) << 16);
}
void broadway::branch(bool aa, bool lk, ircolib::u32 bd) {
if (!aa)
bd += pc - 4;
if (lk)
lr = pc;
pc = bd;
}
void broadway::bx(ircolib::u32 instr) {
const bool link = instr & 1;
const bool absolute = instr & 2;
ircolib::s32 li = (ircolib::s32(instr << 6) >> 6) & 0xFFFFFFFC;
if (!absolute)
li += pc - 4;
branch(absolute, link, li);
}
if (link)
lr = pc;
bool broadway::test_cond_and_ctr(ircolib::u32 instr) {
const ircolib::u8 bo = (instr >> 21) & 0x1f;
const ircolib::u8 bi = (instr >> 16) & 0x1f;
pc = li;
const bool ctr_ok = ircolib::is_bit_set(bo, 2) || ((--ctr == 0) == (ircolib::is_bit_set(bo, 1)));
const bool cond_ok = ircolib::is_bit_set(bo, 4) || (get_cr_bit(0, bi) == ircolib::is_bit_set(bo, 3));
return cond_ok && ctr_ok;
}
void broadway::bcx(ircolib::u32 instr) {
@@ -44,72 +104,81 @@ void broadway::bcx(ircolib::u32 instr) {
const bool absolute = instr & 2;
ircolib::s32 bd = (ircolib::s32(instr << 16) >> 16) & 0xFFFFFFFC;
if (!absolute)
bd += pc - 4;
if (!ircolib::is_bit_set<ircolib::u32, 25>(instr))
ircolib::panic("broadway::bcx unimplemented variants with bit 25 == 0");
if (ircolib::is_bit_set<ircolib::u32, 23>(instr)) { // always
if (link)
lr = pc;
pc = bd;
return;
if (test_cond_and_ctr(instr)) {
branch(absolute, link, bd);
}
}
if (ircolib::is_bit_set<ircolib::u32, 22>(instr)) { // --ctr == 0
if (--ctr != 0)
void broadway::mftspr(bool dir, ircolib::u32 instr) {
const ircolib::u32 spr_field = (instr >> 11) & 0x3FF;
auto move_to_or_from_spr = [&](ircolib::u32 &spr) {
if (dir) { // mtspr
spr = gpr[utils::RS(instr)];
return;
}
// mfspr
gpr[utils::RD(instr)] = spr;
};
if (link)
lr = pc;
pc = bd;
return;
}
// --ctr != 0
if (--ctr == 0)
return;
if (link)
lr = pc;
pc = bd;
}
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;
move_to_or_from_spr(xer.raw);
break;
case 0b0100000000:
gpr[utils::RD(instr)] = lr;
move_to_or_from_spr(lr);
break;
case 0b0100100000:
gpr[utils::RD(instr)] = ctr;
move_to_or_from_spr(ctr);
break;
case 0b1101000000:
move_to_or_from_spr(srr0);
break;
case 0b1101100000: // srr1
break;
case 0b1000011111: // hid0
break;
case 0b1100011100: // hid2
break;
case 0b1100111111: // l2cr
break;
case 0b1000110000:
move_to_or_from_spr(ibat[BAT_LOWER_OFFSET + 0]);
break;
case 0b1000010000:
move_to_or_from_spr(ibat[BAT_UPPER_OFFSET + 0]);
break;
case 0b1001010000:
move_to_or_from_spr(ibat[BAT_UPPER_OFFSET + 1]);
break;
case 0b1010010000:
move_to_or_from_spr(ibat[BAT_UPPER_OFFSET + 2]);
break;
case 0b1011010000:
move_to_or_from_spr(ibat[BAT_UPPER_OFFSET + 3]);
break;
case 0b1100110000:
move_to_or_from_spr(dbat[BAT_LOWER_OFFSET + 0]);
break;
case 0b1101110000:
move_to_or_from_spr(dbat[BAT_LOWER_OFFSET + 1]);
break;
case 0b1100010000:
move_to_or_from_spr(dbat[BAT_UPPER_OFFSET + 0]);
break;
case 0b1101010000:
move_to_or_from_spr(dbat[BAT_UPPER_OFFSET + 1]);
break;
case 0b1110010000:
move_to_or_from_spr(dbat[BAT_UPPER_OFFSET + 2]);
break;
case 0b1111010000:
move_to_or_from_spr(dbat[BAT_UPPER_OFFSET + 3]);
break;
default:
ircolib::panic("broadway::mfspr with unimplemented spr field of value 0x{:04X}", spr_field);
}
}
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::warn("broadway::m{}spr with unimplemented spr field of value "
"0b{:010b} (0x{:04X}) (pc 0x{:08X})",
dir ? 't' : 'f', spr_field, spr_field, pc - 4);
}
}
@@ -118,8 +187,47 @@ void broadway::stwu(ircolib::u32 instr, mem &mem) {
ircolib::panic("broadway::stwu with ra == 0");
const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr);
mem.write32(EA, gpr[utils::RS(instr)]);
gpr[utils::RA(instr)] = EA;
auto _ = mem.write32(EA, gpr[utils::RS(instr)])
.and_then([&] {
gpr[utils::RA(instr)] = EA;
return std::expected<void, std::string>();
})
.or_else([&](std::string e) {
ircolib::panic("stwu broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::sthu(ircolib::u32 instr, mem &mem) {
if (utils::RA(instr) == 0)
ircolib::panic("broadway::sthu with ra == 0");
const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr);
auto _ = mem.write16(EA, gpr[utils::RS(instr)])
.and_then([&] {
gpr[utils::RA(instr)] = EA;
return std::expected<void, std::string>();
})
.or_else([&](std::string e) {
ircolib::panic("sthu broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::stbu(ircolib::u32 instr, mem &mem) {
if (utils::RA(instr) == 0)
ircolib::panic("broadway::stbu with ra == 0");
const ircolib::u32 EA = ircolib::s32(gpr[utils::RA(instr)]) + utils::SIMM(instr);
auto _ = mem.write8(EA, gpr[utils::RS(instr)])
.and_then([&] {
gpr[utils::RA(instr)] = EA;
return std::expected<void, std::string>();
})
.or_else([&](std::string e) {
ircolib::panic("stbu broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::stw(ircolib::u32 instr, mem &mem) {
@@ -128,7 +236,26 @@ void broadway::stw(ircolib::u32 instr, mem &mem) {
b = 0;
const ircolib::u32 EA = b + utils::SIMM(instr);
mem.write32(EA, gpr[utils::RS(instr)]);
auto _ = mem.write32(EA, gpr[utils::RS(instr)])
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("stw broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::stb(ircolib::u32 instr, mem &mem) {
ircolib::s32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
const ircolib::u32 EA = b + utils::SIMM(instr);
auto _ = mem.write8(EA, gpr[utils::RS(instr)])
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("stw broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::sth(ircolib::u32 instr, mem &mem) {
@@ -136,10 +263,28 @@ void broadway::sth(ircolib::u32 instr, mem &mem) {
if (utils::RA(instr) == 0)
b = 0;
const ircolib::s32 d = utils::SIMM(instr);
const ircolib::u32 EA = b + d;
const ircolib::u32 EA = b + utils::SIMM(instr);
mem.write16(EA, ircolib::u16(gpr[utils::RS(instr)]));
auto _ = mem.write16(EA, ircolib::u16(gpr[utils::RS(instr)]))
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("sth broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::stwx(ircolib::u32 instr, mem &mem) {
ircolib::u32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
const ircolib::u32 EA = b + gpr[utils::RB(instr)];
auto _ = mem.write32(EA, gpr[utils::RS(instr)])
.and_then([&] { return std::expected<void, std::string>(); })
.or_else([&](std::string e) {
ircolib::panic("stwx broadway write failed. Reason: {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<void, std::string>();
});
}
void broadway::lwz(ircolib::u32 instr, mem &mem) {
@@ -148,60 +293,104 @@ void broadway::lwz(ircolib::u32 instr, mem &mem) {
b = 0;
ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr);
gpr[utils::RD(instr)] = mem.read32(ea);
gpr[utils::RD(instr)] = mem.read32(ea)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("lwz broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::lwzx(ircolib::u32 instr, mem &mem) {
ircolib::u32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
ircolib::u32 ea = ircolib::s32(b) + gpr[utils::RB(instr)];
gpr[utils::RD(instr)] = mem.read32(ea)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("lwz broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::lhz(ircolib::u32 instr, mem &mem) {
ircolib::u32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr);
gpr[utils::RD(instr)] = mem.read16(ea)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("lhz broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::lhzx(ircolib::u32 instr, mem &mem) {
ircolib::u32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
ircolib::u32 ea = ircolib::s32(b) + gpr[utils::RB(instr)];
gpr[utils::RD(instr)] = mem.read16(ea)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("lhzx broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::lbz(ircolib::u32 instr, mem &mem) {
ircolib::u32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr);
gpr[utils::RD(instr)] = mem.read8(ea)
.and_then([&](ircolib::u32 val) { return std::expected<ircolib::u32, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("lbz broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::lfd(ircolib::u32 instr, mem &mem) {
ircolib::u32 b = gpr[utils::RA(instr)];
if (utils::RA(instr) == 0)
b = 0;
ircolib::u32 ea = ircolib::s32(b) + utils::SIMM(instr);
fgrs[utils::RD(instr)].ps0 =
mem.read64(ea)
.and_then([&](ircolib::u64 val) { return std::expected<ircolib::u64, std::string>(val); })
.or_else([&](std::string e) {
ircolib::panic("lfd broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u64, std::string>();
})
.value();
}
void broadway::bclrx(ircolib::u32 instr) {
const bool link = instr & 1;
ircolib::s32 bd = lr & 0xFFFFFFFC;
if (!ircolib::is_bit_set<ircolib::u32, 25>(instr)) {
if (!ircolib::is_bit_set<ircolib::u32, 24>(instr))
ircolib::panic("broadway::bclrx unimplemented variants with bit 24 == 0");
if (!ircolib::is_bit_set<ircolib::u32, 23>(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 (test_cond_and_ctr(instr)) {
branch(true, link, bd);
}
if (ircolib::is_bit_set<ircolib::u32, 23>(instr)) { // always
if (link)
lr = pc;
pc = bd;
return;
}
if (ircolib::is_bit_set<ircolib::u32, 22>(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) {
@@ -215,9 +404,53 @@ void broadway::cmpi(ircolib::u32 instr) {
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;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::cmpli(ircolib::u32 instr) {
const ircolib::u32 a = gpr[utils::RA(instr)];
const ircolib::u32 uimm = utils::UIMM(instr);
ircolib::u8 c;
if (a < uimm)
c = 0b001;
else if (a > uimm)
c = 0b010;
else
c = 0b100;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::cmp(ircolib::u32 instr) {
const ircolib::s32 a = gpr[utils::RA(instr)];
const ircolib::s32 b = gpr[utils::RB(instr)];
ircolib::u8 c;
if (a < b)
c = 0b001;
else if (a > b)
c = 0b010;
else
c = 0b100;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::cmpl(ircolib::u32 instr) {
const ircolib::u32 a = gpr[utils::RA(instr)];
const ircolib::u32 b = gpr[utils::RB(instr)];
ircolib::u8 c;
if (a < b)
c = 0b001;
else if (a > b)
c = 0b010;
else
c = 0b100;
const ircolib::u8 result = (xer.so << 3) | c;
set_cr(result, utils::crfD(instr));
}
void broadway::rlwinm(ircolib::u32 instr) {
@@ -225,9 +458,32 @@ void broadway::rlwinm(ircolib::u32 instr) {
ircolib::u32 r = std::rotl(gpr[utils::RS(instr)], sh);
const ircolib::u8 mb = (instr >> 6) & 0x1f;
const ircolib::u8 me = (instr >> 1) & 0x1f;
const ircolib::u32 start = 0xffffffff >> mb;
const ircolib::u32 end = 0x7fffffff >> me;
ircolib::u32 mask = start ^ end;
if (mb > me)
mask = ~mask;
r &= ~((0xFFFF'FFFF >> mb) << me);
r &= mask;
gpr[utils::RA(instr)] = r;
cr0_update(instr & 1, r);
}
void broadway::rlwimi(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;
const ircolib::u32 start = 0xffffffff >> mb;
const ircolib::u32 end = 0x7fffffff >> me;
ircolib::u32 mask = start ^ end;
if (mb > me)
mask = ~mask;
r &= mask;
r |= (gpr[utils::RA(instr)] & ~mask);
gpr[utils::RA(instr)] = r;
cr0_update(instr & 1, r);
}
void broadway::lwzu(ircolib::u32 instr, mem &mem) {
@@ -235,7 +491,170 @@ void broadway::lwzu(ircolib::u32 instr, mem &mem) {
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;
gpr[utils::RD(instr)] = mem.read32(EA)
.and_then([&](ircolib::u32 val) {
gpr[utils::RA(instr)] = EA;
return std::expected<ircolib::u32, std::string>(val);
})
.or_else([&](std::string e) {
ircolib::panic("lwzu broadway read failed. Reason {} (pc: 0x{:08X})", e, pc - 4);
return std::expected<ircolib::u32, std::string>();
})
.value();
}
void broadway::rfi(ircolib::u32 instr) {
pc = srr0;
ircolib::clear_bit(msr, 13);
}
void broadway::andi(ircolib::u32 instr) {
const ircolib::s32 result = gpr[utils::RS(instr)] & utils::UIMM(instr);
gpr[utils::RA(instr)] = result;
cr0_update(true, result);
}
void broadway::andis(ircolib::u32 instr) {
const ircolib::s32 result = gpr[utils::RS(instr)] & (ircolib::u32(utils::UIMM(instr)) << 16);
gpr[utils::RA(instr)] = result;
cr0_update(true, result);
}
void broadway::and(ircolib::u32 instr) {
const ircolib::s32 result = gpr[utils::RS(instr)] & gpr[utils::RB(instr)];
gpr[utils::RA(instr)] = result;
cr0_update(instr & 1, result);
}
void broadway::mtfsf(ircolib::u32 instr) {
const ircolib::u8 fm = (instr >> 17) & 0xff;
ircolib::u8 mask = 0;
for (int i = 0; i < 8; i++) {
if (ircolib::is_bit_set(fm, i)) {
mask |= 0xf << (i * 4);
}
}
ircolib::u32 frb = fgrs[utils::RB(instr)].ps0;
fpscr = (fpscr & ~mask) | (frb & mask);
cr1_update(instr & 1);
}
void broadway::mtfsb0(ircolib::u32 instr) {
ircolib::u32 mask = ~(1 << utils::RD(instr));
fpscr = fpscr & mask;
cr1_update(instr & 1);
}
void broadway::mtfsb1(ircolib::u32 instr) {
ircolib::u32 bit = 1 << utils::RD(instr);
ircolib::u32 mask = ~bit;
fpscr = (fpscr & mask) | bit;
cr1_update(instr & 1);
}
void broadway::mfmsr(ircolib::u32 instr) { gpr[utils::RS(instr)] = msr; }
void broadway::mtmsr(ircolib::u32 instr) { msr = gpr[utils::RS(instr)]; }
void broadway::nand(ircolib::u32 instr) {
gpr[utils::RA(instr)] = ~(gpr[utils::RS(instr)] & gpr[utils::RB(instr)]);
cr0_update(instr & 1, gpr[utils::RA(instr)]);
}
void broadway::subf(ircolib::u32 instr) {
gpr[utils::RD(instr)] = ~gpr[utils::RA(instr)] + gpr[utils::RB(instr)];
cr0_update(instr & 1, gpr[utils::RD(instr)]);
}
void broadway::subfc(ircolib::u32 instr) {
ircolib::u32 sum;
bool c0 = __builtin_add_overflow(~gpr[utils::RA(instr)], 1, &sum);
bool c1 = __builtin_add_overflow(sum, gpr[utils::RB(instr)], &sum);
cr0_update(instr & 1, sum);
xer.ca = !c0 | c1;
gpr[utils::RD(instr)] = sum;
}
void broadway::subfic(ircolib::u32 instr) {
ircolib::u32 sum;
bool c0 = __builtin_add_overflow(~gpr[utils::RA(instr)], 1, &sum);
bool c1 = __builtin_add_overflow(sum, utils::SIMM(instr), &sum);
xer.ca = !c0 | c1;
gpr[utils::RD(instr)] = sum;
}
void broadway::subfe(ircolib::u32 instr) {
ircolib::u32 sum;
bool c0 = __builtin_add_overflow(~gpr[utils::RA(instr)], gpr[utils::RB(instr)], &sum);
bool c1 = __builtin_add_overflow(sum, xer.ca, &sum);
cr0_update(instr & 1, sum);
xer.ca = c0 | c1;
gpr[utils::RD(instr)] = sum;
}
void broadway:: or (ircolib::u32 instr) {
gpr[utils::RA(instr)] = gpr[utils::RS(instr)] | gpr[utils::RB(instr)];
cr0_update(instr & 1, gpr[utils::RA(instr)]);
}
void broadway::xori(ircolib::u32 instr) { gpr[utils::RA(instr)] = gpr[utils::RS(instr)] ^ utils::UIMM(instr); }
void broadway::mullw(ircolib::u32 instr) {
gpr[utils::RD(instr)] = ircolib::u64(gpr[utils::RA(instr)]) * ircolib::u64(gpr[utils::RB(instr)]);
}
void broadway::mulli(ircolib::u32 instr) {
gpr[utils::RD(instr)] = ircolib::u64(gpr[utils::RA(instr)]) * ircolib::u64(utils::SIMM(instr));
}
void broadway::mfcr(ircolib::u32 instr) { gpr[utils::RD(instr)] = cr; }
void broadway::mtcrf(ircolib::u32 instr) {
ircolib::u32 mask = 0;
const ircolib::u8 crm = (instr >> 13) & 0xff;
for (int i = 0; i < 7; i++) {
if (ircolib::is_bit_set(crm, i)) {
set_cr(gpr[utils::RS(instr)] & (0xffff << i * 4), i);
}
}
}
void broadway::divwu(ircolib::u32 instr) {
ircolib::u32 dividend = gpr[utils::RA(instr)];
ircolib::u32 divisor = gpr[utils::RB(instr)];
if (divisor == 0) {
if ((instr >> 11) & 1)
xer.ov = true;
return;
}
gpr[utils::RD(instr)] = dividend / divisor;
cr0_update(instr & 1, gpr[utils::RD(instr)]);
}
void broadway::mftb(ircolib::u32 instr) {
const ircolib::u32 tbr = (instr >> 11) & 0x3FF;
if (tbr != 392 && tbr != 424)
ircolib::panic("broadway::mftb with tbr != 268 && != 269 ({})", tbr);
if (tbr == 392)
gpr[utils::RD(instr)] = tbl;
if (tbr == 424)
gpr[utils::RD(instr)] = tbu;
}
void broadway::sraw(ircolib::u32 instr) {
ircolib::u8 shift = std::min(gpr[utils::RB(instr)] & 0x3f, ircolib::u32(31));
ircolib::s32 rs = gpr[utils::RS(instr)];
ircolib::s32 result = rs >> shift;
ircolib::u32 mask = (1 << shift) - 1;
cr0_update(instr & 1, result);
xer.ca = (rs < 0) & ((ircolib::u32(rs) & mask) != 0);
gpr[utils::RA(instr)] = result;
}
} // namespace weee::core
+31
View File
@@ -0,0 +1,31 @@
#include <broadway/mmio/ai.hpp>
#include <mem.hpp>
#include <ircolib/log.hpp>
namespace weee::core {
audio_interface::audio_interface(mem &mem) {
mem.register_read32_handler(0x0c006c00, 0x0c006c1f, [&](ircolib::u32 addr) { return read32(addr); });
mem.register_write32_handler(0x0c006c00, 0x0c006c1f,
[&](ircolib::u32 addr, ircolib::u32 value) { return write32(addr, value); });
}
ircolib::u32 audio_interface::read32(ircolib::u32 addr) {
switch (addr) {
case 0:
return ctrl.raw;
default:
ircolib::panic("audio_interface::read32 from unimplemented addr 0x{:08X}", addr);
return 0;
}
}
void audio_interface::write32(ircolib::u32 addr, ircolib::u32 value) {
switch (addr) {
case 0:
ctrl.raw = value;
break;
default:
ircolib::panic("audio_interface::write32 to unimplemented addr 0x{:08X} with value 0x{:08X}", addr, value);
}
}
} // namespace weee::core
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <ircolib/types.hpp>
namespace weee::core {
struct mem;
struct audio_interface {
audio_interface(mem &);
ircolib::u32 read32(ircolib::u32);
void write32(ircolib::u32, ircolib::u32);
union {
struct {
unsigned pstat : 1;
unsigned afr : 1;
unsigned aiintmsk : 1;
unsigned aiint : 1;
unsigned aiintvld : 1;
unsigned screset : 1;
unsigned dsp_sr : 1;
unsigned : 25;
};
ircolib::u32 raw;
} ctrl;
};
} // namespace weee::core
+152
View File
@@ -0,0 +1,152 @@
#include <broadway/mmio/dsp.hpp>
#include <mem.hpp>
#include <ircolib/log.hpp>
namespace weee::core {
dsp::dsp(mem &mem) {
mem.register_read16_handler(0x0c005000, 0x0c0051ff, [&](ircolib::u32 addr) { return read16(addr); });
mem.register_write16_handler(0x0c005000, 0x0c0051ff,
[&](ircolib::u32 addr, ircolib::u16 value) { return write16(addr, value); });
mem.register_read32_handler(0x0c005000, 0x0c0051ff, [&](ircolib::u32 addr) { return read32(addr); });
mem.register_write32_handler(0x0c005000, 0x0c0051ff,
[&](ircolib::u32 addr, ircolib::u32 value) { return write32(addr, value); });
}
ircolib::u32 dsp::read32(ircolib::u32 addr) {
switch (addr) {
case 0x20:
return ar_dma_mmaddr.whole;
case 0x24:
return ar_dma_araddr.whole;
case 0x28:
return ar_dma_cnt.whole;
case 0x30:
return dma_start_addr.whole;
default:
ircolib::panic("dsp::read32 from unimplemented addr 0x{:08X}", addr);
return 0;
}
}
void dsp::write32(ircolib::u32 addr, ircolib::u32 value) {
switch (addr) {
case 0x20:
ar_dma_mmaddr.whole = value;
break;
case 0x24:
ar_dma_araddr.whole = value;
break;
case 0x28:
ar_dma_cnt.whole = value;
break;
case 0x30:
dma_start_addr.whole = value;
break;
default:
ircolib::panic("dsp::write32 to unimplemented addr 0x{:08X} with value 0x{:08X}", addr, value);
}
}
ircolib::u16 dsp::read16(ircolib::u32 addr) {
switch (addr) {
case 0x00:
return dsp_mail_hi;
case 0x02:
return dsp_mail_lo;
case 0x04:
return cpu_mail_hi;
case 0x06:
return cpu_mail_lo;
case 0x0a:
return csr.raw;
case 0x12:
return ar_size;
case 0x20:
return ar_dma_mmaddr.hi;
case 0x22:
return ar_dma_mmaddr.lo;
case 0x24:
return ar_dma_araddr.hi;
case 0x26:
return ar_dma_araddr.lo;
case 0x28:
return ar_dma_cnt.hi;
case 0x2a:
return ar_dma_cnt.lo;
case 0x30:
return dma_start_addr.hi;
case 0x32:
return dma_start_addr.lo;
default:
ircolib::panic("dsp::read16 from unimplemented addr 0x{:08X}", addr);
return 0;
}
}
void dsp::write16(ircolib::u32 addr, ircolib::u16 value) {
switch (addr) {
case 0x00:
dsp_mail_hi = value;
break;
case 0x02:
dsp_mail_lo = value;
break;
case 0x0a:
{
Csr ccsr = {.raw = value};
Csr ocsr = csr;
csr = ccsr;
if (csr.res || (ocsr.boot_mode != ccsr.boot_mode && ccsr.boot_mode)) {
cpu_mail_hi = 0;
cpu_mail_lo = 0;
dsp_mail_hi = 0;
dsp_mail_lo = 0;
}
if (csr.piint)
csr.piint = false;
if (csr.aidint)
csr.aidint = false;
if (csr.arint)
csr.arint = false;
if (csr.dspint)
csr.dspint = false;
}
break;
case 0x12:
ar_size = value;
break;
case 0x20:
ar_dma_mmaddr.hi = value;
break;
case 0x22:
ar_dma_mmaddr.lo = value;
break;
case 0x24:
ar_dma_araddr.hi = value;
break;
case 0x26:
ar_dma_araddr.lo = value;
break;
case 0x28:
ar_dma_cnt.hi = value;
break;
case 0x2a:
ar_dma_cnt.lo = value;
csr.arint = true;
break;
case 0x30:
dma_start_addr.hi = value;
break;
case 0x32:
dma_start_addr.lo = value;
break;
default:
ircolib::panic("dsp::write16 from unimplemented addr 0x{:08X} with value 0x{:04X}", addr, value);
}
}
} // namespace weee::core
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <ircolib/types.hpp>
namespace weee::core {
struct mem;
struct dsp {
dsp(mem &);
ircolib::u16 read16(ircolib::u32);
void write16(ircolib::u32, ircolib::u16);
ircolib::u32 read32(ircolib::u32);
void write32(ircolib::u32, ircolib::u32);
union Csr {
struct {
unsigned res : 1;
unsigned piint : 1;
unsigned halt : 1;
unsigned aidint : 1;
unsigned aidint_mask : 1;
unsigned arint : 1;
unsigned arint_mask : 1;
unsigned dspint : 1;
unsigned dspint_mask : 1;
unsigned int_status : 1;
unsigned : 1;
unsigned boot_mode : 1;
unsigned : 4;
};
ircolib::u16 raw;
} csr;
union {
struct {
ircolib::u32 lo;
ircolib::u32 hi;
};
ircolib::u64 whole;
} ar_dma_mmaddr, ar_dma_araddr, ar_dma_cnt, dma_start_addr;
ircolib::u16 ar_size;
ircolib::u16 dsp_mail_hi = 0, dsp_mail_lo = 0, cpu_mail_hi = 0, cpu_mail_lo = 0;
};
} // namespace weee::core
+41
View File
@@ -0,0 +1,41 @@
#include <broadway/mmio/exi.hpp>
#include <mem.hpp>
#include <ircolib/log.hpp>
namespace weee::core {
exi::exi(mem &mem) {
mem.register_read32_handler(0x0c006800, 0x0c00683f, [&](ircolib::u32 addr) { return read32(addr); });
mem.register_write32_handler(0x0c006800, 0x0c00683f,
[&](ircolib::u32 addr, ircolib::u32 value) { return write32(addr, value); });
}
ircolib::u32 exi::read32(ircolib::u32 addr) {
switch (addr) {
case 0:
return param0.raw;
case 0x14:
return param1.raw;
case 0x28:
return param2.raw;
default:
ircolib::panic("exi::read32 from unimplemented addr 0x{:08X}", addr);
return 0;
}
}
void exi::write32(ircolib::u32 addr, ircolib::u32 value) {
switch (addr) {
case 0:
param0.raw = value;
break;
case 0x14:
param1.raw = value;
break;
case 0x28:
param2.raw = value;
break;
default:
ircolib::panic("exi::write32 to unimplemented addr 0x{:08X} with value 0x{:08X}", addr, value);
}
}
} // namespace weee::core
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <ircolib/types.hpp>
namespace weee::core {
struct mem;
struct exi {
exi(mem &);
ircolib::u32 read32(ircolib::u32);
void write32(ircolib::u32, ircolib::u32);
union {
struct {
unsigned ext_int_mask : 1;
unsigned ext_int : 1;
unsigned tc_int_mask : 1;
unsigned tc_int : 1;
unsigned clk : 3;
unsigned cs : 3;
unsigned ext_int_mask2 : 1;
unsigned ext_int2 : 1;
unsigned ext : 1;
unsigned romdis : 1;
unsigned : 18;
};
ircolib::u32 raw;
} param0, param1, param2;
};
} // namespace weee::core
+20
View File
@@ -0,0 +1,20 @@
#include <mem.hpp>
#include <broadway/mmio/mi.hpp>
#include <ircolib/log.hpp>
namespace weee::core {
memory_interface::memory_interface(mem &mem) {
mem.register_write16_handler(0x0c004000, 0x0c00407f,
[&](ircolib::u32 addr, ircolib::u16 value) { write16(addr, value); });
}
void memory_interface::write16(ircolib::u32 addr, ircolib::u16 value) {
switch (addr) {
case 0x1C:
int_mask.raw = value;
break;
default:
ircolib::panic("memory_interface::write16 to unimplemented addr 0x{:08X} with value 0x{:04X}", addr, value);
}
}
} // namespace weee::core
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <ircolib/types.hpp>
namespace weee::core {
struct mem;
struct memory_interface {
union {
struct {
unsigned mem0 : 1;
unsigned mem1 : 1;
unsigned mem2 : 1;
unsigned mem3 : 1;
unsigned all : 1;
unsigned : 27;
};
ircolib::u32 raw;
} int_mask;
memory_interface(mem &);
void write16(ircolib::u32, ircolib::u16);
};
} // namespace weee::core
+31
View File
@@ -0,0 +1,31 @@
#include <mem.hpp>
#include <broadway/mmio/pi.hpp>
#include <ircolib/log.hpp>
namespace weee::core {
processor_interface::processor_interface(mem &mem) {
mem.register_write32_handler(0x0c003000, 0x0c0030ff,
[&](ircolib::u32 addr, ircolib::u32 value) { return write32(addr, value); });
mem.register_read32_handler(0x0c003000, 0x0c0030ff, [&](ircolib::u32 addr) { return read32(addr); });
}
void processor_interface::write32(ircolib::u32 addr, ircolib::u32 value) {
switch (addr) {
case 0x04:
intmr.raw = value;
break;
default:
ircolib::panic("processor_interface::write32 to unimplemented addr 0x{:08X} with value 0x{:08X}", addr, value);
}
}
ircolib::u32 processor_interface::read32(ircolib::u32 addr) {
switch (addr) {
case 0x2c:
return 2;
default:
ircolib::panic("processor_interface::read32 from unimplemented addr 0x{:08X}", addr);
return 0;
}
}
} // namespace weee::core
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <ircolib/types.hpp>
namespace weee::core {
struct mem;
struct processor_interface {
union {
struct {
unsigned error : 1;
unsigned rsw : 1;
unsigned di : 1;
unsigned si : 1;
unsigned exi : 1;
unsigned ai : 1;
unsigned dsp : 1;
unsigned mem : 1;
unsigned vi : 1;
unsigned pe_token : 1;
unsigned pe_finish : 1;
unsigned cp : 1;
unsigned debug : 1;
unsigned hsp : 1;
unsigned : 18;
};
ircolib::u32 raw;
} intmr;
processor_interface(mem &);
void write32(ircolib::u32, ircolib::u32);
ircolib::u32 read32(ircolib::u32);
};
} // namespace weee::core
+46
View File
@@ -0,0 +1,46 @@
#include <broadway/mmio/si.hpp>
#include <mem.hpp>
#include <ircolib/log.hpp>
namespace weee::core {
serial_interface::serial_interface(mem &mem) {
mem.register_read32_handler(0x0c006400, 0x0c0064ff, [&](ircolib::u32 addr) { return read32(addr); });
mem.register_write32_handler(0x0c006400, 0x0c0064ff,
[&](ircolib::u32 addr, ircolib::u32 value) { return write32(addr, value); });
}
ircolib::u32 serial_interface::read32(ircolib::u32 addr) {
switch (addr) {
case 0x30:
return sipoll.raw;
case 0x34:
return sicomcsr.raw;
case 0x38:
return sisr.raw;
case 0x3C:
return clock_lk.raw;
default:
ircolib::panic("serial_interface::read32 from unimplemented addr 0x{:08X}", addr);
return 0;
}
}
void serial_interface::write32(ircolib::u32 addr, ircolib::u32 value) {
switch (addr) {
case 0x30:
sipoll.raw = value;
break;
case 0x34:
sicomcsr.raw = value;
break;
case 0x38:
sisr.raw = value;
break;
case 0x3C:
clock_lk.raw = value;
break;
default:
ircolib::panic("serial_interface::write32 to unimplemented addr 0x{:08X} with value 0x{:08X}", addr, value);
}
}
} // namespace weee::core
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include <ircolib/types.hpp>
namespace weee::core {
struct mem;
struct serial_interface {
serial_interface(mem &);
ircolib::u32 read32(ircolib::u32);
void write32(ircolib::u32, ircolib::u32);
union {
struct {
unsigned vbcpy : 4;
unsigned en : 4;
unsigned y : 8;
unsigned x : 8;
unsigned : 8;
};
ircolib::u32 raw;
} sipoll;
union {
struct {
unsigned tstart : 1;
unsigned channel : 2;
unsigned cben : 1;
unsigned cmden : 1;
unsigned inlength : 7;
unsigned : 1;
unsigned outlength : 7;
unsigned : 1;
unsigned chen : 1;
unsigned chnum : 2;
unsigned rdstintmsk : 1;
unsigned rdstint : 1;
unsigned comerr : 1;
unsigned tcintmsk : 1;
unsigned tcint : 1;
};
ircolib::u32 raw;
} sicomcsr;
union {
struct {
unsigned : 31;
unsigned lock : 1;
};
ircolib::u32 raw;
} clock_lk;
union {
struct {
unsigned joy3 : 6;
unsigned : 2;
unsigned joy2 : 6;
unsigned : 2;
unsigned joy1 : 6;
unsigned : 2;
unsigned unrun : 1;
unsigned ovrun0 : 1;
unsigned coll0 : 1;
unsigned norep0 : 1;
unsigned wrst0 : 1;
unsigned rdst0 : 1;
unsigned : 1;
unsigned wr : 1;
};
ircolib::u32 raw;
} sisr;
};
} // namespace weee::core
+57 -2
View File
@@ -4,12 +4,67 @@
namespace weee::core {
video_interface::video_interface(mem &mem) {
mem.register_read16_handler(0x0c002000, 0x0c0020ff, [&](ircolib::u32 addr) { return read16(addr); });
mem.register_read32_handler(0x0c002000, 0x0c0020ff, [&](ircolib::u32 addr) { return read32(addr); });
mem.register_write16_handler(0x0c002000, 0x0c0020ff,
[&](ircolib::u32 addr, ircolib::u16 value) { write16(addr, value); });
mem.register_write32_handler(0x0c002000, 0x0c0020ff,
[&](ircolib::u32 addr, ircolib::u32 value) { write32(addr, value); });
}
ircolib::u16 video_interface::read16(ircolib::u32 addr) {
switch (addr) {
case 0x00:
return vtr.raw;
case 0x02:
return dcr.raw;
case 0x4a:
return hsr.raw;
case 0x6c:
return viclk & 1;
case 0x70:
return 0x0280;
default:
ircolib::panic("video_interface::read16 from unimplemented addr 0x{:04X}", addr);
return 0;
}
}
ircolib::u32 video_interface::read32(ircolib::u32 addr) {
switch (addr) {
case 0x02:
return dcr.raw;
case 0x04:
return htr0.raw;
case 0x08:
return htr1.raw;
case 0x0c:
return vto.raw;
case 0x10:
return vte.raw;
case 0x14:
return bbei.raw;
case 0x18:
return bboi.raw;
case 0x1c:
return tfbl.raw & 0x1ffffe00;
case 0x24:
return bfbl.raw & 0x10fffe00;
case 0x4c:
case 0x50:
case 0x54:
return fct0[addr - 0x4c].raw;
case 0x58:
case 0x5c:
case 0x60:
case 0x64:
return fct1[addr - 0x58].raw;
default:
ircolib::panic("video_interface::read32 from unimplemented addr 0x{:04X}", addr);
return 0;
}
}
void video_interface::write16(ircolib::u32 addr, ircolib::u16 value) {
switch (addr) {
case 0x00:
@@ -55,10 +110,10 @@ void video_interface::write32(ircolib::u32 addr, ircolib::u32 value) {
bboi.raw = value;
break;
case 0x1c:
tfbl.raw = value;
tfbl.raw = value & 0x1ffffe00;
break;
case 0x24:
bfbl.raw = value;
bfbl.raw = value & 0x10fffe00;
break;
case 0x4c:
case 0x50:
+16 -16
View File
@@ -8,6 +8,17 @@ struct video_interface {
video_interface(mem &);
void write16(ircolib::u32, ircolib::u16);
void write32(ircolib::u32, ircolib::u32);
ircolib::u16 read16(ircolib::u32);
ircolib::u32 read32(ircolib::u32);
ircolib::u32 xfb_top_addr() {
auto addr = tfbl.fbb;
if (tfbl.page) {
addr <<= 5;
}
return addr + tfbl.xof;
}
union DCR {
struct {
@@ -80,26 +91,15 @@ struct video_interface {
ircolib::u32 raw;
} bbei, bboi;
union TFBL {
union FBR {
struct {
unsigned : 9;
unsigned fbb : 15;
unsigned : 3;
unsigned page : 1;
unsigned xof : 4;
unsigned : 4;
unsigned fbb : 24;
};
ircolib::u32 raw;
} tfbl;
union BFBL {
struct {
unsigned : 9;
unsigned fbb : 15;
unsigned y : 8;
};
ircolib::u32 raw;
} bfbl;
} tfbl{}, bfbl{};
union FCT012 {
struct {
+1 -1
View File
@@ -3,7 +3,7 @@
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::u16 secondary(ircolib::u32 instr) { return (instr >> 1) & 0x3ff; }
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); }
+1 -1
View File
@@ -20,7 +20,7 @@ bool load_dol(const std::string &path, mem &mem, broadway &broadway) {
ircolib::u32 bss_address, bss_size, entry_point;
} hdr;
for (size_t bin_index = 0; bin_index < 0xD8; bin_index += 4) {
for (ircolib::u32 bin_index = 0; bin_index < 0xD8; bin_index += 4) {
if (ircolib::is_inside_range(bin_index, 0, 0x1b)) // text file offsets
hdr.text[bin_index / 4].offset = std::byteswap(ircolib::read_access<ircolib::u32>(bin, bin_index));
+1 -1
View File
@@ -10,7 +10,7 @@ bool load_elf(const std::string &path, mem &mem, broadway &broadway) {
if (!reader.load(path))
return false;
size_t sanity_bss_check_count = 0;
ircolib::u32 sanity_bss_check_count = 0;
for (const auto &segment : reader.segments) {
const auto segment_type = segment->get_type();
+65 -26
View File
@@ -1,18 +1,28 @@
#include <cstring>
#include <mem.hpp>
#include <ircolib/log.hpp>
#include "ircolib/mem_access.hpp"
#include <ircolib/mem_access.hpp>
namespace weee::core {
mem::mem() : vi(*this) {
mem::mem() : vi(*this), pi(*this), mi(*this), dsp(*this), ai(*this), exi(*this), si(*this) {
mem1.resize(24_mib);
std::fill(mem1.begin(), mem1.end(), 0);
ipl.resize(1_mib);
std::fill(ipl.begin(), ipl.end(), 0);
register_read8_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr) { return mem1[addr]; });
register_read16_handler(0x00000000, 0x017fffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u16>(mem1, addr); });
register_read32_handler(0x00000000, 0x017fffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u32>(mem1, addr); });
register_read64_handler(0x00000000, 0x017fffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u64>(mem1, addr); });
register_write8_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u8 value) { mem1[addr] = value; });
register_write16_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u16 value) {
ircolib::write_access<ircolib::u16>(mem1, addr, value);
});
@@ -20,6 +30,35 @@ mem::mem() : vi(*this) {
register_write32_handler(0x00000000, 0x017fffff, [&](ircolib::u32 addr, ircolib::u32 value) {
ircolib::write_access<ircolib::u32>(mem1, addr, value);
});
register_write64_handler(0x00000000, 0x0fffffff, [&](ircolib::u32 addr, ircolib::u32 value) {
ircolib::write_access<ircolib::u64>(mem1, addr, value);
});
register_read8_handler(0x0ff00000, 0x0fffffff, [&](ircolib::u32 addr) { return ipl[addr]; });
register_read16_handler(0x0ff00000, 0x0fffffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u16>(ipl, addr); });
register_read32_handler(0x0ff00000, 0x0fffffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u32>(ipl, addr); });
register_read64_handler(0x0ff00000, 0x0fffffff,
[&](ircolib::u32 addr) { return ircolib::read_access<ircolib::u64>(ipl, addr); });
register_write8_handler(0x0ff00000, 0x0fffffff, [&](ircolib::u32 addr, ircolib::u8 value) { ipl[addr] = value; });
register_write16_handler(0x0ff00000, 0x0fffffff, [&](ircolib::u32 addr, ircolib::u16 value) {
ircolib::write_access<ircolib::u16>(ipl, addr, value);
});
register_write32_handler(0x0ff00000, 0x0fffffff, [&](ircolib::u32 addr, ircolib::u32 value) {
ircolib::write_access<ircolib::u32>(ipl, addr, value);
});
register_write64_handler(0x0ff00000, 0x0fffffff, [&](ircolib::u32 addr, ircolib::u32 value) {
ircolib::write_access<ircolib::u64>(ipl, addr, value);
});
}
void mem::copy(std::vector<ircolib::u8> &src, const ircolib::u32 offset) {
@@ -45,7 +84,7 @@ void mem::set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32
memset(&mem1[offset], val, size);
}
ircolib::u8 mem::read8(ircolib::u32 addr) {
std::expected<ircolib::u8, std::string> mem::read8(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read8_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -53,11 +92,10 @@ ircolib::u8 mem::read8(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read8 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read8 unimplemented addr 0x{:08X}", addr));
}
ircolib::u16 mem::read16(ircolib::u32 addr) {
std::expected<ircolib::u16, std::string> mem::read16(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read16_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -65,11 +103,10 @@ ircolib::u16 mem::read16(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read16 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read16 unimplemented addr 0x{:08X}", addr));
}
ircolib::u32 mem::read32(ircolib::u32 addr) {
std::expected<ircolib::u32, std::string> mem::read32(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read32_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -77,11 +114,10 @@ ircolib::u32 mem::read32(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read32 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read32 unimplemented addr 0x{:08X}", addr));
}
ircolib::u64 mem::read64(ircolib::u32 addr) {
std::expected<ircolib::u64, std::string> mem::read64(ircolib::u32 addr) {
addr &= 0x0FFFFFFF;
for (const auto &handler : read64_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
@@ -89,51 +125,54 @@ ircolib::u64 mem::read64(ircolib::u32 addr) {
}
}
ircolib::panic("mem::read64 unimplemented addr 0x{:08X}", addr);
return 0;
return std::unexpected(std::format("mem::read64 unimplemented addr 0x{:08X}", addr));
}
void mem::write8(ircolib::u32 addr, ircolib::u8 value) {
std::expected<void, std::string> mem::write8(ircolib::u32 addr, ircolib::u8 value) {
addr &= 0x0FFFFFFF;
for (const auto &handler : write8_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
return handler.func(addr - handler.start, value);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write8 unimplemented addr 0x{:08X} = 0x{:02X}", addr, value);
return std::unexpected(std::format("mem::write8 unimplemented addr 0x{:08X} = 0x{:02X}", addr, value));
}
void mem::write16(ircolib::u32 addr, ircolib::u16 value) {
std::expected<void, std::string> mem::write16(ircolib::u32 addr, ircolib::u16 value) {
addr &= 0x0FFFFFFF;
for (const auto &handler : write16_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
return handler.func(addr - handler.start, value);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write16 unimplemented addr 0x{:08X} = 0x{:04X}", addr, value);
return std::unexpected(std::format("mem::write16 unimplemented addr 0x{:08X} = 0x{:04X}", addr, value));
}
void mem::write32(ircolib::u32 addr, ircolib::u32 value) {
std::expected<void, std::string> mem::write32(ircolib::u32 addr, ircolib::u32 value) {
addr &= 0x0FFFFFFF;
for (const auto &handler : write32_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
return handler.func(addr - handler.start, value);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write32 unimplemented addr 0x{:08X} = 0x{:08X}", addr, value);
return std::unexpected(std::format("mem::write32 unimplemented addr 0x{:08X} = 0x{:08X}", addr, value));
}
void mem::write64(ircolib::u32 addr, ircolib::u64 value) {
std::expected<void, std::string> mem::write64(ircolib::u32 addr, ircolib::u64 value) {
addr &= 0x0FFFFFFF;
for (const auto &handler : write64_handlers) {
if (ircolib::is_inside_range(addr, handler.start, handler.end)) {
return handler.func(addr - handler.start, value);
handler.func(addr - handler.start, value);
return std::expected<void, std::string>();
}
}
ircolib::panic("mem::write64 unimplemented addr 0x{:08X} = 0x{:016X}", addr, value);
return std::unexpected(std::format("mem::write64 unimplemented addr 0x{:08X} = 0x{:016X}", addr, value));
}
} // namespace weee::core
+24 -8
View File
@@ -1,8 +1,16 @@
#pragma once
#include <string>
#include <vector>
#include <ircolib/types.hpp>
#include <broadway/mmio/vi.hpp>
#include <broadway/mmio/pi.hpp>
#include <broadway/mmio/mi.hpp>
#include <broadway/mmio/dsp.hpp>
#include <broadway/mmio/ai.hpp>
#include <broadway/mmio/exi.hpp>
#include <broadway/mmio/si.hpp>
#include <functional>
#include <expected>
namespace weee::core {
template <typename T>
@@ -53,20 +61,21 @@ struct mem {
write64_handlers.push_back({std::move(func), start, end});
}
ircolib::u8 read8(ircolib::u32);
ircolib::u16 read16(ircolib::u32);
ircolib::u32 read32(ircolib::u32);
ircolib::u64 read64(ircolib::u32);
void write8(ircolib::u32, ircolib::u8);
void write16(ircolib::u32, ircolib::u16);
void write32(ircolib::u32, ircolib::u32);
void write64(ircolib::u32, ircolib::u64);
std::expected<ircolib::u8, std::string> read8(ircolib::u32);
std::expected<ircolib::u16, std::string> read16(ircolib::u32);
std::expected<ircolib::u32, std::string> read32(ircolib::u32);
std::expected<ircolib::u64, std::string> read64(ircolib::u32);
std::expected<void, std::string> write8(ircolib::u32, ircolib::u8);
std::expected<void, std::string> write16(ircolib::u32, ircolib::u16);
std::expected<void, std::string> write32(ircolib::u32, ircolib::u32);
std::expected<void, std::string> write64(ircolib::u32, ircolib::u64);
void copy(std::vector<ircolib::u8> &src, const ircolib::u32 offset);
void copy(ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset);
void set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 offset);
std::vector<ircolib::u8> mem1;
std::vector<ircolib::u8> ipl{};
private:
std::vector<read_handler<ircolib::u8>> read8_handlers{};
@@ -78,6 +87,13 @@ struct mem {
std::vector<write_handler<ircolib::u32>> write32_handlers{};
std::vector<write_handler<ircolib::u64>> write64_handlers{};
public:
video_interface vi;
processor_interface pi;
memory_interface mi;
dsp dsp;
exi exi;
audio_interface ai;
serial_interface si;
};
} // namespace weee::core
+56
View File
@@ -0,0 +1,56 @@
---
Language: Cpp
BasedOnStyle: LLVM
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignOperands: false
AlignTrailingComments: false
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: true
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: true
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakConstructorInitializers: AfterColon
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: false
IndentAccessModifiers: false
AccessModifierOffset: 0
ContinuationIndentWidth: 0
IncludeCategories:
- Regex: '^<.*'
Priority: 1
- Regex: '^".*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseBlocks: true
InsertNewlineAtEOF: true
MacroBlockBegin: ''
MacroBlockEnd: ''
SortIncludes: Never
MaxEmptyLinesToKeep: 2
NamespaceIndentation: Inner
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
TabWidth: 4
IndentWidth: 4
...
+5 -6
View File
@@ -1,12 +1,11 @@
#pragma once
#include <ircolib/types.hpp>
#include "types.hpp"
#include <fstream>
#include <vector>
#include <filesystem>
namespace fs = std::filesystem;
namespace ircolib {
namespace fs = std::filesystem;
static inline std::vector<u8> read_file_binary(const std::string &path) {
std::ifstream file(path, std::ios::binary);
return {std::istreambuf_iterator{file}, {}};
@@ -17,19 +16,19 @@ static inline void write_file_binary(const std::vector<u8> &data, const std::str
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
}
static inline void write_file_binary(const u8 *data, const size_t size, const std::string &path) {
static inline void write_file_binary(const u8 *data, const u32 size, const std::string &path) {
FILE *out = fopen(path.c_str(), "wb");
fwrite(data, size, 1, out);
fclose(out);
}
template <size_t Size>
template <u32 Size>
static inline void write_file_binary(const std::array<u8, Size> &data, const std::string &path) {
std::ofstream file(path, std::ios::binary);
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
}
static inline size_t next_pow2(size_t num) {
static inline u32 next_pow2(u32 num) {
// Taken from "Bit Twiddling Hacks" by Sean Anderson:
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
--num;
+11 -11
View File
@@ -1,9 +1,9 @@
#pragma once
#include <cmath>
#include <ircolib/types.hpp>
#include "types.hpp"
namespace ircolib {
static inline auto round_ceil(float f) {
static inline auto roundCeil(float f) {
#ifdef SIMD_SUPPORT
__m128 t = _mm_set_ss(f);
t = _mm_round_ss(t, t, _MM_FROUND_TO_POS_INF);
@@ -13,7 +13,7 @@ static inline auto round_ceil(float f) {
#endif
}
static inline auto round_ceil(double f) {
static inline auto roundCeil(double f) {
#ifdef SIMD_SUPPORT
__m128d t = _mm_set_sd(f);
t = _mm_round_sd(t, t, _MM_FROUND_TO_POS_INF);
@@ -23,7 +23,7 @@ static inline auto round_ceil(double f) {
#endif
}
static inline auto round_nearest(float f) {
static inline auto roundNearest(float f) {
#ifdef SIMD_SUPPORT
__m128 t = _mm_set_ss(f);
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEAREST_INT);
@@ -33,7 +33,7 @@ static inline auto round_nearest(float f) {
#endif
}
static inline auto round_nearest(double f) {
static inline auto roundNearest(double f) {
#ifdef SIMD_SUPPORT
__m128d t = _mm_set_sd(f);
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEAREST_INT);
@@ -43,7 +43,7 @@ static inline auto round_nearest(double f) {
#endif
}
static inline auto round_current(float f) {
static inline auto roundCurrent(float f) {
#ifdef SIMD_SUPPORT
auto t = _mm_set_ss(f);
t = _mm_round_ss(t, t, _MM_FROUND_CUR_DIRECTION);
@@ -53,7 +53,7 @@ static inline auto round_current(float f) {
#endif
}
static inline auto round_current(double f) {
static inline auto roundCurrent(double f) {
#ifdef SIMD_SUPPORT
auto t = _mm_set_sd(f);
t = _mm_round_sd(t, t, _MM_FROUND_CUR_DIRECTION);
@@ -64,7 +64,7 @@ static inline auto round_current(double f) {
}
static inline auto round_floor(float f) {
static inline auto roundFloor(float f) {
#ifdef SIMD_SUPPORT
__m128 t = _mm_set_ss(f);
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF);
@@ -74,7 +74,7 @@ static inline auto round_floor(float f) {
#endif
}
static inline auto round_floor(double f) {
static inline auto roundFloor(double f) {
#ifdef SIMD_SUPPORT
__m128d t = _mm_set_sd(f);
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEG_INF);
@@ -84,7 +84,7 @@ static inline auto round_floor(double f) {
#endif
}
static inline auto round_trunc(float f) {
static inline auto roundTrunc(float f) {
#ifdef SIMD_SUPPORT
__m128 t = _mm_set_ss(f);
t = _mm_round_ss(t, t, _MM_FROUND_TO_ZERO);
@@ -94,7 +94,7 @@ static inline auto round_trunc(float f) {
#endif
}
static inline auto round_trunc(double f) {
static inline auto roundTrunc(double f) {
#ifdef SIMD_SUPPORT
__m128d t = _mm_set_sd(f);
t = _mm_round_sd(t, t, _MM_FROUND_TO_ZERO);
+6
View File
@@ -4,7 +4,13 @@
namespace ircolib {
template <typename... Args>
void panic(std::format_string<Args...> fmt, Args &&...args) {
std::print("[FATAL] ");
std::println(fmt, std::forward<Args>(args)...);
exit(1);
}
template <typename... Args>
void warn(std::format_string<Args...> fmt, Args &&...args) {
std::print("[WARN] ");
std::println(fmt, std::forward<Args>(args)...);
}
} // namespace ircolib
+15 -14
View File
@@ -1,5 +1,6 @@
#pragma once
#include <ircolib/types.hpp>
#include "types.hpp"
#include <cstddef>
#include <cstring>
#include <functional>
#include <bit>
@@ -34,14 +35,14 @@ template <typename T>
static constexpr inline T read_access(const u8 *data, const u32 index);
template <typename T>
static constexpr inline T read_access(const std::vector<u8> &data, const u32 index);
template <typename T, size_t Size>
template <typename T, u32 Size>
static constexpr inline T read_access(const std::array<u8, Size> &data, const u32 index);
template <typename T>
static constexpr inline void write_access(u8 *data, const u32 index, const T val);
template <typename T>
static constexpr inline void write_access(std::vector<u8> &data, const u32 index, const T val);
template <typename T, size_t Size>
template <typename T, u32 Size>
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const T val);
template <>
@@ -69,19 +70,19 @@ static constexpr inline T read_access(const std::vector<u8> &data, const u32 ind
return *reinterpret_cast<const T *>(&data[index]);
}
template <size_t Size>
template <u32 Size>
constexpr inline u64 read_access(const std::array<u8, Size> &data, const u32 index) {
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
return static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
}
template <typename T, size_t Size>
template <typename T, u32 Size>
static constexpr inline T read_access(const std::array<u8, Size> &data, const u32 index) {
return *reinterpret_cast<const T *>(&data[index]);
}
template <size_t Size>
template <u32 Size>
constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const u64 val) {
const u32 hi = val >> 32;
const u32 lo = val;
@@ -90,7 +91,7 @@ constexpr inline void write_access(std::array<u8, Size> &data, const u32 index,
*reinterpret_cast<u32 *>(&data[index + 4]) = lo;
}
template <typename T, size_t Size>
template <typename T, u32 Size>
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const T val) {
*reinterpret_cast<T *>(&data[index]) = val;
}
@@ -125,34 +126,34 @@ static constexpr inline void write_access(u8 *data, const u32 index, const T val
template <typename T>
static constexpr inline void swap_buffer(std::vector<u8> &data) {
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
for (u32 i = 0; i < data.size(); i += sizeof(T)) {
const T original = *reinterpret_cast<T *>(&data[i]);
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
}
}
template <typename T, size_t Size>
template <typename T, u32 Size>
static constexpr inline void swap_buffer(std::array<u8, Size> &data) {
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
for (u32 i = 0; i < data.size(); i += sizeof(T)) {
const T original = *reinterpret_cast<T *>(&data[i]);
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
}
}
template <typename T>
static constexpr inline void swap_buffer(u8 *data, size_t size) {
for (size_t i = 0; i < size; i += sizeof(T)) {
static constexpr inline void swap_buffer(u8 *data, u32 size) {
for (u32 i = 0; i < size; i += sizeof(T)) {
const T original = *reinterpret_cast<T *>(&data[i]);
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
}
}
#ifdef _WIN32
inline void *aligned_alloc(const size_t alignment, const size_t size) { return _aligned_malloc(size, alignment); }
inline void *aligned_alloc(const u32 alignment, const u32 size) { return _aligned_malloc(size, alignment); }
inline void aligned_free(void *ptr) { _aligned_free(ptr); }
#else
inline void *aligned_alloc(const size_t alignment, const size_t size) { return std::aligned_alloc(alignment, size); }
inline void *aligned_alloc(const u32 alignment, const u32 size) { return std::aligned_alloc(alignment, size); }
inline void aligned_free(void *ptr) { std::free(ptr); }
#endif
+9 -4
View File
@@ -11,25 +11,30 @@ using s16 = int16_t;
using s32 = int32_t;
using s64 = int64_t;
template <typename T, size_t bit>
template <typename T, u32 bit>
static constexpr bool is_bit_set(const T &val) {
return val & (1 << bit);
}
template <typename T, size_t bit>
template <typename T, u32 bit>
static constexpr void set_bit(T &val) {
val |= 1 << bit;
}
template <typename T>
inline bool is_bit_set(const T &val, const size_t &bit) {
inline bool is_bit_set(const T &val, const u32 &bit) {
return val & (1 << bit);
}
template <typename T>
inline void set_bit(T &val, const size_t &bit) {
inline void set_bit(T &val, const u32 &bit) {
val |= 1 << bit;
}
template <typename T>
inline void clear_bit(T &val, const u32 &bit) {
val &= ~(1 << bit);
}
} // namespace ircolib
constexpr ircolib::u32 operator""_kib(const unsigned long long v) { return v * 1024; }
+18 -10
View File
@@ -1,25 +1,24 @@
#include <cflags.hpp>
#include <ircolib/mem_access.hpp>
#include <ircolib/file.hpp>
#include <loaders/elf.hpp>
#include <loaders/dol.hpp>
#include <ircolib/log.hpp>
#include <mem.hpp>
#include <broadway.hpp>
#include <SDL3/SDL.h>
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char **argv) {
weee::core::mem mem;
weee::core::broadway broadway;
weee::core::video_interface &vi = mem.vi;
std::string binName;
cflags::cflags flags;
flags.add_string_callback(
'\0', "elf",
[&](const std::string &v) {
binName = fs::path(v).filename().string();
binName = ircolib::fs::path(v).filename().string();
if (!weee::core::load_elf(v, mem, broadway))
ircolib::panic("Could not load '{}'", v);
},
@@ -28,14 +27,20 @@ int main(int argc, char **argv) {
flags.add_string_callback(
'\0', "dol",
[&](const std::string &v) {
binName = fs::path(v).filename().string();
binName = ircolib::fs::path(v).filename().string();
if (!weee::core::load_dol(v, mem, broadway))
ircolib::panic("Could not load '{}'", v);
},
"DOL binary to load");
if (!flags.parse(argc, argv))
if (argc < 3) {
flags.print_usage("./weee <binary type flag> <binary path>",
"Available options:", "https://git.irco.sh/weeemu/weee");
return -1;
}
if (!flags.parse(argc, argv))
return -2;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("weee", 800, 600, SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_RESIZABLE);
@@ -44,7 +49,8 @@ int main(int argc, char **argv) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_SetRenderLogicalPresentation(renderer, 640, 480, SDL_LOGICAL_PRESENTATION_LETTERBOX);
ircolib::u8 *rgbTexture = (ircolib::u8 *)calloc(640 * 240, 3);
std::vector<ircolib::u8> rgbTexture;
rgbTexture.resize(640 * 240 * 3);
bool open = true;
while (open) {
@@ -61,15 +67,17 @@ int main(int argc, char **argv) {
open = false;
}
SDL_ConvertPixels(640, 240, SDL_PIXELFORMAT_UYVY, &mem.mem1[0x104000], 640 * 4, SDL_PIXELFORMAT_BGR24,
rgbTexture, 640 * 3);
SDL_ConvertPixels(640, 240, SDL_PIXELFORMAT_UYVY, &mem.mem1[0], 640 * 4, SDL_PIXELFORMAT_BGR24,
rgbTexture.data(), 640 * 3);
SDL_RenderClear(renderer);
SDL_UpdateTexture(texture, nullptr, rgbTexture, 640 * 3);
SDL_UpdateTexture(texture, nullptr, rgbTexture.data(), 640 * 3);
SDL_RenderTexture(renderer, texture, nullptr, nullptr);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();