use core::fmt;
use crate::bus::BusAccess;
pub trait Step<Address, Bus>
where
Address: Copy,
Bus: BusAccess<Address>,
{
type Error; fn is_running(&mut self) -> bool;
fn reset(&mut self, now: Bus::Instant, bus: &mut Bus) -> Result<(), Self::Error>;
fn step(&mut self, now: Bus::Instant, bus: &mut Bus) -> Result<Bus::Instant, Self::Error>;
}
pub trait Inspect<Address, Bus, Writer>
where
Address: Copy,
Bus: BusAccess<Address>,
Writer: fmt::Write,
{
type InfoType;
type Error;
fn inspect(
&mut self,
info: Self::InfoType,
bus: &mut Bus,
writer: &mut Writer,
) -> Result<(), Self::Error>;
fn brief_summary(&mut self, bus: &mut Bus, writer: &mut Writer) -> Result<(), Self::Error>;
fn detailed_summary(&mut self, bus: &mut Bus, writer: &mut Writer) -> Result<(), Self::Error>;
}
pub trait Debug<Address, Bus, Writer>: Inspect<Address, Bus, Writer> + Step<Address, Bus>
where
Address: Copy,
Bus: BusAccess<Address>,
Writer: fmt::Write,
{
type DebugError;
fn get_execution_address(&mut self) -> Result<Address, Self::DebugError>;
fn set_execution_address(&mut self, address: Address) -> Result<(), Self::DebugError>;
fn add_breakpoint(&mut self, address: Address);
fn remove_breakpoint(&mut self, address: Address);
fn clear_breakpoints(&mut self);
}
#[cfg(test)]
mod test {
use super::*;
use crate::time::Instant;
use crate::{BasicBusError, BusAdapter, ErrorType};
use std::ops::Range;
use std::str;
use std::time::Duration;
#[derive(Clone, Debug)]
enum Error {
BusError,
}
impl ErrorType for Error {}
impl From<BasicBusError> for Error {
fn from(_err: BasicBusError) -> Self {
Error::BusError
}
}
struct Memory(Vec<u8>);
impl BusAccess<u32> for Memory {
type Instant = Duration;
type Error = BasicBusError;
fn read(
&mut self,
_now: Duration,
addr: u32,
data: &mut [u8],
) -> Result<usize, Self::Error> {
let addr = addr as usize;
data.copy_from_slice(&self.0[addr..addr + data.len()]);
Ok(data.len())
}
fn write(&mut self, _now: Duration, addr: u32, data: &[u8]) -> Result<usize, Self::Error> {
let addr = addr as usize;
self.0[addr..addr + data.len()].copy_from_slice(data);
Ok(data.len())
}
}
#[derive(Clone, Debug)]
enum OutputError {
Utf8Error,
}
impl ErrorType for OutputError {}
impl From<OutputError> for Error {
fn from(_err: OutputError) -> Self {
Error::BusError
}
}
struct Output();
impl BusAccess<u16> for Output {
type Instant = Duration;
type Error = OutputError;
fn read(
&mut self,
_now: Duration,
_addr: u16,
_data: &mut [u8],
) -> Result<usize, Self::Error> {
Ok(0)
}
fn write(&mut self, _now: Duration, _addr: u16, data: &[u8]) -> Result<usize, Self::Error> {
let string = str::from_utf8(data).map_err(|_| OutputError::Utf8Error)?;
print!("{}", string);
Ok(data.len())
}
}
struct FixedBus {
output: Output,
memory: Memory,
}
impl BusAccess<u64> for FixedBus {
type Instant = Duration;
type Error = Error;
fn read(
&mut self,
now: Duration,
addr: u64,
data: &mut [u8],
) -> Result<usize, Self::Error> {
if (0..0x1_0000).contains(&addr) {
self.memory
.read(now, addr as u32 % 0x1_0000, data)
.map_err(|_| Error::BusError)
} else {
self.output
.read(now, addr as u16, data)
.map_err(|_| Error::BusError)
}
}
fn write(&mut self, now: Duration, addr: u64, data: &[u8]) -> Result<usize, Self::Error> {
if (0..0x1_0000).contains(&addr) {
self.memory
.write(now, addr as u32 % 0x1_0000, data)
.map_err(|_| Error::BusError)
} else {
self.output
.write(now, addr as u16, data)
.map_err(|_| Error::BusError)
}
}
}
struct DynamicBus {
devices: Vec<(
Range<u64>,
Box<dyn BusAccess<u64, Instant = Duration, Error = Error>>,
)>,
}
impl BusAccess<u64> for DynamicBus {
type Instant = Duration;
type Error = Error;
fn read(
&mut self,
now: Duration,
addr: u64,
data: &mut [u8],
) -> Result<usize, Self::Error> {
for (range, device) in self.devices.iter_mut() {
if range.contains(&addr) {
return device.read(now, addr, data).map_err(|_| Error::BusError);
}
}
Ok(0)
}
fn write(&mut self, now: Duration, addr: u64, data: &[u8]) -> Result<usize, Self::Error> {
for (range, device) in self.devices.iter_mut() {
if range.contains(&addr) {
return device.write(now, addr, data).map_err(|_| Error::BusError);
}
}
Ok(0)
}
}
#[derive(Default)]
struct Cpu {
pc: u64,
sum: u32,
running: bool,
}
impl<Bus> Step<u64, Bus> for Cpu
where
Bus: BusAccess<u64, Instant = Duration>,
Error: From<Bus::Error>,
{
type Error = Error;
fn is_running(&mut self) -> bool {
self.running
}
fn reset(&mut self, now: Duration, bus: &mut Bus) -> Result<(), Self::Error> {
self.running = true;
self.pc = bus.read_beu32(now, 0x0000)? as u64;
Ok(())
}
fn step(&mut self, now: Duration, bus: &mut Bus) -> Result<Duration, Self::Error> {
if self.running {
let value = bus.read_beu32(now, self.pc)?;
self.pc += 4;
if value == 0 {
self.running = false;
} else {
self.sum += value;
}
}
Ok(now + Duration::from_nanos(100))
}
}
#[test]
fn test_static_system() {
let memory = Memory(vec![0; 1024]);
let output = Output();
let mut bus = FixedBus { memory, output };
let mut cpu = Cpu::default();
let location = 0x100;
bus.memory
.write_beu32(Duration::START, 0x0000, location as u32)
.unwrap();
for i in 0..100 {
bus.memory
.write_beu32(Duration::START, location + 4 * i as u32, 1 + i as u32)
.unwrap();
}
fn run_static_test<A, B, C>(bus: &mut B, cpu: &mut C) -> Result<(), C::Error>
where
A: Copy,
B: BusAccess<A, Instant = Duration>,
C: Step<A, B>,
C::Error: From<B::Error>,
{
cpu.reset(Duration::START, bus)?;
while cpu.is_running() {
cpu.step(Duration::START, bus)?;
}
Ok(())
}
run_static_test(&mut bus, &mut cpu).unwrap();
assert_eq!(cpu.sum, 5050);
}
#[cfg(feature = "alloc")]
#[test]
fn test_dynamic_system() {
let memory = Memory(vec![0; 1024]);
let output = Output();
let mut bus = DynamicBus {
devices: vec![
(
0..0x1_0000,
Box::new(BusAdapter::new(memory, |addr| addr as u32)),
),
(
0x2_0000..0x2_0010,
Box::new(BusAdapter::new(output, |addr| addr as u16)),
),
],
};
let mut cpu = Cpu::default();
let location = 0x100 as u64;
bus.write_beu32(Duration::START, 0x0000, location as u32)
.unwrap();
for i in 0..100 {
bus.write_beu32(Duration::START, location + 4 * i as u64, 1 + i as u32)
.unwrap();
}
type Bus = Box<dyn BusAccess<u64, Instant = Duration, Error = Error>>;
fn run_dynamic_test(
mut bus: Bus,
cpu: &mut dyn Step<u64, Bus, Error = Error>,
) -> Result<(), Error> {
cpu.reset(Duration::START, &mut bus)?;
while cpu.is_running() {
cpu.step(Duration::START, &mut bus)?;
}
Ok(())
}
run_dynamic_test(Box::new(bus), &mut cpu).unwrap();
assert_eq!(cpu.sum, 5050);
}
}