From 46b805164747758be0eb1ffc34e326434ffa2fa5 Mon Sep 17 00:00:00 2001 From: Ronit Dsilva <124994670+Cherrytree56567@users.noreply.github.com> Date: Sun, 22 Oct 2023 18:50:41 +1100 Subject: [PATCH] Start from Scratch --- PSEMU/Bios.cpp | 45 -- PSEMU/Bios.h | 19 - PSEMU/Bus.cpp | 1 - PSEMU/Bus.h | 200 ------- PSEMU/CPU.cpp | 1370 ------------------------------------------- PSEMU/CPU.h | 154 ----- PSEMU/Instruction.h | 43 -- PSEMU/PSEMU.cpp | 9 - PSEMU/RAM.cpp | 43 -- PSEMU/RAM.h | 26 - PSEMU/Range.h | 20 - Range.h | 0 12 files changed, 1930 deletions(-) delete mode 100644 PSEMU/Bios.cpp delete mode 100644 PSEMU/Bios.h delete mode 100644 PSEMU/Bus.cpp delete mode 100644 PSEMU/Bus.h delete mode 100644 PSEMU/CPU.cpp delete mode 100644 PSEMU/CPU.h delete mode 100644 PSEMU/Instruction.h delete mode 100644 PSEMU/RAM.cpp delete mode 100644 PSEMU/RAM.h delete mode 100644 PSEMU/Range.h delete mode 100644 Range.h diff --git a/PSEMU/Bios.cpp b/PSEMU/Bios.cpp deleted file mode 100644 index 26a701e..0000000 --- a/PSEMU/Bios.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "Bios.h" - -void Bios::newl(const char* path) { - std::ifstream file(path, std::ios::binary); - if (!file.is_open()) { - std::cerr << "Error: Unable to open the file." << std::endl; - } - - // Determine the file's size - file.seekg(0, std::ios::end); - size_t file_size = file.tellg(); - file.seekg(0, std::ios::beg); - - // Read the file into the vector - file.read(reinterpret_cast(data.data()), file_size); - - if (!file) { - std::cerr << "[Bios] Error: Failed to read the file." << std::endl; - } -} - -uint32_t Bios::load32(uint32_t offset) { - offset = static_cast(offset); - - uint32_t b0 = static_cast(data[offset + 0]); - uint32_t b1 = static_cast(data[offset + 1]); - uint32_t b2 = static_cast(data[offset + 2]); - uint32_t b3 = static_cast(data[offset + 3]); - - return (b0) | (b1 << 8) | (b2 << 16) | (b3 << 24); -} - -void Bios::store32(uint32_t offset, uint32_t val) { - uint32_t offsetU = static_cast(offset); - - uint8_t b0 = static_cast(val); - uint8_t b1 = static_cast(val >> 8); - uint8_t b2 = static_cast(val >> 16); - uint8_t b3 = static_cast(val >> 24); - - data[offsetU + 0] = b0; - data[offsetU + 1] = b1; - data[offsetU + 2] = b2; - data[offsetU + 3] = b3; -} diff --git a/PSEMU/Bios.h b/PSEMU/Bios.h deleted file mode 100644 index fd344fb..0000000 --- a/PSEMU/Bios.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include -#include -#include - -class Bios { -public: - Bios() : data(512*1024) {} - - void newl(const char* path); - uint32_t load32(uint32_t offset); - void store32(uint32_t offset, uint32_t store); - uint8_t load8(uint32_t offset) { return data[offset]; } - - const uint64_t bios_size = 512 * 1024; - std::vector data; -}; - diff --git a/PSEMU/Bus.cpp b/PSEMU/Bus.cpp deleted file mode 100644 index f861dcb..0000000 --- a/PSEMU/Bus.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Bus.h" diff --git a/PSEMU/Bus.h b/PSEMU/Bus.h deleted file mode 100644 index 1258331..0000000 --- a/PSEMU/Bus.h +++ /dev/null @@ -1,200 +0,0 @@ -#pragma once -#include -#include -#include -#include "Bios.h" -#include "Range.h" -#include "RAM.h" - -class Bus { -public: - Bus() { ram.newl(); } // Initialize BIOSRange in the constructor - - // Memory Ranges - const Range BIOS = Range(0x1fc00000, 512 * 1024); - const Range RAM_SIZE = Range(0x1f801060, 4); - const Range CACHE_CONTROL = Range(0xfffe0130, 4); - const Range RAM_ = Range(0x00000000, 2 * 1024 * 1024); - const Range SPU = Range(0x1f801c00, 640); - const Range EXPANSION_2 = Range(0x1f802000, 66); - const Range EXPANSION_1 = Range(0x1f000000, 512 * 1024); - const Range IRQ_CONTROL = Range(0x1f801070, 8); - const Range TIMERS = Range(0x1f801100, 0x30); - const Range DMA = Range(0x1f801080, 0x80); - const Range GPU = Range(0x1f801810, 8); - const Range MEM_CONTROL = Range(0x1f801000, 36); - - uint32_t mask_region(uint32_t addr) { - // Index address space in 512MB chunks - uint32_t index = (addr >> 29); - - return addr & region_mask[index]; - } - - // Load and Store functions - uint32_t load32(uint32_t addr) { - uint32_t abs_addr = mask_region(addr); - if (RAM_.contains(abs_addr)) { - return ram.load32(RAM_.offset(abs_addr)); - } else if (BIOS.contains(abs_addr)) { - return bios.load32(BIOS.offset(abs_addr)); - } else if (IRQ_CONTROL.contains(abs_addr)) { - std::cout << "[BUS] WARNING: IRQ CONTROL NOT IMPLEMENTED. IRQ control read " << std::to_string(IRQ_CONTROL.offset(abs_addr)) << "\n"; - return 0; - } else if (DMA.contains(abs_addr)) { - std::cout << "[BUS] WARNING: DMA NOT IMPLEMENTED. DMA read: " << std::to_string(DMA.offset(abs_addr)) << "\n"; - return 0; - } else if (GPU.contains(abs_addr)) { - std::cout << "[BUS] WARNING: GPU NOT IMPLEMENTED. GPU read " << std::to_string(GPU.offset(abs_addr)) << "\n"; - switch (GPU.offset(abs_addr)) { - case 4: - return 0x10000000; - break; - default: - return 0; - break; - } - } - - if (addr % 4 != 0) { - throw std::runtime_error("[Bus] ERROR: Unaligned load32 address " + std::to_string(addr)); - } - - throw std::runtime_error("[Bus] ERROR: Unhandled fetch32 at address " + std::to_string(addr)); - } - - void store32(uint32_t addr, uint32_t value) { - uint32_t abs_addr = mask_region(addr); - if (RAM_.contains(abs_addr)) { - ram.store32(RAM_.offset(abs_addr), value); - return; - } else if (BIOS.contains(abs_addr)) { - bios.store32(BIOS.offset(abs_addr), value); - return; - } else if (IRQ_CONTROL.contains(abs_addr)) { - std::cout << "[BUS] WARNING: IRQ CONTROL NOT IMPLEMENTED. IRQ control: " << std::to_string(IRQ_CONTROL.offset(abs_addr)) << " " << std::to_string(value) << "\n"; - return; - } else if (DMA.contains(abs_addr)) { - std::cout << "[BUS] WARNING: DMA NOT IMPLEMENTED. DMA write: " << std::to_string(abs_addr) << std::to_string(value) << "\n"; - return; - } else if (GPU.contains(abs_addr)) { - std::cout << "[BUS] WARNING: GPU NOT IMPLEMENTED. GPU write " << std::to_string(GPU.offset(abs_addr)) << " " << std::to_string(value) << "\n"; - return; - } else if (TIMERS.contains(abs_addr)) { - std::cout << "[BUS] WARNING: Timer NOT IMPLEMENTED. Timer write register" << std::to_string(TIMERS.offset(abs_addr)) << " " << std::to_string(value) << "\n"; - return; - } else if (CACHE_CONTROL.contains(abs_addr)) { - std::cout << "[Bus] WARNING: Cache Control not implemented. Cache Control read " << std::to_string(IRQ_CONTROL.offset(abs_addr)) << " " << std::to_string(value) << "\n"; - return; - } else if (MEM_CONTROL.contains(abs_addr)) { - switch (MEM_CONTROL.offset(abs_addr)) { - case 0: - if (value != 0x1f000000) { - std::cout << "[Bus] ERROR: Bad Expansion 1 base address: " << std::to_string(value) << "\n"; - } - break; - case 4: - if (value != 0x1f802000) { - std::cout << "[Bus] ERROR: Bad Expansion 2 base address: " << std::to_string(value) << "\n"; - } - break; - default: - std::cout << "[Bus] ERROR: Unhandled write to MEM Control " << std::to_string(IRQ_CONTROL.offset(abs_addr)) << " " << std::to_string(value) << "\n"; - break; - } - return; - } else if (RAM_SIZE.contains(abs_addr)) { - return; - } - - if (addr % 4 != 0) { - throw std::runtime_error("[Bus] ERROR: Unaligned store32 address " + std::to_string(addr)); - return; - } - - throw std::runtime_error("[Bus] ERROR: Unhandled store32 into address " + std::to_string(addr)); - } - - void store16(uint32_t addr, uint16_t value) { - uint32_t abs_addr = mask_region(addr); - if (RAM_.contains(abs_addr)) { - ram.store16(RAM_.offset(abs_addr), value); - return; - } else if (SPU.contains(abs_addr)) { - std::cout << "[BUS] WARNING: SPU NOT IMPLEMENTED. SPU write register " << std::to_string(SPU.offset(abs_addr)) << "\n"; - return; - } else if (TIMERS.contains(abs_addr)) { - std::cout << "[BUS] WARNING: TIMER NOT IMPLEMENTED. Timer write register " << std::to_string(TIMERS.offset(abs_addr)) << "\n"; - return; - } else if (IRQ_CONTROL.contains(abs_addr)) { - std::cout << "[BUS] WARNING: IRQ CONTROL NOT IMPLEMENTED. IRQ control write " << std::to_string(IRQ_CONTROL.offset(abs_addr)) << " " << std::to_string(value) << "\n"; - return; - } - - if (addr % 4 != 0) { - throw std::runtime_error("[Bus] ERROR: Unaligned store16 address " + std::to_string(addr)); - return; - } - - throw std::runtime_error("[Bus] ERROR: Unhandled store16 into address " + std::to_string(addr)); - } - - void store8(uint32_t addr, uint8_t value) { - uint32_t abs_addr = mask_region(addr); - if (RAM_.contains(abs_addr)) { - ram.store8(RAM_.offset(abs_addr), value); - return; - } else if (EXPANSION_2.contains(abs_addr)) { - std::cout << "[BUS] WARNING: Expansion 2 NOT IMPLEMENTED. Expansion 2 read register " << std::to_string(EXPANSION_2.offset(abs_addr)) << "\n"; - return; - } - - if (addr % 4 != 0) { - throw std::runtime_error("[Bus] ERROR: Unaligned store8 address " + std::to_string(addr)); - return; - } - - throw std::runtime_error("[Bus] ERROR: Unhandled store8 into address " + std::to_string(addr)); - } - - uint8_t load8(uint32_t addr) { - uint32_t abs_addr = mask_region(addr); - - if (RAM_.contains(abs_addr)) { - return ram.load8(RAM_.offset(abs_addr)); - } else if (BIOS.contains(abs_addr)) { - return bios.load8(BIOS.offset(abs_addr)); - } else if (EXPANSION_1.contains(abs_addr)) { - std::cout << "[BUS] WARNING: Expansion 1 NOT IMPLEMENTED. Expansion 1 read register " << std::to_string(EXPANSION_1.offset(abs_addr)) << "\n"; - return !0; - } - - throw std::runtime_error("[Bus] ERROR: Unhandled load8 into address " + std::to_string(addr)); - } - - uint16_t load16(uint8_t addr) { - uint32_t abs_addr = mask_region(addr); - - if (RAM_.contains(abs_addr)) { - return ram.load16(RAM_.offset(abs_addr)); - } else if (SPU.contains(abs_addr)) { - std::cout << "[BUS] WARNING: SPU NOT IMPLEMENTED. SPU read register " << std::to_string(SPU.offset(abs_addr)) << "\n"; - return 0; - } else if (IRQ_CONTROL.contains(abs_addr)) { - std::cout << "[BUS] WARNING: IRQ CONTROL NOT IMPLEMENTED. IRQ control read " << std::to_string(IRQ_CONTROL.offset(abs_addr)) << "\n"; - return 0; - } - - throw std::runtime_error("[Bus] ERROR: Unhandled load16 into address " + std::to_string(addr)); - } - - Bios bios; - RAM ram; - - const uint32_t region_mask[8] = { - 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, - 0x7fffffff, 0x1fffffff, - 0xffffffff, 0xffffffff, - }; -}; diff --git a/PSEMU/CPU.cpp b/PSEMU/CPU.cpp deleted file mode 100644 index 394c407..0000000 --- a/PSEMU/CPU.cpp +++ /dev/null @@ -1,1370 +0,0 @@ -#include "CPU.h" - -void CPU::tick() { - fetch(); -} - -void CPU::reset() { - pc = 0xbfc00000; - next_pc = pc + 4; - current_pc = 0; - hi = 0xdeadbeef; lo = 0xdeadbeef; - for (int i = 0; i < 32; i++) { - regs[i] = 0xdeadbeef; - out_regs[i] = 0xdeadbeef; - } - load = std::make_tuple(0, 0); - sr = 0; - cause = 0; - epc = 0; - delay_slot = false; - brancha = false; -} - -void CPU::fetch() { - current_pc = pc; - - if (current_pc % 4 != 0) { - // PC is not correctly aligned! - exception(Exception::LoadAddressError); - return; - } - - Instruction instr; - instr.instruction = bus->load32(pc); - - pc = next_pc; - next_pc = pc + 4; - - set_reg(std::get<0>(load), std::get<1>(load)); - - load = std::make_tuple(0, 0); - - delay_slot = brancha; - brancha = false; - - decode_execute(instr); - for (int i = 0; i < 32; i++) { - regs[i] = out_regs[i]; - } -} - -void CPU::decode_execute(Instruction instruction) { - std::cout << "instruction: " << instruction.instruction << "\n"; - switch (instruction.opcode()) { - case (0b000000): - switch (instruction.function()) { - case (0b100101): - op_or(instruction); - std::cout << "[CPU] INFO: OR (R-Type)\n"; - break; - - case (0b000000): - op_sll(instruction); - std::cout << "[CPU] INFO: SLL (R-Type)\n"; - break; - - case (0b101011): - op_sltu(instruction); - std::cout << "[CPU] INFO: SLTU (R-Type)\n"; - break; - - case (0b100001): - op_addu(instruction); - std::cout << "[CPU] INFO: ADDU (R-Type)\n"; - break; - - case (0b001000): - op_jr(instruction); - std::cout << "[CPU] INFO: JR (R-Type)\n"; - break; - - case (0b100100): - op_and(instruction); - std::cout << "[CPU] INFO: AND (R-Type)\n"; - break; - - case (0b100000): - op_add(instruction); - std::cout << "[CPU] INFO: ADD (R-Type)\n"; - break; - - case (0b001001): - op_jalr(instruction); - std::cout << "[CPU] INFO: JALR (R-Type)\n"; - break; - - case (0b100011): - op_subu(instruction); - std::cout << "[CPU] INFO: SUBU (R-Type)\n"; - break; - - case (0b000011): - op_sra(instruction); - std::cout << "[CPU] INFO: SRA (R-Type)\n"; - break; - - case (0b011010): - op_div(instruction); - std::cout << "[CPU] INFO: DIV (R-Type)\n"; - break; - - case (0b010010): - op_mflo(instruction); - std::cout << "[CPU] INFO: MFLO (R-Type)\n"; - break; - - case (0b000010): - op_srl(instruction); - std::cout << "[CPU] INFO: SRL (R-Type)\n"; - break; - - case (0b011011): - op_divu(instruction); - std::cout << "[CPU] INFO: DIVU (R-Type)\n"; - break; - - case (0b010000): - op_mfhi(instruction); - std::cout << "[CPU] INFO: MFHI (R-Type)\n"; - break; - - case (0b101010): - op_slt(instruction); - std::cout << "[CPU] INFO: SLT (R-Type)\n"; - break; - - case (0b001100): - op_syscall(instruction); - std::cout << "[CPU] INFO: SYSCALL (R-Type)\n"; - break; - - case (0b010011): - op_mtlo(instruction); - std::cout << "[CPU] INFO: MTLO (R-Type)\n"; - break; - - case (0b010001): - op_mthi(instruction); - std::cout << "[CPU] INFO: MTHI (R-Type)\n"; - break; - - case (0b000100): - op_sllv(instruction); - std::cout << "[CPU] INFO: SLLV (R-Type)\n"; - break; - - case (0b100111): - op_nor(instruction); - std::cout << "[CPU] INFO: NOR (R-Type)\n"; - break; - - case (0b000111): - op_srav(instruction); - std::cout << "[CPU] INFO: SRAV (R-Type)\n"; - break; - - case (0b000110): - op_srlv(instruction); - std::cout << "[CPU] INFO: SRLV (R-Type)\n"; - break; - - case (0b100110): - op_xor(instruction); - std::cout << "[CPU] INFO: XOR (R-Type)\n"; - break; - - case (0b011001): - op_multu(instruction); - std::cout << "[CPU] INFO: MULTU (R-Type)\n"; - break; - - case (0b001101): - op_break(instruction); - std::cout << "[CPU] INFO: BREAK (R-Type)\n"; - break; - - case (0b011000): - op_mult(instruction); - std::cout << "[CPU] INFO: MULT (R-Type)\n"; - break; - - case (0b100010): - op_sub(instruction); - std::cout << "[CPU] INFO: SUB (R-Type)\n"; - break; - - default: - std::cout << "[CPU] ERROR: Unhandled Function Instruction \n" << instruction.function(); - exception(Exception::IllegalInstruction); - break; - } - break; - - case (0b001001): - op_addiu(instruction); - std::cout << "[CPU] INFO: ADDIU (I-Type)\n"; - break; - - case (0b000010): - op_j(instruction); - std::cout << "[CPU] INFO: J (J-Type)\n"; - break; - - case (0b001111): - op_lui(instruction); - std::cout << "[CPU] INFO: LUI (I-Type)\n"; - break; - - case (0b001101): - op_ori(instruction); - std::cout << "[CPU] INFO: ORI (I-Type)\n"; - break; - - case (0b101011): - op_sw(instruction); - std::cout << "[CPU] INFO: SW (I-Type)\n"; - break; - - case (0b010000): - op_cop0(instruction); - std::cout << "[CPU] INFO: COP0 (I-Type)\n"; - break; - - case (0b000101): - op_bne(instruction); - std::cout << "[CPU] INFO: BNE (I-Type)\n"; - break; - - case (0b001000): - op_addi(instruction); - std::cout << "[CPU] INFO: ADDI (I-Type)\n"; - break; - - case (0b100011): - op_lw(instruction); - std::cout << "[CPU] INFO: LW (I-Type)\n"; - break; - - case (0b101001): - op_sh(instruction); - std::cout << "[CPU] INFO: SH (I-Type)\n"; - break; - - case (0b000011): - op_jal(instruction); - std::cout << "[CPU] INFO: JAL (I-Type)\n"; - break; - - case (0b001100): - op_andi(instruction); - std::cout << "[CPU] INFO: ANDI (I-Type)\n"; - break; - - case (0b101000): - op_sb(instruction); - std::cout << "[CPU] INFO: SB (I-Type)\n"; - break; - - case (0b100000): - op_lb(instruction); - std::cout << "[CPU] INFO: LB (I-Type)\n"; - break; - - case (0b000100): - op_beq(instruction); - std::cout << "[CPU] INFO: BEQ (I-Type)\n"; - break; - - case (0b000001): - op_bxx(instruction); - std::cout << "[CPU] INFO: BXX (I-Type)\n"; - break; - - case (0b000111): - op_bgtz(instruction); - std::cout << "[CPU] INFO: BGTZ (I-Type)\n"; - break; - - case (0b000110): - op_blez(instruction); - std::cout << "[CPU] INFO: BLEZ (I-Type)\n"; - break; - - case (0b100100): - op_lbu(instruction); - std::cout << "[CPU] INFO: LBU (I-Type)\n"; - break; - - case (0b001010): - op_slti(instruction); - std::cout << "[CPU] INFO: SLTI (I-Type)\n"; - break; - - case (0b001011): - op_sltiu(instruction); - std::cout << "[CPU] INFO: SLTIU (I-Type)\n"; - break; - - case (0b100101): - op_lhu(instruction); - std::cout << "[CPU] INFO: LHU (I-Type)\n"; - break; - - case (0b100001): - op_lh(instruction); - std::cout << "[CPU] INFO: LH (I-Type)\n"; - break; - - case (0b001110): - op_xori(instruction); - std::cout << "[CPU] INFO: XORI (I-Type)\n"; - break; - - case (0b010001): - op_cop1(instruction); - std::cout << "[CPU] INFO: COP1 (I-Type)\n"; - break; - - case (0b010011): - op_cop3(instruction); - std::cout << "[CPU] INFO: COP3 (I-Type)\n"; - break; - - case (0b010010): - op_cop2(instruction); - std::cout << "[CPU] INFO: COP2 (I-Type)\n"; - break; - - case (0b100010): - op_lwl(instruction); - std::cout << "[CPU] INFO: LWL (I-Type)\n"; - break; - - case (0b100110): - op_lwr(instruction); - std::cout << "[CPU] INFO: LWR (I-Type)\n"; - break; - - case (0b101010): - op_swl(instruction); - std::cout << "[CPU] INFO: SWL (I-Type)\n"; - break; - - case (0b101110): - op_swr(instruction); - std::cout << "[CPU] INFO: SWR (I-Type)\n"; - break; - - case (0b110000): - op_lwc0(instruction); - std::cout << "[CPU] INFO: LWC0 (I-Type)\n"; - break; - - case (0b110001): - op_lwc1(instruction); - std::cout << "[CPU] INFO: LWC1 (I-Type)\n"; - break; - - case (0b110010): - op_lwc2(instruction); - std::cout << "[CPU] INFO: LWC2 (I-Type)\n"; - break; - - case (0b110011): - op_lwc3(instruction); - std::cout << "[CPU] INFO: LWC3 (I-Type)\n"; - break; - - case (0b111000): - op_swc0(instruction); - std::cout << "[CPU] INFO: SWC0 (I-Type)\n"; - break; - - case (0b111001): - op_swc1(instruction); - std::cout << "[CPU] INFO: SWC1 (I-Type)\n"; - break; - - case (0b111010): - op_swc2(instruction); - std::cout << "[CPU] INFO: SWC2 (I-Type)\n"; - break; - - case (0b111011): - op_swc3(instruction); - std::cout << "[CPU] INFO: SWC3 (I-Type)\n"; - break; - - default: - std::cout << "[CPU] ERROR: Unhandled Instruction \n"; - exception(Exception::IllegalInstruction); - break; - } -} - -void CPU::op_lui(Instruction instruction) { - uint32_t i = instruction.imm(); - uint32_t t = instruction.rt(); - - uint32_t v = i << 16; - - set_reg(t, v); -} - -void CPU::op_ori(Instruction instruction) { - uint32_t i = instruction.imm(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t v = regs[s] | i; - - set_reg(t, v); -} - -void CPU::op_sw(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - // Assuming reg is a function that returns the value in a register - uint32_t addr = regs[s] + i; - uint32_t v = regs[t]; - - if (addr % 4 == 0) { - store32(addr, v); - } - else { - exception(Exception::StoreAddressError); - } -} - -void CPU::op_sll(Instruction instruction) { - uint32_t i = instruction.sa(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - uint32_t v = regs[t] << i; - - set_reg(d, v); -} - -void CPU::op_addiu(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t v = regs[s] + i; - - set_reg(t, v); -} - -void CPU::op_j(Instruction instruction) { - uint32_t i = instruction.addr(); - - next_pc = (pc & 0xf0000000) | (i << 2); - - brancha = true; -} - -void CPU::op_or(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = regs[s] | regs[t]; - - set_reg(d, v); -} - -void CPU::op_cop0(Instruction instruction) { - switch (instruction.rs()) { - case (0b00100): - op_mtc0(instruction); - std::cout << "[CPU] INFO: MTC0 (COP0-Type)\n"; - break; - - case (0b00000): - op_mfc0(instruction); - std::cout << "[CPU] INFO: MFC0 (COP0-Type)\n"; - break; - - case (0b10000): - op_rfe(instruction); - std::cout << "[CPU] INFO: RFE (COP0-Type)\n"; - break; - - default: - throw std::runtime_error("[CPU] ERROR: Unhandled COP0 Instruction"); - break; - } -} - -void CPU::op_mtc0(Instruction instruction) { - uint32_t cpu_r = instruction.rt(); - uint32_t cop_r = instruction.rd(); - - uint32_t v = regs[cpu_r]; - - switch (cop_r) { - case 3: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to COP0 Register" + std::to_string(cop_r)); - } - break; - - case 5: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to COP0 Register" + std::to_string(cop_r)); - } - break; - - case 6: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to COP0 Register" + std::to_string(cop_r)); - } - break; - - case 7: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to COP0 Register" + std::to_string(cop_r)); - } - break; - - case 9: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to COP0 Register" + std::to_string(cop_r)); - } - break; - - case 11: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to COP0 Register" + std::to_string(cop_r)); - } - break; - - case 12: - sr = v; - break; - - case 13: - if (v != 0) { - throw std::runtime_error("[CPU] ERROR: Unhandled write to CAUSE register."); - } - break; - - default: - throw std::runtime_error("Unhandled cop0 register " + std::to_string(cop_r)); - break; - } -} - -void CPU::branch(uint32_t offset) { - uint32_t offseta = offset << 2; - - next_pc = pc + offseta; - - brancha = true; -} - -void CPU::op_bne(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - if (regs[s] != regs[t]) { - branch(i); - } -} - -void CPU::op_addi(Instruction instruction) { - int32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - int32_t sValue = regs[s]; - - int32_t v; - - // Manual overflow check - if ((i > 0 && sValue > INT_MAX - i) || (i < 0 && sValue < INT_MIN - i)) { - // Overflow occurred - exception(Exception::Overflow); - } - else { - v = sValue + i; - set_reg(t, static_cast(v)); - } -} - -void CPU::op_lw(Instruction instruction) { - - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - if (addr % 4 == 0) { - uint32_t v = bus->load32(addr); - - // Put the load in the delay slot - load = std::make_tuple(t, v); - } - else { - exception(Exception::LoadAddressError); - } -} - -void CPU::op_sltu(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = regs[s] < regs[t]; - - set_reg(d, v); -} - -void CPU::op_addu(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - uint32_t v = regs[s] + regs[t]; - - set_reg(d, v); -} - -void CPU::op_sh(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - uint32_t v = regs[t]; - - if (addr % 2 == 0) { - store16(addr, (uint16_t)v); - } - else { - exception(Exception::StoreAddressError); - } -} - -void CPU::op_jal(Instruction instruction) { - uint32_t ra = next_pc; - - // Store return address in $31 ($ra) - set_reg(31, ra); - - op_j(instruction); - brancha = true; -} - -void CPU::op_andi(Instruction instruction) { - uint32_t i = instruction.imm(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t v = regs[s] & i; - - set_reg(t, v); -} - -void CPU::op_sb(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - uint32_t v = regs[t]; - - store8(addr, (uint8_t)v); -} - -void CPU::op_jr(Instruction instruction) { - uint32_t s = instruction.rs(); - - next_pc = regs[s]; - - brancha = true; -} - -void CPU::op_lb(Instruction instruction) { - - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - // Cast as i8 to force sign extension - uint8_t v = bus->load8(addr); - - // Put the load in the delay slot - load = std::make_tuple(t, (uint8_t)v); -} - -void CPU::op_beq(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - if (regs[s] == regs[t]) { - branch(i); - } -} - -void CPU::op_mfc0(Instruction instruction) { - uint32_t cpu_r = instruction.rt(); - uint32_t cop_r = instruction.rd(); - - uint32_t v; - - switch (cop_r) { - case 12: - v = sr; - break; - case 13: - v = cause; - break; - case 14: - v = epc; - break; - default: - throw std::runtime_error("[CPU] ERROR: Unhandled read from COP0R" + std::to_string(cop_r)); - } - - load = std::make_tuple(cpu_r, v); -} - -void CPU::op_and(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = regs[s] & regs[t]; - - set_reg(d, v); -} - -void CPU::op_add(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - int32_t sValue = regs[s]; - int32_t tValue = regs[t]; - - // Check for integer overflow - if ((tValue > 0 && sValue > INT_MAX - tValue) || (tValue < 0 && sValue < INT_MIN - tValue)) { - // Overflow occurred - exception(Exception::Overflow); - } - else { - set_reg(d, static_cast(sValue + tValue)); - } - -} - -void CPU::op_bgtz(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - - int32_t v = regs[s]; - - if (v > 0) { - branch(i); - } -} - -void CPU::op_blez(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - - int32_t v = regs[s]; - - if (v <= 0) { - branch(i); - } -} - -void CPU::op_lbu(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - uint8_t v = bus->load8(addr); - - // Put the load in the delay slot - load = std::make_tuple(t, (uint32_t)v); -} - -void CPU::op_jalr(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - - uint32_t ra = next_pc; - - // Store return address in `d` - set_reg(d, ra); - - next_pc = regs[s]; - brancha = true; -} - -void CPU::op_bxx(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - - uint32_t instructiona = instruction.instruction; - - uint32_t is_bgez = (instructiona >> 16) & 1; - uint32_t is_link = (instructiona >> 20) & 1 != 0; - - int32_t v = regs[s]; - - // Test "less than zero" - uint32_t test = (v < 0); - - // If the test is "greater than or equal to zero" we need - // to negate the comparison above since - // ("a >= 0" <=> "!(a < 0)"). The xor takes care of that. - test = test ^ is_bgez; - - if (test != 0) { - if (is_link) { - uint32_t ra = next_pc; - - // Store return address in R31 - set_reg(31, ra); - } - branch(i); - } -} - -void CPU::op_slti(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = ((int32_t)regs[s]) < i; - - set_reg(t, v); -} - -void CPU::op_subu(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - uint32_t v = regs[s] - regs[t]; - - set_reg(d, v); -} - -void CPU::op_sra(Instruction instruction) { - uint32_t i = instruction.sa(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - uint32_t v = ((int32_t)regs[t]) >> i; - - set_reg(d, v); -} - -void CPU::op_div(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t n = regs[s]; - uint32_t d = regs[t]; - - if (d == 0) { - // Division by zero, results are bogus - hi = static_cast(n); - - if (n >= 0) { - lo = 0xffffffff; - } else { - lo = 1; - } - } else if (static_cast(n) == 0x80000000 && d == -1) { - // Result is not representable in a 32-bit signed integer - hi = 0; - lo = 0x80000000; - } else { - hi = static_cast(n % d); - lo = static_cast(n / d); - } -} - -void CPU::op_mflo(Instruction instruction) { - uint32_t d = instruction.rd(); - - set_reg(d, lo); -} - -void CPU::op_srl(Instruction instruction) { - uint32_t i = instruction.sa(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - uint32_t v = regs[t] >> i; - - set_reg(d, v); -} - -void CPU::op_sltiu(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = regs[s] < i; - - set_reg(t, v); -} - -void CPU::op_divu(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t n = regs[s]; - uint32_t d = regs[t]; - - if (d == 0) { - // Division by zero, results are bogus - hi = n; - lo = 0xffffffff; - } else { - hi = n % d; - lo = n / d; - } -} - -void CPU::op_mfhi(Instruction instruction) { - uint32_t d = instruction.rd(); - - set_reg(d, hi); -} - -void CPU::op_slt(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - int32_t sa = regs[s]; - int32_t ta = regs[t]; - - int32_t v = s < t; - - set_reg(d, (uint32_t)v); -} - -void CPU::exception(Exception causea) { - if (regs[1] == 10) exit(0); - uint32_t handler = (sr & (1 << 22)) ? 0xbfc00180 : 0x80000080; - - uint32_t mode = sr & 0x3F; - sr &= (uint32_t)0x3F; - sr |= (mode << 2) & 0x3F; - - // Update `CAUSE` register with the exception code (bits [6:2]) - cause = (static_cast(causea) << 2); - - epc = current_pc; - - if (delay_slot) { - epc = epc - 4; - cause |= 1 << 31; - } - - // Exceptions don't have a branch delay slot; we jump directly - // into the handler. - pc = handler; - next_pc = pc + 4; -} - -void CPU::op_syscall(Instruction instruction) { - exception(Exception::SysCall); -} - -void CPU::op_mtlo(Instruction instruction) { - uint32_t s = instruction.rs(); - - lo = regs[s]; -} - -void CPU::op_mthi(Instruction instruction) { - uint32_t s = instruction.rs(); - - hi = regs[s]; -} - -void CPU::op_rfe(Instruction instruction) { - if ((instruction.instruction & 0x3f) != 0b010000) { - std::cout << "[CPU] ERROR: Invalid cop0 instruction: " << std::to_string(instruction.instruction) << "\n"; - } - - // Restore the pre-exception mode by shifting the Interrupt - // Enable/User Mode stack back to its original position. - uint32_t mode = sr & 0x3f; - sr &= !0x3f; - sr |= mode >> 2; -} - -void CPU::op_lhu(Instruction instruction) { - - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - // Address must be 16bit aligned - if (addr % 2 == 0) { - uint16_t v = bus->load16(addr); - - // Put the load in the delay slot - load = std::make_tuple(t, (uint32_t)v); - } else { - exception(Exception::LoadAddressError); - } -} - -void CPU::op_sllv(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - // Shift amount is truncated to 5 bits - uint32_t v = regs[t] << (regs[s] & 0x1f); - - set_reg(d, v); -} - -void CPU::op_lh(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - // Cast as i16 to force sign extension - uint16_t v = bus->load16(addr); - - // Put the load in the delay slot - load = std::make_tuple(t, (uint32_t)v); -} - -void CPU::op_nor(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = ~(regs[s] | regs[t]); - - set_reg(d, v); -} - -void CPU::op_srav(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - // Shift amount is truncated to 5 bits - uint32_t v = ((int32_t)regs[t]) >> (regs[s] & 0x1f); - - set_reg(d, v); -} - -void CPU::op_srlv(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - // Shift amount is truncated to 5 bits - uint32_t v = regs[t] >> (regs[s] & 0x1f); - - set_reg(d, v); -} - -void CPU::op_multu(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint64_t a = regs[s]; - uint64_t b = regs[t]; - - uint32_t v = a * b; - - hi = (uint32_t)(v >> 32); - lo = (uint32_t)v; -} - -void CPU::op_xor(Instruction instruction) { - uint32_t d = instruction.rd(); - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint32_t v = regs[s] ^ regs[t]; - - set_reg(d, v); -} - -void CPU::op_break(Instruction instruction) { - exception(Exception::Break); -} - -void CPU::op_mult(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - - uint64_t a = ((uint32_t)regs[s]); - uint64_t b = ((uint32_t)regs[t]); - - uint64_t v = (a * b); - - hi = (uint32_t)(v >> 32); - lo = (uint32_t)v; -} - -void CPU::op_sub(Instruction instruction) { - uint32_t s = instruction.rs(); - uint32_t t = instruction.rt(); - uint32_t d = instruction.rd(); - - int32_t sValue = regs[s]; - int32_t tValue = regs[t]; - - // Check for integer underflow - if ((tValue > 0 && sValue < INT_MIN + tValue) || (tValue < 0 && sValue > INT_MAX + tValue)) { - // Underflow occurred - exception(Exception::Overflow); - } - else { - set_reg(d, static_cast(sValue - tValue)); - } -} - -void CPU::op_xori(Instruction instruction) { - uint32_t i = instruction.imm(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t v = regs[s] ^ i; - - set_reg(t, v); -} - -void CPU::op_cop1(Instruction) { - exception(Exception::CoprocessorError); -} - -void CPU::op_cop3(Instruction) { - exception(Exception::CoprocessorError); -} - -void CPU::op_cop2(Instruction instruction) { - std::cout << "Unhandled GTE instruction: {" << std::to_string(instruction.instruction); -} - -void CPU::op_lwl(Instruction instruction) { - int32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - // This instruction bypasses the load delay restriction: this - // instruction will merge the new contents with the value - // currently being loaded if need be. - uint32_t cur_v = out_regs[t]; - - // Next we load the *aligned* word containing the first - // addressed byte - uint32_t aligned_addr = addr & ~3U; - uint32_t aligned_word = bus->load32(aligned_addr); - - // Depending on the address alignment, we fetch the 1, 2, 3, or - // 4 *most* significant bytes and put them in the target register. - uint32_t v; - switch (addr & 3U) { - case 0: - v = (cur_v & 0x00FFFFFF) | (aligned_word << 24); - break; - case 1: - v = (cur_v & 0x0000FFFF) | (aligned_word << 16); - break; - case 2: - v = (cur_v & 0x000000FF) | (aligned_word << 8); - break; - case 3: - v = (cur_v & 0x00000000) | (aligned_word); - break; - default: - throw std::runtime_error("Unreachable code"); - } - - // Put the load in the delay slot - load = std::make_tuple(t, v); -} - - -void CPU::op_lwr(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - - // This instruction bypasses the load delay restriction: this - // instruction will merge the new contents with the value - // currently being loaded if need be. - uint32_t cur_v = out_regs[t]; - - // Next, we load the *aligned* word containing the first - // addressed byte - uint32_t aligned_addr = addr & ~3; - uint32_t aligned_word = bus->load32(aligned_addr); - - // Depending on the address alignment, we fetch the 1, 2, 3, or - // 4 *least* significant bytes and put them in the target - // register. - uint32_t v = 0; - switch (addr & 3) { - case 0: - v = (cur_v & 0x00000000) | (aligned_word >> 0); - break; - case 1: - v = (cur_v & 0xff000000) | (aligned_word >> 8); - break; - case 2: - v = (cur_v & 0xffff0000) | (aligned_word >> 16); - break; - case 3: - v = (cur_v & 0xffffff00) | (aligned_word >> 24); - break; - default: - // Handle any unexpected cases here - break; - } - - // Put the load in the delay slot - load = std::make_tuple(t, v); -} - -void CPU::op_swl(Instruction instruction) { - int32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - uint32_t v = regs[t]; - - uint32_t aligned_addr = addr & ~3; - - // Load the current value for the aligned word at the target address - uint32_t cur_mem = bus->load32(aligned_addr); - - uint32_t mem; - switch (addr & 3U) { - case 0: - mem = (cur_mem & 0xFFFFFF00) | (v >> 24); - break; - case 1: - mem = (cur_mem & 0xFFFF0000) | (v >> 16); - break; - case 2: - mem = (cur_mem & 0xFF000000) | (v >> 8); - break; - case 3: - mem = (cur_mem & 0x00000000) | (v >> 0); - break; - default: - throw std::runtime_error("Unreachable code"); - } - - store32(aligned_addr, mem); -} - -void CPU::op_swr(Instruction instruction) { - uint32_t i = instruction.imm_s(); - uint32_t t = instruction.rt(); - uint32_t s = instruction.rs(); - - uint32_t addr = regs[s] + i; - uint32_t v = regs[t]; - - uint32_t aligned_addr = addr & ~3; - - // Load the current value for the aligned word at the target address - uint32_t cur_mem = bus->load32(aligned_addr); - - uint32_t mem; - switch (addr & 3U) { - case 0: - mem = (cur_mem & 0x00000000) | (v << 0); - break; - case 1: - mem = (cur_mem & 0x000000FF) | (v << 8); - break; - case 2: - mem = (cur_mem & 0x0000FFFF) | (v << 16); - break; - case 3: - mem = (cur_mem & 0x00FFFFFF) | (v << 24); - break; - default: - throw std::runtime_error("Unreachable code"); - } - - store32(aligned_addr, mem); -} - -void CPU::op_lwc0(Instruction instruction) { - // Not supported by this coprocessor - exception(Exception::CoprocessorError); -} - -void CPU::op_lwc1(Instruction instruction) { - // Not supported by this coprocessor - exception(Exception::CoprocessorError); -} - -void CPU::op_lwc2(Instruction instruction) { - // Handle the GTE LWC instruction. You can customize this part. - // If not supported, you can throw an exception like in the Rust code. - // For example: - throw std::runtime_error("Unhandled GTE LWC: " + std::to_string(instruction.instruction)); -} - -void CPU::op_lwc3(Instruction instruction) { - // Not supported by this coprocessor - exception(Exception::CoprocessorError); -} - -void CPU::op_swc0(Instruction instruction) { - // Not supported by this coprocessor - exception(Exception::CoprocessorError); -} - -void CPU::op_swc1(Instruction instruction) { - // Not supported by this coprocessor - exception(Exception::CoprocessorError); -} - -void CPU::op_swc2(Instruction instruction) { - // Handle the GTE SWC instruction. You can customize this part. - // If not supported, you can throw an exception like in the Rust code. - // For example: - throw std::runtime_error("Unhandled GTE SWC: " + std::to_string(instruction.instruction)); -} - -void CPU::op_swc3(Instruction instruction) { - // Not supported by this coprocessor - exception(Exception::CoprocessorError); -} diff --git a/PSEMU/CPU.h b/PSEMU/CPU.h deleted file mode 100644 index 8f5397a..0000000 --- a/PSEMU/CPU.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once -#include "Bus.h" -#include -#include -#include "Instruction.h" - -enum Exception { - SysCall = 0x8, - Overflow = 0xc, - LoadAddressError = 0x4, - StoreAddressError = 0x5, - Break = 0x9, - CoprocessorError = 0xb, - IllegalInstruction = 0xa -}; - -class CPU { -public: - CPU(Bus* bu) : bus(bu) {} - - // CPU FUNCTIONS - void tick(); - void fetch(); - void decode_execute(Instruction instruction); - - // CPU OPCODES - void op_lui(Instruction instruction); - void op_ori(Instruction instruction); - void op_sw(Instruction instruction); - void op_sll(Instruction instruction); - void op_addiu(Instruction instruction); - void op_j(Instruction instruction); - void op_or(Instruction instruction); - void op_cop0(Instruction instruction); - void op_mtc0(Instruction instruction); - void op_bne(Instruction instruction); - void op_addi(Instruction instruction); - void op_lw(Instruction instruction); - void op_sltu(Instruction instruction); - void op_addu(Instruction instruction); - void op_sh(Instruction instruction); - void branch(uint32_t offset); - - void op_jal(Instruction instruction); - void op_andi(Instruction instruction); - void op_sb(Instruction instruction); - void op_jr(Instruction instruction); - void op_lb(Instruction instruction); - void op_beq(Instruction instruction); - void op_mfc0(Instruction instruction); - void op_and(Instruction instruction); - void op_add(Instruction instruction); - void op_bgtz(Instruction instruction); - - void op_blez(Instruction instruction); - void op_lbu(Instruction instruction); - void op_jalr(Instruction instruction); - void op_bxx(Instruction instruction); - void op_slti(Instruction instruction); - void op_subu(Instruction instruction); - void op_sra(Instruction instruction); - void op_div(Instruction instruction); - void op_mflo(Instruction instruction); - void op_srl(Instruction instruction); - void op_sltiu(Instruction instruction); - void op_divu(Instruction instruction); - void op_mfhi(Instruction instruction); - void op_slt(Instruction instruction); - - void exception(Exception cause); - void op_syscall(Instruction instruction); - void op_mtlo(Instruction instruction); - void op_mthi(Instruction instruction); - void op_rfe(Instruction instruction); - void op_lhu(Instruction instruction); - void op_sllv(Instruction instruction); - void op_lh(Instruction instruction); - void op_nor(Instruction instruction); - void op_srav(Instruction instruction); - - void op_srlv(Instruction instruction); - void op_multu(Instruction instruction); - void op_xor(Instruction instruction); - void op_break(Instruction instruction); - void op_mult(Instruction instruction); - void op_sub(Instruction instruction); - void op_xori(Instruction instruction); - void op_cop1(Instruction instruction); - void op_cop3(Instruction instruction); - void reset(); - - void op_cop2(Instruction instruction); - void op_lwl(Instruction instruction); - void op_lwr(Instruction instruction); - void op_swl(Instruction instruction); - void op_swr(Instruction instruction); - void op_lwc0(Instruction instruction); - void op_lwc1(Instruction instruction); - void op_lwc2(Instruction instruction); - void op_lwc3(Instruction instruction); - void op_swc0(Instruction instruction); - void op_swc1(Instruction instruction); - void op_swc2(Instruction instruction); - void op_swc3(Instruction instruction); - - // HELPER FUNCTIONS - void set_reg(uint32_t index, uint32_t value) { - out_regs[index] = value; - - out_regs[0] = 0; - } - - void store32(uint32_t addr, uint32_t value) { - if (sr & 0x10000 != 0) { - // Cache is isolated, ignore write - std::cout << "[CPU] INFO: Ignore load while cache is isolated\n"; - return; - } - bus->store32(addr, value); - } - - void store16(uint32_t addr, uint32_t value) { - if (sr & 0x10000 != 0) { - // Cache is isolated, ignore write - std::cout << "[CPU] INFO: Ignore load while cache is isolated\n"; - return; - } - bus->store16(addr, value); - } - - void store8(uint32_t addr, uint32_t value) { - if (sr & 0x10000 != 0) { - // Cache is isolated, ignore write - std::cout << "[CPU] INFO: Ignore load while cache is isolated\n"; - return; - } - bus->store8(addr, value); - } - - Bus* bus; - uint32_t pc; - uint32_t next_pc; - uint32_t current_pc; - uint32_t cause; - uint32_t epc; - uint32_t regs[32]; - uint32_t hi; - uint32_t lo; - uint32_t sr; // COP0 Status Register - uint32_t out_regs[32]; - std::tuple load; - bool delay_slot, brancha; -}; - diff --git a/PSEMU/Instruction.h b/PSEMU/Instruction.h deleted file mode 100644 index 1281047..0000000 --- a/PSEMU/Instruction.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include - -struct Instruction { - uint32_t instruction; - - // OPCode - inline uint32_t opcode() const { - return instruction >> 26; - } - - inline uint32_t rt() const { - return (instruction >> 16) & 0x1f; - } - - inline uint32_t rs() const { - return (instruction >> 21) & 0x1F; - } - - inline uint32_t imm() const { - return instruction & 0xffff; - } - - inline uint32_t imm_s() const { - return(uint32_t)(int16_t)imm(); - } - - inline uint32_t rd() const { - return(instruction >> 11) & 0x1F; - } - - inline uint32_t sa() const { - return(instruction >> 6) & 0x1F; - } - - inline uint32_t function() const { - return instruction & 0x3F; - } - - inline uint32_t addr() const { - return instruction & 0x3FFFFFF; - } -}; \ No newline at end of file diff --git a/PSEMU/PSEMU.cpp b/PSEMU/PSEMU.cpp index a5744d1..a5e4633 100644 --- a/PSEMU/PSEMU.cpp +++ b/PSEMU/PSEMU.cpp @@ -7,16 +7,7 @@ */ #include -#include "CPU.h" -#include "Bus.h" int main() { - Bus bus; - bus.bios.newl("scph1001.bin"); - CPU cpu(&bus); - cpu.reset(); - while (true) { - cpu.tick(); - } return 0; } diff --git a/PSEMU/RAM.cpp b/PSEMU/RAM.cpp deleted file mode 100644 index f09da68..0000000 --- a/PSEMU/RAM.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "RAM.h" - -void RAM::newl() { - for (int i = 0; i < (2 * 1024 * 1024); i++) { - ram[i] = 0x0; - } -} - -uint32_t RAM::load32(uint32_t offset) { - offset = static_cast(offset); - - uint32_t b0 = ram[offset + 0]; - uint32_t b1 = ram[offset + 1]; - uint32_t b2 = ram[offset + 2]; - uint32_t b3 = ram[offset + 3]; - - return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); -} - -/// Store the 32bit little endian word `val` into `offset` -void RAM::store32(uint32_t offset, uint32_t value) { - offset = static_cast(offset); - - ram[offset + 0] = static_cast(value); - ram[offset + 1] = static_cast(value >> 8); - ram[offset + 2] = static_cast(value >> 16); - ram[offset + 3] = static_cast(value >> 24); -} - -void RAM::store16(uint32_t offset, uint16_t val) { - uint8_t b0 = val; - uint8_t b1 = (val >> 8); - - ram[offset + 0] = b0; - ram[offset + 1] = b1; -} - -uint16_t RAM::load16(uint32_t offset) { - uint16_t b0 = ram[offset + 0]; - uint16_t b1 = ram[offset + 1]; - - return b0 | (b1 << 8); -} \ No newline at end of file diff --git a/PSEMU/RAM.h b/PSEMU/RAM.h deleted file mode 100644 index 3c93703..0000000 --- a/PSEMU/RAM.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include - -class RAM { -public: - RAM() : ram(2 * 1024 * 1024) {} - - void newl(); - uint32_t load32(uint32_t offset); - void store32(uint32_t offset, uint32_t value); - void store16(uint32_t offset, uint16_t value); - void store8(uint32_t offset, uint8_t value) { - ram[offset] = value; - } - uint16_t load16(uint32_t offset); - - /// Fetch the byte at `offset` - uint8_t load8(uint32_t offset) { - return ram[offset]; - } - - std::vector ram; -}; - diff --git a/PSEMU/Range.h b/PSEMU/Range.h deleted file mode 100644 index 712ed21..0000000 --- a/PSEMU/Range.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include -#include -#include -#include - -struct Range { - uint32_t start; - uint32_t length; - - Range(uint32_t s, uint32_t l) : start(s), length(l) {} - - inline bool contains(uint32_t addr) const { - return (addr >= start && addr < start + length); - } - - inline uint32_t offset(uint32_t addr) const { - return addr - start; - } -}; diff --git a/Range.h b/Range.h deleted file mode 100644 index e69de29..0000000