diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.toml | 10 | ||||
| -rw-r--r-- | src/device_bus.rs | 19 | ||||
| -rw-r--r-- | src/lib.rs | 16 | ||||
| -rw-r--r-- | src/memory.rs | 62 | ||||
| -rw-r--r-- | src/processor.rs | 326 | ||||
| -rw-r--r-- | src/stack.rs | 40 | 
7 files changed, 475 insertions, 0 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c7349e6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bedrock_core" +version = "1.0.0" +authors = ["Ben Bridle"] +edition = "2021" +description = "Create Bedrock virtual processors and evaluate Bedrock bytecode" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/device_bus.rs b/src/device_bus.rs new file mode 100644 index 0000000..38a1a24 --- /dev/null +++ b/src/device_bus.rs @@ -0,0 +1,19 @@ +use crate::*; + +pub trait DeviceBus { +    fn read_u8(&mut self, port: u8) -> u8; + +    fn write_u8(&mut self, value: u8, port: u8) -> Option<Signal>; + +    fn read_u16(&mut self, port: u8) -> u16 { +        let high = self.read_u8(port); +        let low = self.read_u8(port.wrapping_add(1)); +        u16::from_be_bytes([high, low]) +    } + +    fn write_u16(&mut self, value: u16, port: u8) -> Option<Signal> { +        let [h, l] = value.to_be_bytes(); +        self.write_u8(h, port); +        self.write_u8(l, port.wrapping_add(1)) +    } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f04b18d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,16 @@ +mod device_bus; +mod memory; +mod processor; +mod stack; + +pub use device_bus::*; +pub use memory::*; +pub use processor::*; +pub use stack::*; + +#[derive(Copy, Clone, Debug)] +pub enum Signal { +    Debug, +    Pause, +    Halt, +} diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 0000000..755c4bc --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,62 @@ +pub struct Memory { +    pub mem: [u8; 65536], +    pub pc: u16, +} + +impl Memory { +    pub fn new() -> Self { +        Self { +            mem: [0; 65536], +            pc: 0, +        } +    } + +    pub fn load_program(&mut self, bytecode: &[u8]) { +        self.mem[..bytecode.len()].copy_from_slice(bytecode) +    } + +    pub fn read_u8(&self, addr: u16) -> u8 { +        self.mem[addr as usize] +    } + +    pub fn write_u8(&mut self, val: u8, addr: u16) { +        self.mem[addr as usize] = val; +    } + +    pub fn read_u8_next(&mut self) -> u8 { +        let byte = self.mem[self.pc as usize]; +        self.pc = self.pc.wrapping_add(1); +        byte +    } + +    pub fn read_u16(&self, addr: u16) -> u16 { +        let byte_high = self.read_u8(addr); +        let byte_low = self.read_u8(addr.wrapping_add(1)); +        u16::from_be_bytes([byte_high, byte_low]) +    } + +    pub fn write_u16(&mut self, val: u16, addr: u16) { +        let [byte_high, byte_low] = val.to_be_bytes(); +        self.write_u8(byte_high, addr); +        self.write_u8(byte_low, addr.wrapping_add(1)); +    } + +    pub fn read_u16_next(&mut self) -> u16 { +        let byte_high = self.read_u8_next(); +        let byte_low = self.read_u8_next(); +        u16::from_be_bytes([byte_high, byte_low]) +    } + +    pub fn read_pc(&self) -> u16 { +        self.pc +    } + +    pub fn write_pc(&mut self, val: u16) { +        self.pc = val; +    } + +    pub fn reset(&mut self) { +        self.mem.fill(0); +        self.pc = 0; +    } +} diff --git a/src/processor.rs b/src/processor.rs new file mode 100644 index 0000000..fc1cfa4 --- /dev/null +++ b/src/processor.rs @@ -0,0 +1,326 @@ +use crate::*; +use std::ops::*; + +pub struct Processor<D> { +    pub mem: Memory, +    pub wst: Stack, +    pub rst: Stack, +    pub dev: D, +    pub cycles: usize, +} + +impl<D: DeviceBus> Processor<D> { +    pub fn new(device_bus: D) -> Self { +        Self { +            mem: Memory::new(), +            wst: Stack::new(), +            rst: Stack::new(), +            dev: device_bus, +            cycles: 0, +        } +    } + +    pub fn load_program(&mut self, bytecode: &[u8]) { +        self.mem.load_program(bytecode); +    } + +    pub fn evaluate(&mut self, num_cycles: usize) -> Option<Signal> { +        macro_rules! w_psh_8    { ($v:expr) => { self.wst.push_u8($v);  }; } +        macro_rules! r_psh_8    { ($v:expr) => { self.rst.push_u8($v);  }; } +        macro_rules! w_psh_16   { ($v:expr) => { self.wst.push_u16($v); }; } +        macro_rules! r_psh_16   { ($v:expr) => { self.rst.push_u16($v); }; } +        macro_rules! w_pop_8    { ($v:ident) => { let $v = self.wst.pop_u8();  }; } +        macro_rules! r_pop_8    { ($v:ident) => { let $v = self.rst.pop_u8();  }; } +        macro_rules! w_pop_16   { ($v:ident) => { let $v = self.wst.pop_u16(); }; } +        macro_rules! r_pop_16   { ($v:ident) => { let $v = self.rst.pop_u16(); }; } +        macro_rules! m_read_8   { ($a:expr) => { self.mem.read_u8($a)  }; } +        macro_rules! m_read_16  { ($a:expr) => { self.mem.read_u16($a) }; } +        macro_rules! m_lit_8    { ($l:ident) => { let $l = self.mem.read_u8_next();  }; } +        macro_rules! m_lit_16   { ($l:ident) => { let $l = self.mem.read_u16_next(); }; } +        macro_rules! m_write_8  { ($v:expr,$a:expr) => { self.mem.write_u8($v,$a);  }; } +        macro_rules! m_write_16 { ($v:expr,$a:expr) => { self.mem.write_u16($v,$a); }; } +        macro_rules! d_read_8   { ($p:expr) => { self.dev.read_u8($p)  }; } +        macro_rules! d_read_16  { ($p:expr) => { self.dev.read_u16($p) }; } +        macro_rules! d_write_8  { ($v:expr,$p:expr) => { let s = self.dev.write_u8( $v, $p); if s.is_some() { return s }; }; } +        macro_rules! d_write_16 { ($v:expr,$p:expr) => { let s = self.dev.write_u16($v, $p); if s.is_some() { return s }; }; } +        macro_rules! jump       { ($a:expr) => { self.mem.write_pc($a) }; } +        macro_rules! pc         { ()        => { self.mem.read_pc()    }; } +        macro_rules! truth      { ($x:expr) => { if $x {0xff} else {0x00} }; } +        macro_rules! nyb        { ($v:expr=>$h:ident,$l:ident) => { let $h=($v>>4) as u32; let $l=($v&0x0f) as u32; } } +        macro_rules! shf        { ($x:expr,$y:expr) => { { nyb!($y=>l,r); $x.wrapping_shl(l).wrapping_shr(r) } } ; } +        macro_rules! shc        { ($x:expr,$y:expr) => { { nyb!($y=>l,r); $x.rotate_left(l).rotate_right(r) } }; } + +        for _ in 0..num_cycles { +            self.cycles += 1; + +            match self.mem.read_u8_next() { +                /* HLT    */ 0x00 => { return Some(Signal::Halt); } +                /* JMP    */ 0x01 => { w_pop_16!(a);                                    jump!(a);  } +                /* JCN    */ 0x02 => { w_pop_16!(a); w_pop_8!(t);              if t!=0 {jump!(a)}; } +                /* JKN    */ 0x03 => { w_pop_16!(a); w_pop_8!(t); w_psh_8!(t); if t!=0 {jump!(a)}; } +                /* EQU    */ 0x04 => { w_pop_8!(y); w_pop_8!(x);                           w_psh_8!(truth!(x==y)); } +                /* NKQ    */ 0x05 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x); w_psh_8!(y); w_psh_8!(truth!(x!=y)); } +                /* LTH    */ 0x06 => { w_pop_8!(y); w_pop_8!(x);                           w_psh_8!(truth!(x <y)); } +                /* GTH    */ 0x07 => { w_pop_8!(y); w_pop_8!(x);                           w_psh_8!(truth!(x >y)); } +                /* LDA    */ 0x08 => { w_pop_16!(a);               w_psh_8!(m_read_8!(a)); } +                /* LKA    */ 0x09 => { w_pop_16!(a); w_psh_16!(a); w_psh_8!(m_read_8!(a)); } +                /* STA    */ 0x0A => { w_pop_16!(a); w_pop_8!(v);               m_write_8!(v,a); } +                /* SKA    */ 0x0B => { w_pop_8!(v); w_pop_16!(a); w_psh_16!(a); m_write_8!(v,a); } +                /* LDD    */ 0x0C => { w_pop_8!(p);              w_psh_8!(d_read_8!(p)); }, +                /* LKD    */ 0x0D => { w_pop_8!(p); w_psh_8!(p); w_psh_8!(d_read_8!(p)); }, +                /* STD    */ 0x0E => { w_pop_8!(p); w_pop_8!(v);              d_write_8!(v,p); }, +                /* SKD    */ 0x0F => { w_pop_8!(p); w_pop_8!(v); w_psh_8!(v); d_write_8!(v,p); }, +                /* PSH    */ 0x10 => { r_pop_8!(x); w_psh_8!(x); }, +                /* POP    */ 0x11 => { w_pop_8!(_x); }, +                /* SHF    */ 0x12 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(shf!(x,y)); }, +                /* SHC    */ 0x13 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(shc!(x,y)); }, +                /* SWP    */ 0x14 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(y); w_psh_8!(x); }, +                /* ROT    */ 0x15 => { w_pop_8!(z); w_pop_8!(y); w_pop_8!(x); w_psh_8!(y); w_psh_8!(z); w_psh_8!(x); }, +                /* DUP    */ 0x16 => { w_pop_8!(x); w_psh_8!(x); w_psh_8!(x); }, +                /* OVR    */ 0x17 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x); w_psh_8!(y); w_psh_8!(x); }, +                /* ADD    */ 0x18 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x.wrapping_add(y)); }, +                /* SUB    */ 0x19 => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x.wrapping_sub(y)); }, +                /* INC    */ 0x1A => { w_pop_8!(x); w_psh_8!(x.wrapping_add(1)); }, +                /* DEC    */ 0x1B => { w_pop_8!(x); w_psh_8!(x.wrapping_sub(1)); }, +                /* NOT    */ 0x1C => { w_pop_8!(x); w_psh_8!(x.not()); }, +                /* AND    */ 0x1D => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x.bitand(y)); }, +                /* IOR    */ 0x1E => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x.bitor(y)); }, +                /* XOR    */ 0x1F => { w_pop_8!(y); w_pop_8!(x); w_psh_8!(x.bitxor(y)); }, + +                /* DBG    */ 0x20 => { return Some(Signal::Debug); } +                /* JSR    */ 0x21 => { w_pop_16!(a);                        r_psh_16!(pc!()); jump!(a);  } +                /* JSN    */ 0x22 => { w_pop_16!(a);  w_pop_8!(t); if t!=0 {r_psh_16!(pc!()); jump!(a)}; } +                /* JKN*   */ 0x23 => { w_pop_16!(a); w_pop_16!(t); w_psh_16!(t);     if t!=0 {jump!(a)}; } +                /* EQU*   */ 0x24 => { w_pop_16!(y); w_pop_16!(x);                             w_psh_8!(truth!(x==y)); } +                /* NKQ*   */ 0x25 => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x); w_psh_16!(y); w_psh_8!(truth!(x!=y)); } +                /* LTH*   */ 0x26 => { w_pop_16!(y); w_pop_16!(x);                             w_psh_8!(truth!(x <y)); } +                /* GTH*   */ 0x27 => { w_pop_16!(y); w_pop_16!(x);                             w_psh_8!(truth!(x >y)); } +                /* LDA*   */ 0x28 => { w_pop_16!(a);               w_psh_16!(m_read_16!(a)); } +                /* LKA*   */ 0x29 => { w_pop_16!(a); w_psh_16!(a); w_psh_16!(m_read_16!(a)); } +                /* STA*   */ 0x2A => { w_pop_16!(a); w_pop_16!(v);               m_write_16!(v,a); } +                /* SKA*   */ 0x2B => { w_pop_16!(v); w_pop_16!(a); w_psh_16!(a); m_write_16!(v,a); } +                /* LDD*   */ 0x2C => { w_pop_8!(p);              w_psh_16!(d_read_16!(p)); }, +                /* LKD*   */ 0x2D => { w_pop_8!(p); w_psh_8!(p); w_psh_16!(d_read_16!(p)); }, +                /* STD*   */ 0x2E => { w_pop_8!(p); w_pop_16!(v);               d_write_16!(v,p); }, +                /* SKD*   */ 0x2F => { w_pop_8!(p); w_pop_16!(v); w_psh_16!(v); d_write_16!(v,p); }, +                /* PSH*   */ 0x30 => { r_pop_16!(x); w_psh_16!(x); }, +                /* POP*   */ 0x31 => { w_pop_16!(_x); }, +                /* SHF*   */ 0x32 => { w_pop_8!(y); w_pop_16!(x); w_psh_16!(shf!(x,y)); }, +                /* SHC*   */ 0x33 => { w_pop_8!(y); w_pop_16!(x); w_psh_16!(shc!(x,y)); }, +                /* SWP*   */ 0x34 => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(y); w_psh_16!(x); }, +                /* ROT*   */ 0x35 => { w_pop_16!(z); w_pop_16!(y); w_pop_16!(x); w_psh_16!(y); w_psh_16!(z); w_psh_16!(x); }, +                /* DUP*   */ 0x36 => { w_pop_16!(x); w_psh_16!(x); w_psh_16!(x); }, +                /* OVR*   */ 0x37 => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x); w_psh_16!(y); w_psh_16!(x); }, +                /* ADD*   */ 0x38 => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x.wrapping_add(y)); }, +                /* SUB*   */ 0x39 => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x.wrapping_sub(y)); }, +                /* INC*   */ 0x3A => { w_pop_16!(x); w_psh_16!(x.wrapping_add(1)); }, +                /* DEC*   */ 0x3B => { w_pop_16!(x); w_psh_16!(x.wrapping_sub(1)); }, +                /* NOT*   */ 0x3C => { w_pop_16!(x); w_psh_16!(x.not()); }, +                /* AND*   */ 0x3D => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x.bitand(y)); }, +                /* IOR*   */ 0x3E => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x.bitor(y)); }, +                /* XOR*   */ 0x3F => { w_pop_16!(y); w_pop_16!(x); w_psh_16!(x.bitxor(y)); }, + +                /* --     */ 0x40 => { } +                /* JMP:   */ 0x41 => { m_lit_16!(a);                                   jump!(a);  } +                /* JCN:   */ 0x42 => { m_lit_16!(a); w_pop_8!(t);              if t!=0{jump!(a)}; } +                /* JKN:   */ 0x43 => { m_lit_16!(a); w_pop_8!(t); w_psh_8!(t); if t!=0{jump!(a)}; } +                /* EQU:   */ 0x44 => { m_lit_8!(y); w_pop_8!(x);                           w_psh_8!(truth!(x==y)); } +                /* NKQ:   */ 0x45 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x); w_psh_8!(y); w_psh_8!(truth!(x!=y)); } +                /* LTH:   */ 0x46 => { m_lit_8!(y); w_pop_8!(x);                           w_psh_8!(truth!(x <y)); } +                /* GTH:   */ 0x47 => { m_lit_8!(y); w_pop_8!(x);                           w_psh_8!(truth!(x >y)); } +                /* LDA:   */ 0x48 => { m_lit_16!(a);               w_psh_8!(m_read_8!(a)); } +                /* LKA:   */ 0x49 => { m_lit_16!(a); w_psh_16!(a); w_psh_8!(m_read_8!(a)); } +                /* STA:   */ 0x4A => { m_lit_16!(a); w_pop_8!(v);               m_write_8!(v,a); } +                /* SKA:   */ 0x4B => { m_lit_8!(v); w_pop_16!(a); w_psh_16!(a); m_write_8!(v,a); } +                /* LDD:   */ 0x4C => { m_lit_8!(p);              w_psh_8!(d_read_8!(p)); }, +                /* LKD:   */ 0x4D => { m_lit_8!(p); w_psh_8!(p); w_psh_8!(d_read_8!(p)); }, +                /* STD:   */ 0x4E => { m_lit_8!(p); w_pop_8!(v);              d_write_8!(v,p); }, +                /* SKD:   */ 0x4F => { m_lit_8!(p); w_pop_8!(v); w_psh_8!(v); d_write_8!(v,p); }, +                /* PSH:   */ 0x50 => { m_lit_8!(x); w_psh_8!(x); }, +                /* POP:   */ 0x51 => { m_lit_8!(_x); }, +                /* SHF:   */ 0x52 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(shf!(x,y)); }, +                /* SHC:   */ 0x53 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(shc!(x,y)); }, +                /* SWP:   */ 0x54 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(y); w_psh_8!(x); }, +                /* ROT:   */ 0x55 => { m_lit_8!(z); w_pop_8!(y); w_pop_8!(x); w_psh_8!(y); w_psh_8!(z); w_psh_8!(x); }, +                /* DUP:   */ 0x56 => { m_lit_8!(x); w_psh_8!(x); w_psh_8!(x); }, +                /* OVR:   */ 0x57 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x); w_psh_8!(y); w_psh_8!(x); }, +                /* ADD:   */ 0x58 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x.wrapping_add(y)); }, +                /* SUB:   */ 0x59 => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x.wrapping_sub(y)); }, +                /* INC:   */ 0x5A => { m_lit_8!(x); w_psh_8!(x.wrapping_add(1)); }, +                /* DEC:   */ 0x5B => { m_lit_8!(x); w_psh_8!(x.wrapping_sub(1)); }, +                /* NOT:   */ 0x5C => { m_lit_8!(x); w_psh_8!(x.not()); }, +                /* AND:   */ 0x5D => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x.bitand(y)); }, +                /* IOR:   */ 0x5E => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x.bitor(y)); }, +                /* XOR:   */ 0x5F => { m_lit_8!(y); w_pop_8!(x); w_psh_8!(x.bitxor(y)); }, + +                /* --     */ 0x60 => { } +                /* JSR:   */ 0x61 => { m_lit_16!(a);                        r_psh_16!(pc!()); jump!(a);  } +                /* JSN:   */ 0x62 => { m_lit_16!(a);  w_pop_8!(t); if t!=0 {r_psh_16!(pc!()); jump!(a)}; } +                /* JKN*:  */ 0x63 => { m_lit_16!(a); w_pop_16!(t); w_psh_16!(t);     if t!=0 {jump!(a)}; } +                /* EQU*:  */ 0x64 => { m_lit_16!(y); w_pop_16!(x);                             w_psh_8!(truth!(x==y)); } +                /* NKQ*:  */ 0x65 => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x); w_psh_16!(y); w_psh_8!(truth!(x!=y)); } +                /* LTH*:  */ 0x66 => { m_lit_16!(y); w_pop_16!(x);                             w_psh_8!(truth!(x <y)); } +                /* GTH*:  */ 0x67 => { m_lit_16!(y); w_pop_16!(x);                             w_psh_8!(truth!(x >y)); } +                /* LDA*:  */ 0x68 => { m_lit_16!(a);               w_psh_16!(m_read_16!(a)); } +                /* LKA*:  */ 0x69 => { m_lit_16!(a); w_psh_16!(a); w_psh_16!(m_read_16!(a)); } +                /* STA*:  */ 0x6A => { m_lit_16!(a); w_pop_16!(v);               m_write_16!(v,a); } +                /* SKA*:  */ 0x6B => { m_lit_16!(v); w_pop_16!(a); w_psh_16!(a); m_write_16!(v,a); } +                /* LDD*:  */ 0x6C => { m_lit_8!(p);              w_psh_16!(d_read_16!(p)); }, +                /* LKD*:  */ 0x6D => { m_lit_8!(p); w_psh_8!(p); w_psh_16!(d_read_16!(p)); }, +                /* STD*:  */ 0x6E => { m_lit_8!(p); w_pop_16!(v);               d_write_16!(v,p); }, +                /* SKD*:  */ 0x6F => { m_lit_8!(p); w_pop_16!(v); w_psh_16!(v); d_write_16!(v,p); }, +                /* PSH*:  */ 0x70 => { m_lit_16!(x); w_psh_16!(x); }, +                /* POP*:  */ 0x71 => { m_lit_16!(_x); }, +                /* SHF*:  */ 0x72 => { m_lit_8!(y); w_pop_16!(x); w_psh_16!(shf!(x,y)); }, +                /* SHC*:  */ 0x73 => { m_lit_8!(y); w_pop_16!(x); w_psh_16!(shc!(x,y)); }, +                /* SWP*:  */ 0x74 => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(y); w_psh_16!(x); }, +                /* ROT*:  */ 0x75 => { m_lit_16!(z); w_pop_16!(y); w_pop_16!(x); w_psh_16!(y); w_psh_16!(z); w_psh_16!(x); }, +                /* DUP*:  */ 0x76 => { m_lit_16!(x); w_psh_16!(x); w_psh_16!(x); }, +                /* OVR*:  */ 0x77 => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x); w_psh_16!(y); w_psh_16!(x); }, +                /* ADD*:  */ 0x78 => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x.wrapping_add(y)); }, +                /* SUB*:  */ 0x79 => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x.wrapping_sub(y)); }, +                /* INC*:  */ 0x7A => { m_lit_16!(x); w_psh_16!(x.wrapping_add(1)); }, +                /* DEC*:  */ 0x7B => { m_lit_16!(x); w_psh_16!(x.wrapping_sub(1)); }, +                /* NOT*:  */ 0x7C => { m_lit_16!(x); w_psh_16!(x.not()); }, +                /* AND*:  */ 0x7D => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x.bitand(y)); }, +                /* IOR*:  */ 0x7E => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x.bitor(y)); }, +                /* XOR*:  */ 0x7F => { m_lit_16!(y); w_pop_16!(x); w_psh_16!(x.bitxor(y)); }, + +                /* --     */ 0x80 => { } +                /* JMPr   */ 0x81 => { r_pop_16!(a);                                   jump!(a);  } +                /* JCNr   */ 0x82 => { r_pop_16!(a); r_pop_8!(t);              if t!=0{jump!(a)}; } +                /* JKNr   */ 0x83 => { r_pop_16!(a); r_pop_8!(t); r_psh_8!(t); if t!=0{jump!(a)}; } +                /* EQUr   */ 0x84 => { r_pop_8!(y); r_pop_8!(x);                           r_psh_8!(truth!(x==y)); } +                /* NKQr   */ 0x85 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x); r_psh_8!(y); r_psh_8!(truth!(x!=y)); } +                /* LTHr   */ 0x86 => { r_pop_8!(y); r_pop_8!(x);                           r_psh_8!(truth!(x <y)); } +                /* GTHr   */ 0x87 => { r_pop_8!(y); r_pop_8!(x);                           r_psh_8!(truth!(x >y)); } +                /* LDAr   */ 0x88 => { r_pop_16!(a);               r_psh_8!(m_read_8!(a)); } +                /* LKAr   */ 0x89 => { r_pop_16!(a); r_psh_16!(a); r_psh_8!(m_read_8!(a)); } +                /* STAr   */ 0x8A => { r_pop_16!(a); r_pop_8!(v);               m_write_8!(v,a); } +                /* SKAr   */ 0x8B => { r_pop_8!(v); r_pop_16!(a); r_psh_16!(a); m_write_8!(v,a); } +                /* LDDr   */ 0x8C => { r_pop_8!(p);              r_psh_8!(d_read_8!(p)); }, +                /* LKDr   */ 0x8D => { r_pop_8!(p); r_psh_8!(p); r_psh_8!(d_read_8!(p)); }, +                /* STDr   */ 0x8E => { r_pop_8!(p); r_pop_8!(v);              d_write_8!(v,p); }, +                /* SKDr   */ 0x8F => { r_pop_8!(p); r_pop_8!(v); r_psh_8!(v); d_write_8!(v,p); }, +                /* PSHr   */ 0x90 => { w_pop_8!(x); r_psh_8!(x); }, +                /* POPr   */ 0x91 => { r_pop_8!(_x); }, +                /* SHFr   */ 0x92 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(shf!(x,y)); }, +                /* SHCr   */ 0x93 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(shc!(x,y)); }, +                /* SWPr   */ 0x94 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(y); r_psh_8!(x); }, +                /* ROTr   */ 0x95 => { r_pop_8!(z); r_pop_8!(y); r_pop_8!(x); r_psh_8!(y); r_psh_8!(z); r_psh_8!(x); }, +                /* DUPr   */ 0x96 => { r_pop_8!(x); r_psh_8!(x); r_psh_8!(x); }, +                /* OVRr   */ 0x97 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x); r_psh_8!(y); r_psh_8!(x); }, +                /* ADDr   */ 0x98 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x.wrapping_add(y)); }, +                /* SUBr   */ 0x99 => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x.wrapping_sub(y)); }, +                /* INCr   */ 0x9A => { r_pop_8!(x); r_psh_8!(x.wrapping_add(1)); }, +                /* DECr   */ 0x9B => { r_pop_8!(x); r_psh_8!(x.wrapping_sub(1)); }, +                /* NOTr   */ 0x9C => { r_pop_8!(x); r_psh_8!(x.not()); }, +                /* ANDr   */ 0x9D => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x.bitand(y)); }, +                /* IORr   */ 0x9E => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x.bitor(y)); }, +                /* XORr   */ 0x9F => { r_pop_8!(y); r_pop_8!(x); r_psh_8!(x.bitxor(y)); }, + + +                /* --     */ 0xA0 => { } +                /* JSRr   */ 0xA1 => { r_pop_16!(a);                        w_psh_16!(pc!()); jump!(a);  } +                /* JSNr   */ 0xA2 => { r_pop_16!(a);  r_pop_8!(t); if t!=0 {w_psh_16!(pc!()); jump!(a)}; } +                /* JKNr*  */ 0xA3 => { r_pop_16!(a); r_pop_16!(t); r_psh_16!(t);     if t!=0 {jump!(a)}; } +                /* EQUr*  */ 0xA4 => { r_pop_16!(y); r_pop_16!(x);                             r_psh_8!(truth!(x==y)); } +                /* NKQr*  */ 0xA5 => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x); r_psh_16!(y); r_psh_8!(truth!(x!=y)); } +                /* LTHr*  */ 0xA6 => { r_pop_16!(y); r_pop_16!(x);                             r_psh_8!(truth!(x <y)); } +                /* GTHr*  */ 0xA7 => { r_pop_16!(y); r_pop_16!(x);                             r_psh_8!(truth!(x >y)); } +                /* LDAr*  */ 0xA8 => { r_pop_16!(a);               r_psh_16!(m_read_16!(a)); } +                /* LKAr*  */ 0xA9 => { r_pop_16!(a); r_psh_16!(a); r_psh_16!(m_read_16!(a)); } +                /* STAr*  */ 0xAA => { r_pop_16!(a); r_pop_16!(v);               m_write_16!(v,a); } +                /* SKAr*  */ 0xAB => { r_pop_16!(v); r_pop_16!(a); r_psh_16!(a); m_write_16!(v,a); } +                /* LDDr*  */ 0xAC => { r_pop_8!(p);              r_psh_16!(d_read_16!(p)); }, +                /* LKDr*  */ 0xAD => { r_pop_8!(p); r_psh_8!(p); r_psh_16!(d_read_16!(p)); }, +                /* STDr*  */ 0xAE => { r_pop_8!(p); r_pop_16!(v);               d_write_16!(v,p); }, +                /* SKDr*  */ 0xAF => { r_pop_8!(p); r_pop_16!(v); r_psh_16!(v); d_write_16!(v,p); }, +                /* PSHr*  */ 0xB0 => { w_pop_16!(x); r_psh_16!(x); }, +                /* POPr*  */ 0xB1 => { r_pop_16!(_x); }, +                /* SHFr*  */ 0xB2 => { r_pop_8!(y); r_pop_16!(x); r_psh_16!(shf!(x,y)); }, +                /* SHCr*  */ 0xB3 => { r_pop_8!(y); r_pop_16!(x); r_psh_16!(shc!(x,y)); }, +                /* SWPr*  */ 0xB4 => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(y); r_psh_16!(x); }, +                /* ROTr*  */ 0xB5 => { r_pop_16!(z); r_pop_16!(y); r_pop_16!(x); r_psh_16!(y); r_psh_16!(z); r_psh_16!(x); }, +                /* DUPr*  */ 0xB6 => { r_pop_16!(x); r_psh_16!(x); r_psh_16!(x); }, +                /* OVRr*  */ 0xB7 => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x); r_psh_16!(y); r_psh_16!(x); }, +                /* ADDr*  */ 0xB8 => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x.wrapping_add(y)); }, +                /* SUBr*  */ 0xB9 => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x.wrapping_sub(y)); }, +                /* INCr*  */ 0xBA => { r_pop_16!(x); r_psh_16!(x.wrapping_add(1)); }, +                /* DECr*  */ 0xBB => { r_pop_16!(x); r_psh_16!(x.wrapping_sub(1)); }, +                /* NOTr*  */ 0xBC => { r_pop_16!(x); r_psh_16!(x.not()); }, +                /* ANDr*  */ 0xBD => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x.bitand(y)); }, +                /* IORr*  */ 0xBE => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x.bitor(y)); }, +                /* XORr*  */ 0xBF => { r_pop_16!(y); r_pop_16!(x); r_psh_16!(x.bitxor(y)); }, + +                /* --     */ 0xC0 => { } +                /* JMPr:  */ 0xC1 => { m_lit_16!(a);                                   jump!(a);  } +                /* JCNr:  */ 0xC2 => { m_lit_16!(a); r_pop_8!(t);              if t!=0{jump!(a)}; } +                /* JKNr:  */ 0xC3 => { m_lit_16!(a); r_pop_8!(t); r_psh_8!(t); if t!=0{jump!(a)}; } +                /* EQUr:  */ 0xC4 => { m_lit_8!(y); r_pop_8!(x);                           r_psh_8!(truth!(x==y)); } +                /* NKQr:  */ 0xC5 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x); r_psh_8!(y); r_psh_8!(truth!(x!=y)); } +                /* LTHr:  */ 0xC6 => { m_lit_8!(y); r_pop_8!(x);                           r_psh_8!(truth!(x <y)); } +                /* GTHr:  */ 0xC7 => { m_lit_8!(y); r_pop_8!(x);                           r_psh_8!(truth!(x >y)); } +                /* LDAr:  */ 0xC8 => { m_lit_16!(a);               r_psh_8!(m_read_8!(a)); } +                /* LKAr:  */ 0xC9 => { m_lit_16!(a); r_psh_16!(a); r_psh_8!(m_read_8!(a)); } +                /* STAr:  */ 0xCA => { m_lit_16!(a); r_pop_8!(v);               m_write_8!(v,a); } +                /* SKAr:  */ 0xCB => { m_lit_8!(v); r_pop_16!(a); r_psh_16!(a); m_write_8!(v,a); } +                /* LDDr:  */ 0xCC => { m_lit_8!(p);              r_psh_8!(d_read_8!(p)); }, +                /* LKDr:  */ 0xCD => { m_lit_8!(p); r_psh_8!(p); r_psh_8!(d_read_8!(p)); }, +                /* STDr:  */ 0xCE => { m_lit_8!(p); r_pop_8!(v);              d_write_8!(v,p); }, +                /* SKDr:  */ 0xCF => { m_lit_8!(p); r_pop_8!(v); r_psh_8!(v); d_write_8!(v,p); }, +                /* PSHr:  */ 0xD0 => { m_lit_8!(x); r_psh_8!(x); }, +                /* POPr:  */ 0xD1 => { m_lit_8!(_x); }, +                /* SHFr:  */ 0xD2 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(shf!(x,y)); }, +                /* SHCr:  */ 0xD3 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(shc!(x,y)); }, +                /* SWPr:  */ 0xD4 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(y); r_psh_8!(x); }, +                /* ROTr:  */ 0xD5 => { m_lit_8!(z); r_pop_8!(y); r_pop_8!(x); r_psh_8!(y); r_psh_8!(z); r_psh_8!(x); }, +                /* DUPr:  */ 0xD6 => { m_lit_8!(x); r_psh_8!(x); r_psh_8!(x); }, +                /* OVRr:  */ 0xD7 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x); r_psh_8!(y); r_psh_8!(x); }, +                /* ADDr:  */ 0xD8 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x.wrapping_add(y)); }, +                /* SUBr:  */ 0xD9 => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x.wrapping_sub(y)); }, +                /* INCr:  */ 0xDA => { m_lit_8!(x); r_psh_8!(x.wrapping_add(1)); }, +                /* DECr:  */ 0xDB => { m_lit_8!(x); r_psh_8!(x.wrapping_sub(1)); }, +                /* NOTr:  */ 0xDC => { m_lit_8!(x); r_psh_8!(x.not()); }, +                /* ANDr:  */ 0xDD => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x.bitand(y)); }, +                /* IORr:  */ 0xDE => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x.bitor(y)); }, +                /* XORr:  */ 0xDF => { m_lit_8!(y); r_pop_8!(x); r_psh_8!(x.bitxor(y)); }, + +                /* NOP    */ 0xE0 => { } +                /* JSRr:  */ 0xE1 => { m_lit_16!(a);                        w_psh_16!(pc!()); jump!(a);  } +                /* JSNr:  */ 0xE2 => { m_lit_16!(a);  r_pop_8!(t); if t!=0 {w_psh_16!(pc!()); jump!(a)}; } +                /* JKNr*: */ 0xE3 => { m_lit_16!(a); r_pop_16!(t); r_psh_16!(t);     if t!=0 {jump!(a)}; } +                /* EQUr*: */ 0xE4 => { m_lit_16!(y); r_pop_16!(x);                             r_psh_8!(truth!(x==y)); } +                /* NKQr*: */ 0xE5 => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x); r_psh_16!(y); r_psh_8!(truth!(x!=y)); } +                /* LTHr*: */ 0xE6 => { m_lit_16!(y); r_pop_16!(x);                             r_psh_8!(truth!(x <y)); } +                /* GTHr*: */ 0xE7 => { m_lit_16!(y); r_pop_16!(x);                             r_psh_8!(truth!(x >y)); } +                /* LDAr*: */ 0xE8 => { m_lit_16!(a);               r_psh_16!(m_read_16!(a)); } +                /* LKAr*: */ 0xE9 => { m_lit_16!(a); r_psh_16!(a); r_psh_16!(m_read_16!(a)); } +                /* STAr*: */ 0xEA => { m_lit_16!(a); r_pop_16!(v);               m_write_16!(v,a); } +                /* SKAr*: */ 0xEB => { m_lit_16!(v); r_pop_16!(a); r_psh_16!(a); m_write_16!(v,a); } +                /* LDDr*: */ 0xEC => { m_lit_8!(p);              r_psh_16!(d_read_16!(p)); }, +                /* LKDr*: */ 0xED => { m_lit_8!(p); r_psh_8!(p); r_psh_16!(d_read_16!(p)); }, +                /* STDr*: */ 0xEE => { m_lit_8!(p); r_pop_16!(v);               d_write_16!(v,p); }, +                /* SKDr*: */ 0xEF => { m_lit_8!(p); r_pop_16!(v); r_psh_16!(v); d_write_16!(v,p); }, +                /* PSHr*: */ 0xF0 => { m_lit_16!(x); r_psh_16!(x); }, +                /* POPr*: */ 0xF1 => { m_lit_16!(_x); }, +                /* SHFr*: */ 0xF2 => { m_lit_8!(y); r_pop_16!(x); r_psh_16!(shf!(x,y)); }, +                /* SHCr*: */ 0xF3 => { m_lit_8!(y); r_pop_16!(x); r_psh_16!(shc!(x,y)); }, +                /* SWPr*: */ 0xF4 => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(y); r_psh_16!(x); }, +                /* ROTr*: */ 0xF5 => { m_lit_16!(z); r_pop_16!(y); r_pop_16!(x); r_psh_16!(y); r_psh_16!(z); r_psh_16!(x); }, +                /* DUPr*: */ 0xF6 => { m_lit_16!(x); r_psh_16!(x); r_psh_16!(x); }, +                /* OVRr*: */ 0xF7 => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x); r_psh_16!(y); r_psh_16!(x); }, +                /* ADDr*: */ 0xF8 => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x.wrapping_add(y)); }, +                /* SUBr*: */ 0xF9 => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x.wrapping_sub(y)); }, +                /* INCr*: */ 0xFA => { m_lit_16!(x); r_psh_16!(x.wrapping_add(1)); }, +                /* DECr*: */ 0xFB => { m_lit_16!(x); r_psh_16!(x.wrapping_sub(1)); }, +                /* NOTr*: */ 0xFC => { m_lit_16!(x); r_psh_16!(x.not()); }, +                /* ANDr*: */ 0xFD => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x.bitand(y)); }, +                /* IORr*: */ 0xFE => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x.bitor(y)); }, +                /* XORr*: */ 0xFF => { m_lit_16!(y); r_pop_16!(x); r_psh_16!(x.bitxor(y)); }, +            } +        } + +        return None; +    } +} diff --git a/src/stack.rs b/src/stack.rs new file mode 100644 index 0000000..2a0a514 --- /dev/null +++ b/src/stack.rs @@ -0,0 +1,40 @@ +pub struct Stack { +    pub mem: [u8; 256], +    pub sp: u8, +} + +impl Stack { +    pub fn new() -> Self { +        Self { +            mem: [0; 256], +            sp: 0, +        } +    } + +    pub fn push_u8(&mut self, val: u8) { +        self.mem[self.sp as usize] = val; +        self.sp = self.sp.wrapping_add(1); +    } + +    pub fn pop_u8(&mut self) -> u8 { +        self.sp = self.sp.wrapping_sub(1); +        self.mem[self.sp as usize] +    } + +    pub fn push_u16(&mut self, val: u16) { +        let [byte_high, byte_low] = u16::to_be_bytes(val); +        self.push_u8(byte_high); +        self.push_u8(byte_low); +    } + +    pub fn pop_u16(&mut self) -> u16 { +        let byte_low = self.pop_u8(); +        let byte_high = self.pop_u8(); +        u16::from_be_bytes([byte_high, byte_low]) +    } + +    pub fn reset(&mut self) { +        self.mem.fill(0); +        self.sp = 0; +    } +} | 
