use super::*;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
#[derive(Default)]
struct CaptureLog {
stdout: Vec<u8>,
stderr: Vec<u8>,
diagnostics: Vec<String>,
traps: Vec<(TrapCode, u8, u64, u64)>,
flushes: usize,
}
#[derive(Clone, Default)]
struct CaptureHandle(Rc<RefCell<CaptureLog>>);
impl CaptureHandle {
fn stdout(&self) -> Vec<u8> {
self.0.borrow().stdout.clone()
}
fn stderr(&self) -> Vec<u8> {
self.0.borrow().stderr.clone()
}
fn diagnostics(&self) -> Vec<String> {
self.0.borrow().diagnostics.clone()
}
fn traps(&self) -> Vec<(TrapCode, u8, u64, u64)> {
self.0.borrow().traps.clone()
}
fn flushes(&self) -> usize {
self.0.borrow().flushes
}
}
struct CaptureHost {
log: Rc<RefCell<CaptureLog>>,
clock_micros: u64,
input: VecDeque<u8>,
}
impl CaptureHost {
fn new() -> (Self, CaptureHandle) {
let log = Rc::new(RefCell::new(CaptureLog::default()));
let handle = CaptureHandle(log.clone());
(
Self {
log,
clock_micros: 0,
input: VecDeque::new(),
},
handle,
)
}
fn with_clock(clock_micros: u64) -> (Self, CaptureHandle) {
let (mut host, handle) = Self::new();
host.clock_micros = clock_micros;
(host, handle)
}
fn queue_input(&mut self, bytes: &[u8]) {
self.input.extend(bytes);
}
}
impl Host for CaptureHost {
fn write(&mut self, fd: u8, bytes: &[u8]) -> std::io::Result<()> {
let mut log = self.log.borrow_mut();
match fd {
1 => log.stdout.extend_from_slice(bytes),
2 => log.stderr.extend_from_slice(bytes),
_ => return Err(std::io::Error::other("CaptureHost: unsupported fd")),
}
Ok(())
}
fn read(&mut self, fd: u8, buf: &mut [u8]) -> std::io::Result<usize> {
if fd != 0 {
return Err(std::io::Error::other("CaptureHost: unsupported fd"));
}
if buf.is_empty() {
return Ok(0);
}
match self.input.pop_front() {
Some(byte) => {
buf[0] = byte;
Ok(1)
}
None => Ok(0),
}
}
fn flush(&mut self) {
self.log.borrow_mut().flushes += 1;
}
fn now_micros(&mut self) -> u64 {
self.clock_micros
}
fn diagnostic(&mut self, msg: &str) {
self.log.borrow_mut().diagnostics.push(msg.to_string());
}
fn trap(&mut self, code: TrapCode, arg: u8, arg255: u64, result255: u64) {
self.log
.borrow_mut()
.traps
.push((code, arg, arg255, result255));
}
}
fn run_to_halt(source: &str) -> u64 {
use crate::debugger::{entry_point, write_image};
use crate::mmixal::MMixAssembler;
let mut asm = MMixAssembler::new(source, "<test>");
asm.parse().expect("program must assemble");
let mut mmix = MMix::new();
write_image(&mut mmix, &asm);
mmix.set_pc(entry_point(&asm));
mmix.run();
mmix.get_register(255)
}
fn load_tetra(mmix: &mut MMix, addr: u64, value: u32) {
for i in 0..4 {
let shift = 24 - 8 * i;
mmix.write_loaded_byte(addr + i as u64, (value >> shift) as u8);
}
}
mod dispatch_arithmetic;
mod dispatch_branches;
mod dispatch_misc;
mod display;
mod exceptions;
mod float;
mod lifecycle;
mod memory;
mod registers;
mod stack;
mod trap;