lemurs-8080 0.5.2

An emulator for the Intel 8080 microprocessor
Documentation
#[cfg(not(test))]
extern crate cpp;

use crate::{prelude::*, Op};

use core::marker::PhantomData;

#[repr(C)]
struct Harness (u8, PhantomData<dyn crate::Harness>);

mod safe {
    use super::*;
    pub (super) enum FreePtr {
        External(*mut Harness),
        Owned(Box<dyn crate::Harness>),
    }
    impl FreePtr {
        pub fn new_unowned(reference: &mut Harness) -> Self {
            Self::External(reference as *mut _)
        }
        pub fn new_owned(container: impl crate::Harness + 'static) -> Self {
            Self::Owned(Box::new(container))
        }
    }
    impl Borrow<dyn crate::Harness> for FreePtr {
        fn borrow(&self) -> &(dyn crate::Harness + 'static) {
            match self {
                Self::External(ptr) => unsafe { &**ptr },
                Self::Owned(ref ptr) => &**ptr,
            }
        }
    }
    impl BorrowMut<dyn crate::Harness> for FreePtr {
        fn borrow_mut(&mut self) -> &mut (dyn crate::Harness + 'static) {
            match self {
                Self::External(ptr) => unsafe { &mut **ptr },
                Self::Owned(ref mut ptr) => &mut **ptr,
            }
        }
    }
}

type Machine = crate::Machine<dyn crate::Harness, safe::FreePtr>;

#[no_mangle]
extern "C" fn create_machine<'a>(board: Option<&mut Harness>) -> *mut Machine {
    Box::into_raw(Box::new(match board {
        Some(ext) => Machine::new(safe::FreePtr::new_unowned(ext)),
        None => Machine::new(safe::FreePtr::new_owned(crate::SimpleBoard::default())),
    }))
}

#[no_mangle]
extern "C" fn request_default_impl(host: &Machine) -> Option<&crate::SimpleBoard> {
    host.as_any()?.downcast_ref()
}

#[no_mangle]
#[cfg(feature="open")]
extern "C" fn machine_state(host: &Machine) -> &State {
    host.as_ref()
}

#[no_mangle]
#[cfg(not(feature="open"))]
extern "C-unwind" fn machine_execute(host: &mut Machine) -> u8 {
    match host.execute() {
        None => 0,
        Some(byte) => byte.get(),
    }
}

#[no_mangle]
#[cfg(feature="open")]
extern "C-unwind" fn machine_execute(host: &mut Machine) -> u8 {
    Wrapping(match host.execute() {
        Ok(None) => 0,
        Ok(Some(byte)) => byte.get(),
        Err(string) => panic!("{string}"),
    })
}

#[no_mangle]
extern "C-unwind" fn machine_interrupt(host:&mut Machine, code: u8) -> bool {
    unsafe { host.interrupt(Op::extract(core::iter::once(code)).expect("not a valid interrupt code.").0).unwrap_unchecked() }
}

#[no_mangle]
extern "C" fn discard_machine(state: *mut Machine) {
    drop(unsafe{Box::from_raw(state)});
}

extern "C-unwind" {
    fn read_harness(host: &Harness, address: u16) -> u8;
    fn read_word_harness(host: &Harness, address: u16) -> u16;
    fn write_harness(host: &mut Harness, address: u16, value: u8);
    fn write_word_harness(host: &mut Harness, address: u16, value: u16);
    fn input_harness(host: &Harness, port: raw::u8) -> u8;
    fn output_harness(host: &mut Harness, port: raw::u8, value: u8);
    #[cfg(feature="open")]
    fn did_execute_harness(host: &mut Harness, chip: &crate::State, op: u32) -> Option<&'static [u8;4]>;
}

impl crate::Harness for Harness {
    fn read(&self, from: u16) -> u8 {
        unsafe { read_harness(self, from) }
    }
    fn read_word(&self, from: u16) -> u16 {
        unsafe { read_word_harness(self, from) }
    }
    fn write(&mut self, to: u16, value: u8) {
        unsafe { write_harness(self, to, value) }
    }
    fn write_word(&mut self, to: u16, value: u16) {
        unsafe { write_word_harness(self, to, value) }
    }
    fn input(&mut self, port: raw::u8) -> u8 {
        unsafe { input_harness(self, port) }
    }
    fn output(&mut self, port: raw::u8, value: u8) {
        unsafe { output_harness(self, port, value) }
    }
    #[cfg(feature="open")]
    fn did_execute(&mut self, client: &crate::State, did: Op) -> Result<Option<Op>, String> {
        use core::{mem::transmute, ffi::CStr};
        unsafe {
            match did_execute_harness(self, client, u32::from_be_bytes(did.into())) {
                None => Ok(None),
                Some(code@&[Wrapping(0), ..]) => Ok(Some(Op::extract(code[1..].iter().copied()).or(Err(String::from("Not a valid opcode")))?.0)),
                Some(bytes) => Err(CStr::from_ptr(transmute(bytes)).to_string_lossy().into_owned()),
            }
        }
    }
}