#pragma once #include <cpu/iop/cop0.h> #include <common/manager.h> namespace iop { /* Used for storing load-delay slots */ struct LoadInfo { uint32_t reg = 0; uint32_t value = 0; }; /* Nice interface for instructions */ struct Instruction { union { uint32_t value; struct { /* Used when polling for the opcode */ uint32_t : 26; uint32_t opcode : 6; }; struct { uint32_t immediate : 16; uint32_t rt : 5; uint32_t rs : 5; uint32_t opcode : 6; } i_type; struct { uint32_t target : 26; uint32_t opcode : 6; } j_type; struct { uint32_t funct : 6; uint32_t sa : 5; uint32_t rd : 5; uint32_t rt : 5; uint32_t rs : 5; uint32_t opcode : 6; } r_type; }; uint32_t pc; bool is_delay_slot = false; bool branch_taken = false; Instruction operator=(const Instruction& instr) { value = instr.value; pc = instr.pc; is_delay_slot = instr.is_delay_slot; branch_taken = instr.branch_taken; return *this; } }; enum class Exception { Interrupt = 0x0, ReadError = 0x4, WriteError = 0x5, BusError = 0x6, Syscall = 0x8, Break = 0x9, IllegalInstr = 0xA, CoprocessorError = 0xB, Overflow = 0xC }; /* A class implemeting the PS2 IOP, a MIPS R3000A CPU. */ class IOProcessor { public: IOProcessor(ComponentManager* manager); ~IOProcessor(); /* CPU functionality */ void tick(); void reset(); void fetch(); void branch(); void handle_load_delay(); /* Call this after setting the PC to skip delay slot */ void direct_jump(); void exception(Exception cause, uint32_t cop = 0); void set_reg(uint32_t regN, uint32_t value); void load(uint32_t regN, uint32_t value); /* Bus communication. */ template <typename T> T read(uint32_t addr); template <typename T> void write(uint32_t addr, T data); /* Opcodes. */ void op_special(); void op_cop0(); /* Read/Write instructions. */ void op_lhu(); void op_lh(); void op_lbu(); void op_sw(); void op_swr(); void op_swl(); void op_lwr(); void op_lwl(); void op_lui(); void op_sb(); void op_lw(); void op_lb(); void op_sh(); /* Bitwise manipulation instructions. */ void op_and(); void op_andi(); void op_xor(); void op_xori(); void op_nor(); void op_or(); void op_ori(); /* Jump and branch instructions. */ void op_bcond(); void op_jalr(); void op_blez(); void op_bgtz(); void op_j(); void op_beq(); void op_jr(); void op_jal(); void op_bne(); /* Arithmetic instructions. */ void op_add(); void op_addi(); void op_addu(); void op_addiu(); void op_sub(); void op_subu(); void op_mult(); void op_multu(); void op_div(); void op_divu(); /* Bit shift-rotation instructions. */ void op_srl(); void op_srlv(); void op_sra(); void op_srav(); void op_sll(); void op_sllv(); void op_slt(); void op_slti(); void op_sltu(); void op_sltiu(); /* HI/LO instructions. */ void op_mthi(); void op_mtlo(); void op_mfhi(); void op_mflo(); /* Exception instructions. */ void op_break(); void op_syscall(); void op_rfe(); /* Coprocessor instructions. */ void op_mfc0(); void op_mtc0(); public: ComponentManager* manager; uint32_t pc; uint32_t i_stat, i_mask; uint32_t gpr[32]; uint32_t hi, lo; uint32_t exception_addr[2] = { 0x80000080, 0xBFC00180 }; /* Coprocessors. */ COP0 cop0; /* Pipeline stuff. */ LoadInfo write_back, memory_load, delayed_memory_load; Instruction instr, next_instr; FILE* disassembly; }; template<typename T> inline T IOProcessor::read(uint32_t addr) { return manager->read<T>(addr, Component::IOP); } template<typename T> inline void IOProcessor::write(uint32_t addr, T data) { manager->write<T>(addr, data, Component::IOP); } };