use crate::mips::Insn;
use crate::Encode;
use crate::Sequence;
use trapezoid_core::cpu::{BusLine, Cpu, CpuBusProvider, RegisterType};
struct Bus {
kseg1: [u8; 0x10000],
}
impl BusLine for Bus {
fn read_u32(&mut self, addr: u32) -> Result<u32, String> {
match addr {
0xBFC00000..=0xBFC0FFFF => {
let offset = addr - 0xBFC00000;
let word = u32::from_le_bytes([
self.kseg1[offset as usize],
self.kseg1[(offset + 1) as usize],
self.kseg1[(offset + 2) as usize],
self.kseg1[(offset + 3) as usize],
]);
Ok(word)
}
_ => Ok(0),
}
}
fn read_u8(&mut self, addr: u32) -> Result<u8, String> {
match addr {
0xBFC00000..=0xBFC0FFFF => {
let offset = addr - 0xBFC00000;
Ok(self.kseg1[offset as usize])
}
_ => Ok(0),
}
}
fn write_u32(&mut self, addr: u32, data: u32) -> Result<(), String> {
match addr {
0xBFC00000..=0xBFC0FFFF => {
let offset = addr - 0xBFC00000;
self.kseg1[offset as usize] = data as u8;
self.kseg1[(offset + 1) as usize] = (data >> 8) as u8;
self.kseg1[(offset + 2) as usize] = (data >> 16) as u8;
self.kseg1[(offset + 3) as usize] = (data >> 24) as u8;
Ok(())
}
_ => Ok(()),
}
}
fn write_u8(&mut self, addr: u32, data: u8) -> Result<(), String> {
match addr {
0xbfc00000..=0xbfc0ffff => {
let offset = addr - 0xbfc00000;
self.kseg1[offset as usize] = data;
Ok(())
}
_ => Ok(()),
}
}
}
impl CpuBusProvider for Bus {
fn pending_interrupts(&self) -> bool {
false
}
fn should_run_dma(&self) -> bool {
false
}
}
pub trait Parameters {
fn install(self, cpu: &mut Cpu);
fn analyze_this(seq: &Sequence<Insn>) -> Result<(), crate::StaticAnalysis<Insn>>;
}
pub trait ReturnValue {
fn extract(cpu: &Cpu) -> Self;
fn analyze_this(seq: &Sequence<Insn>) -> Result<(), crate::StaticAnalysis<Insn>>;
}
impl Parameters for u8 {
fn install(self, cpu: &mut Cpu) {
cpu.registers_mut().write(RegisterType::A0, self as u32)
}
fn analyze_this(seq: &Sequence<Insn>) -> Result<(), crate::StaticAnalysis<Insn>> {
crate::dataflow::expect_read(seq, &RegisterType::A0)
}
}
impl ReturnValue for u8 {
fn extract(cpu: &Cpu) -> Self {
cpu.registers().read(RegisterType::V0) as u8
}
fn analyze_this(seq: &Sequence<Insn>) -> Result<(), crate::StaticAnalysis<Insn>> {
crate::dataflow::expect_write(seq, &RegisterType::V0)
}
}
impl Parameters for f32 {
fn install(self, cpu: &mut Cpu) {
cpu.registers_mut().write(RegisterType::A0, self.to_bits())
}
fn analyze_this(seq: &Sequence<Insn>) -> Result<(), crate::StaticAnalysis<Insn>> {
crate::dataflow::expect_read(seq, &RegisterType::A0)?;
crate::dataflow::uninitialized(seq, &RegisterType::A1)?;
crate::dataflow::uninitialized(seq, &RegisterType::A2)?;
crate::dataflow::uninitialized(seq, &RegisterType::A3)
}
}
impl ReturnValue for f32 {
fn extract(cpu: &Cpu) -> Self {
Self::from_bits(cpu.registers().read(RegisterType::V0))
}
fn analyze_this(seq: &Sequence<Insn>) -> Result<(), crate::StaticAnalysis<Insn>> {
crate::dataflow::expect_write(seq, &RegisterType::V0)
}
}
pub fn call<P: Parameters, R: ReturnValue>(
subroutine: &Sequence<Insn>,
params: P,
) -> crate::RunResult<R> {
let mut cpu = Cpu::new();
let mut kseg1 = [0; 0x10000];
let subroutine = subroutine.encode();
kseg1[0..subroutine.len()].copy_from_slice(&subroutine);
let mut bus = Bus { kseg1 };
let end_pc = 0xBFC00000 + subroutine.len() as u32;
params.install(&mut cpu);
for _ in 0..10000 {
if cpu.registers().read(RegisterType::Pc) == end_pc {
return Ok(R::extract(&cpu));
}
cpu.clock(&mut bus, 1);
}
Err(crate::RunError::RanAmok)
}
#[cfg(test)]
pub fn call_instruction(insn: &Insn) {
let mut cpu = Cpu::new();
let mut kseg1 = [0; 0x10000];
let bin = insn.encode();
kseg1[0..bin.len()].copy_from_slice(&bin);
let mut bus = Bus { kseg1 };
cpu.clock(&mut bus, 1);
}
pub fn call_raw(subroutine: &Sequence<Insn>) -> crate::RunResult<()> {
let mut cpu = Cpu::new();
let mut kseg1 = [0; 0x10000];
let subroutine = subroutine.encode();
kseg1[0..subroutine.len()].copy_from_slice(&subroutine);
let mut bus = Bus { kseg1 };
let end_pc = 0xBFC00000 + subroutine.len() as u32;
for _ in 0..10000 {
if cpu.registers().read(RegisterType::Pc) == end_pc {
return Ok(());
}
cpu.clock(&mut bus, 1);
}
Err(crate::RunError::RanAmok)
}