use crate::device; #[derive(PartialEq)] pub enum State { Step, Take, NotTaken, DelaySlotTaken, DelaySlotNotTaken, Discard, Exception, } pub struct BranchState { pub state: State, pub pc: u64, } pub struct Cpu { pub cop0: device::cop0::Cop0, pub cop1: device::cop1::Cop1, pub cop2: device::cop2::Cop2, pub branch_state: BranchState, pub gpr: [u64; 32], pub pc: u64, pub lo: u64, pub hi: u64, pub running: u8, pub llbit: bool, pub clock_rate: u64, pub instrs: [fn(&mut device::Device, u32); 64], pub special_instrs: [fn(&mut device::Device, u32); 64], pub regimm_instrs: [fn(&mut device::Device, u32); 32], pub events: Vec, pub next_event_count: u64, pub next_event: Option, } pub fn decode_opcode(device: &mut device::Device, opcode: u32) -> fn(&mut device::Device, u32) { match opcode >> 26 { 0 => device.cpu.special_instrs[(opcode & 0x3F) as usize], // SPECIAL 1 => device.cpu.regimm_instrs[((opcode >> 16) & 0x1F) as usize], // REGIMM 16 => device.cpu.cop0.instrs[((opcode >> 21) & 0x1F) as usize], // COP0 17 => device.cpu.cop1.instrs[((opcode >> 21) & 0x1F) as usize], // COP1 18 => device.cpu.cop2.instrs[((opcode >> 21) & 0x1F) as usize], // COP2 _ => device.cpu.instrs[(opcode >> 26) as usize], } } pub fn init(device: &mut device::Device) { device.cpu.clock_rate = 93750000; device.cpu.instrs = [ device::cop0::reserved, // SPECIAL device::cop0::reserved, // REGIMM device::cpu_instructions::j, // 2 device::cpu_instructions::jal, // 3 device::cpu_instructions::beq, // 4 device::cpu_instructions::bne, // 5 device::cpu_instructions::blez, // 6 device::cpu_instructions::bgtz, // 7 device::cpu_instructions::addi, // 8 device::cpu_instructions::addiu, // 9 device::cpu_instructions::slti, // 10 device::cpu_instructions::sltiu, // 11 device::cpu_instructions::andi, // 12 device::cpu_instructions::ori, // 13 device::cpu_instructions::xori, // 14 device::cpu_instructions::lui, // 15 device::cop0::reserved, // COP0 device::cop0::reserved, // COP1 device::cop0::reserved, // COP2 device::cop0::reserved, // 19 device::cpu_instructions::beql, // 20 device::cpu_instructions::bnel, // 21 device::cpu_instructions::blezl, // 22 device::cpu_instructions::bgtzl, // 23 device::cpu_instructions::daddi, // 24 device::cpu_instructions::daddiu, // 25 device::cpu_instructions::ldl, // 26 device::cpu_instructions::ldr, // 27 device::cop0::reserved, // 28 device::cop0::reserved, // 29 device::cop0::reserved, // 30 device::cop0::reserved, // 31 device::cpu_instructions::lb, // 32 device::cpu_instructions::lh, // 33 device::cpu_instructions::lwl, // 34 device::cpu_instructions::lw, // 35 device::cpu_instructions::lbu, // 36 device::cpu_instructions::lhu, // 37 device::cpu_instructions::lwr, // 38 device::cpu_instructions::lwu, // 39 device::cpu_instructions::sb, // 40 device::cpu_instructions::sh, // 41 device::cpu_instructions::swl, // 42 device::cpu_instructions::sw, // 43 device::cpu_instructions::sdl, // 44 device::cpu_instructions::sdr, // 45 device::cpu_instructions::swr, // 46 device::cpu_instructions::cache, // 47 device::cpu_instructions::ll, // 48 device::cop1::lwc1, // 49 device::cop0::reserved, // 50 device::cop0::reserved, // 51 device::cpu_instructions::lld, // 52 device::cop1::ldc1, // 53 device::cop0::reserved, // 54 device::cpu_instructions::ld, // 55 device::cpu_instructions::sc, // 56 device::cop1::swc1, // 57 device::cop0::reserved, // 58 device::cop0::reserved, // 59 device::cpu_instructions::scd, // 60 device::cop1::sdc1, // 61 device::cop0::reserved, // 62 device::cpu_instructions::sd, // 63 ]; device.cpu.special_instrs = [ device::cpu_instructions::sll, // 0 device::cop0::reserved, // 1 device::cpu_instructions::srl, // 2 device::cpu_instructions::sra, // 3 device::cpu_instructions::sllv, // 4 device::cop0::reserved, // 5 device::cpu_instructions::srlv, // 6 device::cpu_instructions::srav, // 7 device::cpu_instructions::jr, // 8 device::cpu_instructions::jalr, // 9 device::cop0::reserved, // 10 device::cop0::reserved, // 11 device::cop0::syscall, // 12 device::cop0::break_, // 13 device::cop0::reserved, // 14 device::cpu_instructions::sync, // 15 device::cpu_instructions::mfhi, // 16 device::cpu_instructions::mthi, // 17 device::cpu_instructions::mflo, // 18 device::cpu_instructions::mtlo, // 19 device::cpu_instructions::dsllv, // 20 device::cop0::reserved, // 21 device::cpu_instructions::dsrlv, // 22 device::cpu_instructions::dsrav, // 23 device::cpu_instructions::mult, // 24 device::cpu_instructions::multu, // 25 device::cpu_instructions::div, // 26 device::cpu_instructions::divu, // 27 device::cpu_instructions::dmult, // 28 device::cpu_instructions::dmultu, // 29 device::cpu_instructions::ddiv, // 30 device::cpu_instructions::ddivu, // 31 device::cpu_instructions::add, // 32 device::cpu_instructions::addu, // 33 device::cpu_instructions::sub, // 34 device::cpu_instructions::subu, // 35 device::cpu_instructions::and, // 36 device::cpu_instructions::or, // 37 device::cpu_instructions::xor, // 38 device::cpu_instructions::nor, // 39 device::cop0::reserved, // 40 device::cop0::reserved, // 41 device::cpu_instructions::slt, // 42 device::cpu_instructions::sltu, // 43 device::cpu_instructions::dadd, // 44 device::cpu_instructions::daddu, // 45 device::cpu_instructions::dsub, // 46 device::cpu_instructions::dsubu, // 47 device::cpu_instructions::tge, // 48 device::cpu_instructions::tgeu, // 49 device::cpu_instructions::tlt, // 50 device::cpu_instructions::tltu, // 51 device::cpu_instructions::teq, // 52 device::cop0::reserved, // 53 device::cpu_instructions::tne, // 54 device::cop0::reserved, // 55 device::cpu_instructions::dsll, // 56 device::cop0::reserved, // 57 device::cpu_instructions::dsrl, // 58 device::cpu_instructions::dsra, // 59 device::cpu_instructions::dsll32, // 60 device::cop0::reserved, // 61 device::cpu_instructions::dsrl32, // 62 device::cpu_instructions::dsra32, // 63 ]; device.cpu.regimm_instrs = [ device::cpu_instructions::bltz, // 0 device::cpu_instructions::bgez, // 1 device::cpu_instructions::bltzl, // 2 device::cpu_instructions::bgezl, // 3 device::cop0::reserved, // 4 device::cop0::reserved, // 5 device::cop0::reserved, // 6 device::cop0::reserved, // 7 device::cpu_instructions::tgei, // 8 device::cpu_instructions::tgeiu, // 9 device::cpu_instructions::tlti, // 10 device::cpu_instructions::tltiu, // 11 device::cpu_instructions::teqi, // 12 device::cop0::reserved, // 13 device::cpu_instructions::tnei, // 14 device::cop0::reserved, // 15 device::cpu_instructions::bltzal, // 16 device::cpu_instructions::bgezal, // 17 device::cpu_instructions::bltzall, // 18 device::cpu_instructions::bgezall, // 19 device::cop0::reserved, // 20 device::cop0::reserved, // 21 device::cop0::reserved, // 22 device::cop0::reserved, // 23 device::cop0::reserved, // 24 device::cop0::reserved, // 25 device::cop0::reserved, // 26 device::cop0::reserved, // 27 device::cop0::reserved, // 28 device::cop0::reserved, // 29 device::cop0::reserved, // 30 device::cop0::reserved, // 31 ]; device::cop0::init(device); device::cop1::init(device); device::cop2::init(device); } pub fn in_delay_slot(device: &mut device::Device) -> bool { return device.cpu.branch_state.state == State::DelaySlotTaken || device.cpu.branch_state.state == State::DelaySlotNotTaken; } pub fn in_delay_slot_taken(device: &mut device::Device) -> bool { return device.cpu.branch_state.state == State::DelaySlotTaken; } pub fn run(device: &mut device::Device) { device.cpu.running = 1; while device.cpu.running == 1 { device.cpu.gpr[0] = 0; // gpr 0 is read only let (phys_address, cached, err) = device::memory::translate_address( device, device.cpu.pc, device::memory::AccessType::Read, ); if err { continue; // TLB exception } if cached { device::cache::icache_fetch(device, phys_address) } else { let opcode = device.memory.memory_map_read[(phys_address >> 16) as usize]( device, phys_address, device::memory::AccessSize::Word, ); device::cpu::decode_opcode(device, opcode)(device, opcode); } match device.cpu.branch_state.state { State::Step => device.cpu.pc += 4, State::Take => { device.cpu.pc += 4; device.cpu.branch_state.state = State::DelaySlotTaken } State::NotTaken => { device.cpu.pc += 4; device.cpu.branch_state.state = State::DelaySlotNotTaken } State::DelaySlotTaken => { device.cpu.pc = device.cpu.branch_state.pc; device.cpu.branch_state.state = State::Step } State::DelaySlotNotTaken => { device.cpu.pc += 4; device.cpu.branch_state.state = State::Step } State::Discard => { device.cpu.pc += 8; device.cpu.branch_state.state = State::Step } State::Exception => device.cpu.branch_state.state = State::Step, } device::cop0::add_cycles(device, 1); if device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG as usize] > device.cpu.next_event_count { device::events::trigger_event(device) } } }