lemurs-8080 0.5.2

An emulator for the Intel 8080 microprocessor
Documentation
use lemurs_8080::{prelude::*, Op};
use std::collections::HashSet;

#[allow(non_camel_case_types)]
pub struct CP_M {
    dead: u8,
    ram: [u8;0x10000],
    port: [u8;256],
    history: std::collections::HashSet<Wrapping<u16>>,
    order: Vec<Wrapping<u16>>,
}

impl CP_M {
    pub fn with_program(mut code: &[u8]) -> Self {
        let mut new = Self {
            dead: 0,
            ram: [0;_],
            port: [0;_],
            history: HashSet::new(),
            order: vec!()
        };
        [new.ram[0], new.ram[1], new.ram[2]] = [0xC3, 0x00, 0x01];
        let mut ram = &mut new.ram[0x100..];
        if ram.len() > code.len() { ram = &mut ram[..code.len()]; }
        if code.len() > ram.len() { code = &code[..ram.len()]; }
        ram.copy_from_slice(code);
        new
    }
}

impl Index<u16> for CP_M {
    type Output = u8;
    fn index(&self, index: u16) -> &Self::Output { &self.ram[index as usize] }
}

impl IndexMut<u16> for CP_M {
    fn index_mut(&mut self, index: u16) -> &mut Self::Output {
        match index {
            0..=0x00FF => { self.dead = 0; &mut self.dead },
            i@0x0100.. => &mut self.ram[i as usize],
        }
    }
}

impl Deref for CP_M {
    type Target = [u8];
    fn deref(&self) -> &Self::Target { &self.ram[..] }
}

impl Harness for CP_M {
    fn read(&self, from: Wrapping<u16>) -> Wrapping<u8> { Wrapping(self.ram[from.0 as usize]) }
    fn write(&mut self, to: Wrapping<u16>, value: Wrapping<u8>) { if (0x100..).contains(&to.0) { self.ram[to.0 as usize] = value.0; } }
    fn input(&mut self, port: u8) -> Wrapping<u8> { Wrapping(self.port[port as usize]) }
    fn output(&mut self, port: u8, value: Wrapping<u8>) { self.port[port as usize] = value.0; }
    fn did_execute(&mut self, client: &lemurs_8080::State, _did: Op) -> Result<Option<Op>, String> {
        use lemurs_8080::{Double, Register};
        self.order.push(client.pc);
        if client.pc.0 >= 0x01AB && self.history.contains(&client.pc) {
            eprintln!("\n{:?}", self.order);
            return Err(format!("Repeated instruction at {:#06X}", client.pc));
        } else {
            self.history.insert(client.pc);
        }
        match client.pc.0 {
            0 => {
                print!("\n");
                return (self.dead == 0).then_some(Some(Op::Halt)).ok_or(String::from("Failed tests"));
            }
            5 => { 
                let offset = client[Double::DE].0;
                match client[Register::C].0 {
                    2 => print!("{}", client[Register::E].0 as char),
                    9 => {
                        let text = &self.ram[offset as usize..];
                        if let Some(text) = text.splitn(2, |c| *c == '$' as u8).next() {
                            if let Ok(text) = std::str::from_utf8(text) {
                                print!("{text}");
                            };
                        };
                    }
                    _ => (), 
                };
                return Ok(Some(Op::Return));
            }
            0x0689 => {
                let from = u16::from_le_bytes([self[client.sp.0], self[client.sp.0 + 1]]) - 3;
                self.dead = true as u8;
                eprintln!("Entered CPU Error routine from {from:#06X}");
                let (a, cy, _ac, pe, m, z) = (client.register[6], client.c as u8, client.a as u8, client.p as u8, client.m as u8, client.z as u8);
                eprintln!("a={a:02X}H,C={cy},P={pe},S={m},Z={z}");
            }
            _ => (),
        };
        Ok ( None )
    }
}