This repository has been archived on 2026-08-27. You can view files and clone it, but cannot push or open issues or pull requests.
gopher64-netplay/src/device/cpu.rs
Logan McNaughton 2e4a23c315 Initial Commit
2023-10-04 14:33:17 -06:00

285 lines
11 KiB
Rust

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<device::events::Event>,
pub next_event_count: u64,
pub next_event: Option<device::events::Event>,
}
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)
}
}
}