diff options
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/device_bus.rs | 22 | ||||
-rw-r--r-- | src/components/mod.rs | 8 | ||||
-rw-r--r-- | src/components/processor.rs | 360 | ||||
-rw-r--r-- | src/components/program_memory.rs | 51 | ||||
-rw-r--r-- | src/components/stack.rs | 39 |
5 files changed, 480 insertions, 0 deletions
diff --git a/src/components/device_bus.rs b/src/components/device_bus.rs new file mode 100644 index 0000000..9854ee9 --- /dev/null +++ b/src/components/device_bus.rs @@ -0,0 +1,22 @@ +use crate::*; + + +pub trait DeviceBus { + fn read(&mut self, port: u8) -> u8; + fn write(&mut self, port: u8, value: u8) -> Option<Signal>; + fn wake(&mut self) -> bool; +} + + +pub trait Device { + fn read(&mut self, port: u8) -> u8; + fn write(&mut self, port: u8, value: u8) -> Option<Signal>; + fn wake(&mut self) -> bool; +} + +impl Device for () { + fn read(&mut self, _: u8) -> u8 { 0 } + fn write(&mut self, _: u8, _: u8) -> Option<Signal> { None } + fn wake(&mut self) -> bool { false } +} + diff --git a/src/components/mod.rs b/src/components/mod.rs new file mode 100644 index 0000000..f922bcc --- /dev/null +++ b/src/components/mod.rs @@ -0,0 +1,8 @@ +mod device_bus; +mod processor; +mod program_memory; +mod stack; + +pub use device_bus::*; +pub use program_memory::*; +pub use stack::*; diff --git a/src/components/processor.rs b/src/components/processor.rs new file mode 100644 index 0000000..d5d343d --- /dev/null +++ b/src/components/processor.rs @@ -0,0 +1,360 @@ +use crate::*; + +use std::ops::*; + + +impl <DB: DeviceBus> BedrockEmulator<DB> { + pub fn evaluate(&mut self, cycles: usize, debug: bool) -> Option<Signal> { + macro_rules! WPSH1 { ($x:expr) => { self.core.wst.push_u8($x) }; } + macro_rules! RPSH1 { ($x:expr) => { self.core.rst.push_u8($x) }; } + macro_rules! WPSH2 { ($x:expr,$y:expr) => { WPSH1!($x); WPSH1!($y); }; } + macro_rules! RPSH2 { ($x:expr,$y:expr) => { RPSH1!($x); RPSH1!($y); }; } + macro_rules! WPSHD { ($d:expr) => { self.core.wst.push_u16($d) }; } + macro_rules! RPSHD { ($d:expr) => { self.core.rst.push_u16($d) }; } + macro_rules! WPSHB { ($x:expr) => { self.core.wst.push_u8(0u8.wrapping_sub($x as u8)) }; } + macro_rules! RPSHB { ($x:expr) => { self.core.rst.push_u8(0u8.wrapping_sub($x as u8)) }; } + + macro_rules! WPOP1 { ($x:ident) => { let $x = self.core.wst.pop_u8(); }; } + macro_rules! RPOP1 { ($x:ident) => { let $x = self.core.rst.pop_u8(); }; } + macro_rules! WPOP2 { ($x:ident,$y:ident) => { WPOP1!($y); WPOP1!($x); }; } + macro_rules! RPOP2 { ($x:ident,$y:ident) => { RPOP1!($y); RPOP1!($x); }; } + macro_rules! WPOPD { ($d:ident) => { let $d = self.core.wst.pop_u16(); }; } + macro_rules! RPOPD { ($d:ident) => { let $d = self.core.rst.pop_u16(); }; } + + macro_rules! WGETV { ($i:expr) => { self.core.wst.mem[self.core.wst.sp.wrapping_sub($i) as usize] }; } + macro_rules! RGETV { ($i:expr) => { self.core.rst.mem[self.core.rst.sp.wrapping_sub($i) as usize] }; } + macro_rules! WGET1 { ($x:ident) => { let $x = WGETV!(1); }; } + macro_rules! RGET1 { ($x:ident) => { let $x = RGETV!(1); }; } + macro_rules! WGET1N { ($x:ident) => { let $x = WGETV!(2); }; } + macro_rules! RGET1N { ($x:ident) => { let $x = RGETV!(2); }; } + macro_rules! WGET2 { ($x:ident,$y:ident) => { let $x = WGETV!(2); let $y = WGETV!(1); }; } + macro_rules! RGET2 { ($x:ident,$y:ident) => { let $x = RGETV!(2); let $y = RGETV!(1); }; } + macro_rules! WGET2N { ($x:ident,$y:ident) => { let $x = WGETV!(4); let $y = WGETV!(3); }; } + macro_rules! RGET2N { ($x:ident,$y:ident) => { let $x = RGETV!(4); let $y = RGETV!(3); }; } + macro_rules! WGETD { ($d:ident) => { let $d = u16::from_be_bytes([WGETV!(2),WGETV!(1)]); }; } + macro_rules! RGETD { ($d:ident) => { let $d = u16::from_be_bytes([RGETV!(2),RGETV!(1)]); }; } + macro_rules! WGETDN { ($d:ident) => { let $d = u16::from_be_bytes([WGETV!(4),WGETV!(3)]); }; } + macro_rules! RGETDN { ($d:ident) => { let $d = u16::from_be_bytes([RGETV!(4),RGETV!(3)]); }; } + + macro_rules! PCSET { ($a:expr) => { self.core.mem.pc=$a }; } + macro_rules! MEM { ($a:expr) => { self.core.mem.mem[$a as usize] }; } + macro_rules! MEMN { ($a:expr) => { self.core.mem.mem[$a.wrapping_add(1) as usize] }; } + macro_rules! DEV { ($p:expr) => { self.dev.read($p) }; } + macro_rules! DEVN { ($p:expr) => { self.dev.read($p.wrapping_add(1)) }; } + + macro_rules! MLIT1 { ($x:ident) => { let $x = self.core.mem.read_u8_next(); }; } + macro_rules! MLIT2 { ($x:ident,$y:ident) => { MLIT1!($x); MLIT1!($y); }; } + macro_rules! MLITD { ($d:ident) => { let $d = self.core.mem.read_u16_next(); }; } + + macro_rules! DSET1 { ($p:expr,$x:expr) => { + let s = self.dev.write($p, $x); + if s.is_some() { return s }; + }; } + macro_rules! DSET2 { ($p:expr,$x:expr,$y:expr) => { + let s1 = self.dev.write($p, $x); + let s2 = self.dev.write($p.wrapping_add(1), $y); + if s1.is_some() { return s1 }; + if s2.is_some() { return s2 }; + }; } + + macro_rules! math { + ($v:expr; ADD $i:expr) => { $v = $v.wrapping_add($i); }; + ($v:expr; SUB $i:expr) => { $v = $v.wrapping_sub($i); }; + ($v:expr; IOR $i:expr) => { $v = $v.bitor($i); }; + ($v:expr; XOR $i:expr) => { $v = $v.bitxor($i); }; + ($v:expr; AND $i:expr) => { $v = $v.bitand($i); }; + ($v:expr; NOT ) => { $v = $v.not(); }; + ($v:expr; TAL ) => { $v = $v.count_ones() as u8; }; + ($v:expr; REV ) => { $v = $v.reverse_bits(); }; + } + + macro_rules! split { + ($v:expr=>$h:ident,$l:ident) => { + let $h=($v>>4); let $l=($v&0x0f); + } + } + macro_rules! shf { + ($x:expr,$y:expr) => { + { split!($y=>l,r); $x.checked_shl(l as u32).unwrap_or(0).checked_shr(r as u32).unwrap_or(0) } + }; + } + macro_rules! shc { + ($x:expr,$y:expr) => { + { split!($y=>l,r); $x.rotate_left(l as u32).rotate_right(r as u32) } + }; + } + + let end = self.core.cycle + cycles; + while self.core.cycle < end { + self.core.cycle += 1; + + match self.core.mem.read_u8_next() { + /* HLT */ 0x00 => { return Some(Signal::Halt); } + /* JMP */ 0x01 => { WPOPD!(a); PCSET!(a); } + /* JCN */ 0x02 => { WPOPD!(a); WPOP1!(t); if t!=0 {PCSET!(a)}; } + /* JCK */ 0x03 => { WPOPD!(a); WGET1!(t); if t!=0 {PCSET!(a)}; } + /* LDA */ 0x04 => { WPOPD!(a); WPSH1!(MEM!(a)); } + /* STA */ 0x05 => { WPOPD!(a); WPOP1!(x); MEM!(a)=x; } + /* LDD */ 0x06 => { WPOP1!(p); WPSH1!(DEV!(p)); } + /* STD */ 0x07 => { WPOP1!(p); WPOP1!(x); DSET1!(p,x); } + /* PSH */ 0x08 => { RPOP1!(x); WPSH1!(x); } + /* POP */ 0x09 => { math!(self.core.wst.sp; SUB 1); } + /* CPY */ 0x0A => { RGET1!(x); WPSH1!(x); } + /* SPL */ 0x0B => { WPOP1!(x); split!(x=>a,b); WPSH2!(a,b); } + /* DUP */ 0x0C => { WGET1!(x); WPSH1!(x); } + /* OVR */ 0x0D => { WGET1N!(x); WPSH1!(x); } + /* SWP */ 0x0E => { WPOP1!(y); WPOP1!(x); WPSH1!(y); WPSH1!(x); } + /* ROT */ 0x0F => { WPOP1!(z); WPOP1!(y); WPOP1!(x); WPSH1!(y); WPSH1!(z); WPSH1!(x); } + /* ADD */ 0x10 => { WPOP1!(y); math!(WGETV!(1); ADD y); } + /* SUB */ 0x11 => { WPOP1!(y); math!(WGETV!(1); SUB y); } + /* INC */ 0x12 => { math!(WGETV!(1); ADD 1); } + /* DEC */ 0x13 => { math!(WGETV!(1); SUB 1); } + /* LTH */ 0x14 => { WPOP1!(y); WPOP1!(x); WPSHB!(x < y); } + /* GTH */ 0x15 => { WPOP1!(y); WPOP1!(x); WPSHB!(x > y); } + /* EQU */ 0x16 => { WPOP1!(y); WPOP1!(x); WPSHB!(x==y); } + /* NQK */ 0x17 => { WGET2!(x,y); WPSHB!(x!=y); } + /* IOR */ 0x18 => { WPOP1!(y); math!(WGETV!(1); IOR y); } + /* XOR */ 0x19 => { WPOP1!(y); math!(WGETV!(1); XOR y); } + /* AND */ 0x1A => { WPOP1!(y); math!(WGETV!(1); AND y); } + /* NOT */ 0x1B => { math!(WGETV!(1); NOT); } + /* SHF */ 0x1C => { WPOP1!(y); WPOP1!(x); WPSH1!(shf!(x,y)); } + /* SHC */ 0x1D => { WPOP1!(y); WPOP1!(x); WPSH1!(shc!(x,y)); } + /* TAL */ 0x1E => { math!(WGETV!(1); TAL); } + /* REV */ 0x1F => { math!(WGETV!(1); REV); } + + /* NOP */ 0x20 => { } + /* JMS */ 0x21 => { WPOPD!(a); RPSHD!(self.core.mem.pc); PCSET!(a); } + /* JCS */ 0x22 => { WPOPD!(a); WPOP1!(t); if t!=0 {RPSHD!(self.core.mem.pc); PCSET!(a)}; } + /* JCK* */ 0x23 => { WPOPD!(a); WGETD!(t); if t!=0 {PCSET!(a)}; } + /* LDA* */ 0x24 => { WPOPD!(a); WPSH2!(MEM!(a),MEMN!(a)); } + /* STA* */ 0x25 => { WPOPD!(a); WPOP2!(x,y); MEM!(a)=x; MEMN!(a)=y; } + /* LDD* */ 0x26 => { WPOP1!(p); WPSH2!(DEV!(p),DEVN!(p)); } + /* STD* */ 0x27 => { WPOP1!(p); WPOP2!(x,y); DSET2!(p,x,y); } + /* PSH* */ 0x28 => { RPOP2!(x,y); WPSH2!(x,y); } + /* POP* */ 0x29 => { math!(self.core.wst.sp; SUB 2); } + /* CPY* */ 0x2A => { RGET2!(x,y); WPSH2!(x,y); } + /* SPL* */ 0x2B => { WPOP2!(x,y); split!(x=>a,b); split!(y=>c,d); WPSH2!(a,b); WPSH2!(c,d); } + /* DUP* */ 0x2C => { WGET2!(x,y); WPSH2!(x,y); } + /* OVR* */ 0x2D => { WGET2N!(x,y); WPSH2!(x,y); } + /* SWP* */ 0x2E => { WPOP2!(c,d); WPOP2!(a,b); WPSH2!(c,d); WPSH2!(a,b); } + /* ROT* */ 0x2F => { WPOP2!(e,f); WPOP2!(c,d); WPOP2!(a,b); WPSH2!(c,d); WPSH2!(e,f); WPSH2!(a,b); } + /* ADD* */ 0x30 => { WPOPD!(y); WPOPD!(x); WPSHD!(x.wrapping_add(y)); } + /* SUB* */ 0x31 => { WPOPD!(y); WPOPD!(x); WPSHD!(x.wrapping_sub(y)); } + /* INC* */ 0x32 => { WPOPD!(x); WPSHD!(x.wrapping_add(1)); } + /* DEC* */ 0x33 => { WPOPD!(x); WPSHD!(x.wrapping_sub(1)); } + /* LTH* */ 0x34 => { WPOPD!(y); WPOPD!(x); WPSHB!(x < y); } + /* GTH* */ 0x35 => { WPOPD!(y); WPOPD!(x); WPSHB!(x > y); } + /* EQU* */ 0x36 => { WPOPD!(y); WPOPD!(x); WPSHB!(x==y); } + /* NQK* */ 0x37 => { WGETD!(y); WGETDN!(x); WPSHB!(x!=y); } + /* IOR* */ 0x38 => { WPOP2!(x,y); math!(WGETV!(2); IOR x); math!(WGETV!(1); IOR y); } + /* XOR* */ 0x39 => { WPOP2!(x,y); math!(WGETV!(2); XOR x); math!(WGETV!(1); XOR y); } + /* AND* */ 0x3A => { WPOP2!(x,y); math!(WGETV!(2); AND x); math!(WGETV!(1); AND y); } + /* NOT* */ 0x3B => { math!(WGETV!(2); NOT); math!(WGETV!(1); NOT); } + /* SHF* */ 0x3C => { WPOP1!(y); WPOPD!(x); WPSHD!(shf!(x,y)); } + /* SHC* */ 0x3D => { WPOP1!(y); WPOPD!(x); WPSHD!(shc!(x,y)); } + /* TAL* */ 0x3E => { WPOPD!(x); WPSH1!(x.count_ones() as u8); } + /* REV* */ 0x3F => { WPOPD!(x); WPSHD!(x.reverse_bits()); } + + /* DB1 */ 0x40 => { if debug { return Some(Signal::Debug(Debug::Debug1)); } } + /* JMP: */ 0x41 => { MLITD!(a); PCSET!(a); } + /* JCN: */ 0x42 => { MLITD!(a); WPOP1!(t); if t!=0 {PCSET!(a)}; } + /* JCK: */ 0x43 => { MLITD!(a); WGET1!(t); if t!=0 {PCSET!(a)}; } + /* LDA: */ 0x44 => { MLITD!(a); WPSH1!(MEM!(a)); } + /* STA: */ 0x45 => { MLITD!(a); WPOP1!(x); MEM!(a)=x; } + /* LDD: */ 0x46 => { MLIT1!(p); WPSH1!(DEV!(p)); } + /* STD: */ 0x47 => { MLIT1!(p); WPOP1!(x); DSET1!(p,x); } + /* PSH: */ 0x48 => { MLIT1!(x); WPSH1!(x); } + /* POP: */ 0x49 => { math!(self.core.mem.pc; ADD 1); } + /* CPY: */ 0x4A => { MLIT1!(x); WPSH1!(x); RPSH1!(x); } + /* SPL: */ 0x4B => { MLIT1!(x); split!(x=>a,b); WPSH2!(a,b); } + /* DUP: */ 0x4C => { MLIT1!(x); WPSH1!(x); WPSH1!(x); } + /* OVR: */ 0x4D => { MLIT1!(y); WGET1!(x); WPSH1!(y); WPSH1!(x); } + /* SWP: */ 0x4E => { MLIT1!(y); WPOP1!(x); WPSH1!(y); WPSH1!(x); } + /* ROT: */ 0x4F => { MLIT1!(z); WPOP1!(y); WPOP1!(x); WPSH1!(y); WPSH1!(z); WPSH1!(x); } + /* ADD: */ 0x50 => { MLIT1!(y); math!(WGETV!(1); ADD y); } + /* SUB: */ 0x51 => { MLIT1!(y); math!(WGETV!(1); SUB y); } + /* INC: */ 0x52 => { MLIT1!(x); WPSH1!(x.wrapping_add(1)); } + /* DEC: */ 0x53 => { MLIT1!(x); WPSH1!(x.wrapping_sub(1)); } + /* LTH: */ 0x54 => { MLIT1!(y); WPOP1!(x); WPSHB!(x < y); } + /* GTH: */ 0x55 => { MLIT1!(y); WPOP1!(x); WPSHB!(x > y); } + /* EQU: */ 0x56 => { MLIT1!(y); WPOP1!(x); WPSHB!(x==y); } + /* NQK: */ 0x57 => { MLIT1!(y); WGET1!(x); WPSH1!(y); WPSHB!(x!=y); } + /* IOR: */ 0x58 => { MLIT1!(y); math!(WGETV!(1); IOR y); } + /* XOR: */ 0x59 => { MLIT1!(y); math!(WGETV!(1); XOR y); } + /* AND: */ 0x5A => { MLIT1!(y); math!(WGETV!(1); AND y); } + /* NOT: */ 0x5B => { MLIT1!(x); WPSH1!(x.not()); } + /* SHF: */ 0x5C => { MLIT1!(y); WPOP1!(x); WPSH1!(shf!(x,y)); } + /* SHC: */ 0x5D => { MLIT1!(y); WPOP1!(x); WPSH1!(shc!(x,y)); } + /* TAL: */ 0x5E => { MLIT1!(x); WPSH1!(x.count_ones() as u8); } + /* REV: */ 0x5F => { MLIT1!(x); WPSH1!(x.reverse_bits()); } + + /* DB2 */ 0x60 => { if debug { return Some(Signal::Debug(Debug::Debug2)); } } + /* JMS: */ 0x61 => { MLITD!(a); RPSHD!(self.core.mem.pc); PCSET!(a); } + /* JCS: */ 0x62 => { MLITD!(a); WPOP1!(t); if t!=0 {RPSHD!(self.core.mem.pc); PCSET!(a)}; } + /* JCK*: */ 0x63 => { MLITD!(a); WGETD!(t); if t!=0 {PCSET!(a)}; } + /* LDA*: */ 0x64 => { MLITD!(a); WPSH2!(MEM!(a),MEMN!(a)); } + /* STA*: */ 0x65 => { MLITD!(a); WPOP2!(x,y); MEM!(a)=x; MEMN!(a)=y; } + /* LDD*: */ 0x66 => { MLIT1!(p); WPSH2!(DEV!(p),DEVN!(p)); } + /* STD*: */ 0x67 => { MLIT1!(p); WPOP2!(x,y); DSET2!(p,x,y); } + /* PSH*: */ 0x68 => { MLIT2!(x,y); WPSH2!(x,y); } + /* POP*: */ 0x69 => { math!(self.core.mem.pc; ADD 2); } + /* CPY*: */ 0x6A => { MLIT2!(x,y); WPSH2!(x,y); RPSH2!(x,y); } + /* SPL*: */ 0x6B => { MLIT2!(x,y); split!(x=>a,b); split!(y=>c,d); WPSH2!(a,b); WPSH2!(c,d); } + /* DUP*: */ 0x6C => { MLIT2!(x,y); WPSH2!(x,y); WPSH2!(x,y); } + /* OVR*: */ 0x6D => { MLIT2!(c,d); WGET2!(a,b); WPSH2!(c,d); WPSH2!(a,b); } + /* SWP*: */ 0x6E => { MLIT2!(c,d); WPOP2!(a,b); WPSH2!(c,d); WPSH2!(a,b); } + /* ROT*: */ 0x6F => { MLIT2!(e,f); WPOP2!(c,d); WPOP2!(a,b); WPSH2!(c,d); WPSH2!(e,f); WPSH2!(a,b); } + /* ADD*: */ 0x70 => { MLITD!(y); WPOPD!(x); WPSHD!(x.wrapping_add(y)); } + /* SUB*: */ 0x71 => { MLITD!(y); WPOPD!(x); WPSHD!(x.wrapping_sub(y)); } + /* INC*: */ 0x72 => { MLITD!(x); WPSHD!(x.wrapping_add(1)); } + /* DEC*: */ 0x73 => { MLITD!(x); WPSHD!(x.wrapping_sub(1)); } + /* LTH*: */ 0x74 => { MLITD!(y); WPOPD!(x); WPSHB!(x < y); } + /* GTH*: */ 0x75 => { MLITD!(y); WPOPD!(x); WPSHB!(x > y); } + /* EQU*: */ 0x76 => { MLITD!(y); WPOPD!(x); WPSHB!(x==y); } + /* NQK*: */ 0x77 => { MLITD!(y); WGETD!(x); WPSHD!(y); WPSHB!(x!=y); } + /* IOR*: */ 0x78 => { MLIT2!(x,y); math!(WGETV!(2); IOR x); math!(WGETV!(1); IOR y); } + /* XOR*: */ 0x79 => { MLIT2!(x,y); math!(WGETV!(2); XOR x); math!(WGETV!(1); XOR y); } + /* AND*: */ 0x7A => { MLIT2!(x,y); math!(WGETV!(2); AND x); math!(WGETV!(1); AND y); } + /* NOT*: */ 0x7B => { MLITD!(x); WPSHD!(x.not()); } + /* SHF*: */ 0x7C => { MLIT1!(y); WPOPD!(x); WPSHD!(shf!(x,y)); } + /* SHC*: */ 0x7D => { MLIT1!(y); WPOPD!(x); WPSHD!(shc!(x,y)); } + /* TAL*: */ 0x7E => { MLITD!(x); WPSH1!(x.count_ones() as u8); } + /* REV*: */ 0x7F => { MLITD!(x); WPSHD!(x.reverse_bits()); } + + /* DB3 */ 0x80 => { if debug { return Some(Signal::Debug(Debug::Debug3)); } } + /* JMPr */ 0x81 => { RPOPD!(a); PCSET!(a); } + /* JCNr */ 0x82 => { RPOPD!(a); RPOP1!(t); if t!=0 {PCSET!(a)}; } + /* JCKr */ 0x83 => { RPOPD!(a); RGET1!(t); if t!=0 {PCSET!(a)}; } + /* LDAr */ 0x84 => { RPOPD!(a); RPSH1!(MEM!(a)); } + /* STAr */ 0x85 => { RPOPD!(a); RPOP1!(x); MEM!(a)=x; } + /* LDDr */ 0x86 => { RPOP1!(p); RPSH1!(DEV!(p)); } + /* STDr */ 0x87 => { RPOP1!(p); RPOP1!(x); DSET1!(p,x); } + /* PSHr */ 0x88 => { WPOP1!(x); RPSH1!(x); } + /* POPr */ 0x89 => { math!(self.core.rst.sp; SUB 1); } + /* CPYr */ 0x8A => { WGET1!(x); RPSH1!(x); } + /* SPLr */ 0x8B => { RPOP1!(x); split!(x=>a,b); RPSH2!(a,b); } + /* DUPr */ 0x8C => { RGET1!(x); RPSH1!(x); } + /* OVRr */ 0x8D => { RGET1N!(x); RPSH1!(x); } + /* SWPr */ 0x8E => { RPOP1!(y); RPOP1!(x); RPSH1!(y); RPSH1!(x); } + /* ROTr */ 0x8F => { RPOP1!(z); RPOP1!(y); RPOP1!(x); RPSH1!(y); RPSH1!(z); RPSH1!(x); } + /* ADDr */ 0x90 => { RPOP1!(y); math!(RGETV!(1); ADD y); } + /* SUBr */ 0x91 => { RPOP1!(y); math!(RGETV!(1); SUB y); } + /* INCr */ 0x92 => { math!(RGETV!(1); ADD 1); } + /* DECr */ 0x93 => { math!(RGETV!(1); SUB 1); } + /* LTHr */ 0x94 => { RPOP1!(y); RPOP1!(x); RPSHB!(x < y); } + /* GTHr */ 0x95 => { RPOP1!(y); RPOP1!(x); RPSHB!(x > y); } + /* EQUr */ 0x96 => { RPOP1!(y); RPOP1!(x); RPSHB!(x==y); } + /* NQKr */ 0x97 => { RGET2!(x,y); RPSHB!(x!=y); } + /* IORr */ 0x98 => { RPOP1!(y); math!(RGETV!(1); IOR y); } + /* XORr */ 0x99 => { RPOP1!(y); math!(RGETV!(1); XOR y); } + /* ANDr */ 0x9A => { RPOP1!(y); math!(RGETV!(1); AND y); } + /* NOTr */ 0x9B => { math!(RGETV!(1); NOT); } + /* SHFr */ 0x9C => { RPOP1!(y); RPOP1!(x); RPSH1!(shf!(x,y)); } + /* SHCr */ 0x9D => { RPOP1!(y); RPOP1!(x); RPSH1!(shc!(x,y)); } + /* TALr */ 0x9E => { math!(RGETV!(1); TAL); } + /* REVr */ 0x9F => { math!(RGETV!(1); REV); } + + /* DB4 */ 0xA0 => { if debug { return Some(Signal::Debug(Debug::Debug4)); } } + /* JMSr */ 0xA1 => { RPOPD!(a); WPSHD!(self.core.mem.pc); PCSET!(a); } + /* JCSr */ 0xA2 => { RPOPD!(a); RPOP1!(t); if t!=0 {WPSHD!(self.core.mem.pc); PCSET!(a)}; } + /* JCKr* */ 0xA3 => { RPOPD!(a); RGETD!(t); if t!=0 {PCSET!(a)}; } + /* LDAr* */ 0xA4 => { RPOPD!(a); RPSH2!(MEM!(a),MEMN!(a)); } + /* STAr* */ 0xA5 => { RPOPD!(a); RPOP2!(x,y); MEM!(a)=x; MEMN!(a)=y; } + /* LDDr* */ 0xA6 => { RPOP1!(p); RPSH2!(DEV!(p),DEVN!(p)); } + /* STDr* */ 0xA7 => { RPOP1!(p); RPOP2!(x,y); DSET2!(p,x,y); } + /* PSHr* */ 0xA8 => { WPOP2!(x,y); RPSH2!(x,y); } + /* POPr* */ 0xA9 => { math!(self.core.rst.sp; SUB 2); } + /* CPYr* */ 0xAA => { WGET2!(x,y); RPSH2!(x,y); } + /* SPLr* */ 0xAB => { RPOP2!(x,y); split!(x=>a,b); split!(y=>c,d); RPSH2!(a,b); RPSH2!(c,d); } + /* DUPr* */ 0xAC => { RGET2!(x,y); RPSH2!(x,y); } + /* OVRr* */ 0xAD => { RGET2N!(x,y); RPSH2!(x,y); } + /* SWPr* */ 0xAE => { RPOP2!(c,d); RPOP2!(a,b); RPSH2!(c,d); RPSH2!(a,b); } + /* ROTr* */ 0xAF => { RPOP2!(e,f); RPOP2!(c,d); RPOP2!(a,b); RPSH2!(c,d); RPSH2!(e,f); RPSH2!(a,b); } + /* ADDr* */ 0xB0 => { RPOPD!(y); RPOPD!(x); RPSHD!(x.wrapping_add(y)); } + /* SUBr* */ 0xB1 => { RPOPD!(y); RPOPD!(x); RPSHD!(x.wrapping_sub(y)); } + /* INCr* */ 0xB2 => { RPOPD!(x); RPSHD!(x.wrapping_add(1)); } + /* DECr* */ 0xB3 => { RPOPD!(x); RPSHD!(x.wrapping_sub(1)); } + /* LTHr* */ 0xB4 => { RPOPD!(y); RPOPD!(x); RPSHB!(x < y); } + /* GTHr* */ 0xB5 => { RPOPD!(y); RPOPD!(x); RPSHB!(x > y); } + /* EQUr* */ 0xB6 => { RPOPD!(y); RPOPD!(x); RPSHB!(x==y); } + /* NQKr* */ 0xB7 => { RGETD!(y); RGETDN!(x); RPSHB!(x!=y); } + /* IORr* */ 0xB8 => { RPOP2!(x,y); math!(RGETV!(2); IOR x); math!(RGETV!(1); IOR y); } + /* XORr* */ 0xB9 => { RPOP2!(x,y); math!(RGETV!(2); XOR x); math!(RGETV!(1); XOR y); } + /* ANDr* */ 0xBA => { RPOP2!(x,y); math!(RGETV!(2); AND x); math!(RGETV!(1); AND y); } + /* NOTr* */ 0xBB => { math!(RGETV!(2); NOT); math!(RGETV!(1); NOT); } + /* SHFr* */ 0xBC => { RPOP1!(y); RPOPD!(x); RPSHD!(shf!(x,y)); } + /* SHCr* */ 0xBD => { RPOP1!(y); RPOPD!(x); RPSHD!(shc!(x,y)); } + /* TALr* */ 0xBE => { RPOPD!(x); RPSH1!(x.count_ones() as u8); } + /* REVr* */ 0xBF => { RPOPD!(x); RPSHD!(x.reverse_bits()); } + + /* DB5 */ 0xC0 => { if debug { return Some(Signal::Debug(Debug::Debug5)); } } + /* JMPr: */ 0xC1 => { MLITD!(a); PCSET!(a); } + /* JCNr: */ 0xC2 => { MLITD!(a); RPOP1!(t); if t!=0 {PCSET!(a)}; } + /* JCKr: */ 0xC3 => { MLITD!(a); RGET1!(t); if t!=0 {PCSET!(a)}; } + /* LDAr: */ 0xC4 => { MLITD!(a); RPSH1!(MEM!(a)); } + /* STAr: */ 0xC5 => { MLITD!(a); RPOP1!(x); MEM!(a)=x; } + /* LDDr: */ 0xC6 => { MLIT1!(p); RPSH1!(DEV!(p)); } + /* STDr: */ 0xC7 => { MLIT1!(p); RPOP1!(x); DSET1!(p,x); } + /* PSHr: */ 0xC8 => { MLIT1!(x); RPSH1!(x); } + /* POPr: */ 0xC9 => { math!(self.core.mem.pc; ADD 1); } + /* CPYr: */ 0xCA => { MLIT1!(x); RPSH1!(x); WPSH1!(x); } + /* SPLr: */ 0xCB => { MLIT1!(x); split!(x=>a,b); RPSH2!(a,b); } + /* DUPr: */ 0xCC => { MLIT1!(x); RPSH1!(x); RPSH1!(x); } + /* OVRr: */ 0xCD => { MLIT1!(y); RGET1!(x); RPSH1!(y); RPSH1!(x); } + /* SWPr: */ 0xCE => { MLIT1!(y); RPOP1!(x); RPSH1!(y); RPSH1!(x); } + /* ROTr: */ 0xCF => { MLIT1!(z); RPOP1!(y); RPOP1!(x); RPSH1!(y); RPSH1!(z); RPSH1!(x); } + /* ADDr: */ 0xD0 => { MLIT1!(y); math!(RGETV!(1); ADD y); } + /* SUBr: */ 0xD1 => { MLIT1!(y); math!(RGETV!(1); SUB y); } + /* INCr: */ 0xD2 => { MLIT1!(x); RPSH1!(x.wrapping_add(1)); } + /* DECr: */ 0xD3 => { MLIT1!(x); RPSH1!(x.wrapping_sub(1)); } + /* LTHr: */ 0xD4 => { MLIT1!(y); RPOP1!(x); RPSHB!(x < y); } + /* GTHr: */ 0xD5 => { MLIT1!(y); RPOP1!(x); RPSHB!(x > y); } + /* EQUr: */ 0xD6 => { MLIT1!(y); RPOP1!(x); RPSHB!(x==y); } + /* NQKr: */ 0xD7 => { MLIT1!(y); RGET1!(x); RPSH1!(y); RPSHB!(x!=y); } + /* IORr: */ 0xD8 => { MLIT1!(y); math!(RGETV!(1); IOR y); } + /* XORr: */ 0xD9 => { MLIT1!(y); math!(RGETV!(1); XOR y); } + /* ANDr: */ 0xDA => { MLIT1!(y); math!(RGETV!(1); AND y); } + /* NOTr: */ 0xDB => { MLIT1!(x); RPSH1!(x.not()); } + /* SHFr: */ 0xDC => { MLIT1!(y); RPOP1!(x); RPSH1!(shf!(x,y)); } + /* SHCr: */ 0xDD => { MLIT1!(y); RPOP1!(x); RPSH1!(shc!(x,y)); } + /* TALr: */ 0xDE => { MLIT1!(x); RPSH1!(x.count_ones() as u8); } + /* REVr: */ 0xDF => { MLIT1!(x); RPSH1!(x.reverse_bits()); } + + /* DB6 */ 0xE0 => { if debug { return Some(Signal::Debug(Debug::Debug6)); } } + /* JMSr: */ 0xE1 => { MLITD!(a); WPSHD!(self.core.mem.pc); PCSET!(a); } + /* JCSr: */ 0xE2 => { MLITD!(a); RPOP1!(t); if t!=0 {WPSHD!(self.core.mem.pc); PCSET!(a)}; } + /* JCKr*: */ 0xE3 => { MLITD!(a); RGETD!(t); if t!=0 {PCSET!(a)}; } + /* LDAr*: */ 0xE4 => { MLITD!(a); RPSH2!(MEM!(a),MEMN!(a)); } + /* STAr*: */ 0xE5 => { MLITD!(a); RPOP2!(x,y); MEM!(a)=x; MEMN!(a)=y; } + /* LDDr*: */ 0xE6 => { MLIT1!(p); RPSH2!(DEV!(p),DEVN!(p)); } + /* STDr*: */ 0xE7 => { MLIT1!(p); RPOP2!(x,y); DSET2!(p,x,y); } + /* PSHr*: */ 0xE8 => { MLIT2!(x,y); RPSH2!(x,y); } + /* POPr*: */ 0xE9 => { math!(self.core.mem.pc; ADD 2); } + /* CPYr*: */ 0xEA => { MLIT2!(x,y); RPSH2!(x,y); WPSH2!(x,y); } + /* SPLr*: */ 0xEB => { MLIT2!(x,y); split!(x=>a,b); split!(y=>c,d); RPSH2!(a,b); RPSH2!(c,d); } + /* DUPr*: */ 0xEC => { MLIT2!(x,y); RPSH2!(x,y); RPSH2!(x,y); } + /* OVRr*: */ 0xED => { MLIT2!(c,d); RGET2!(a,b); RPSH2!(c,d); RPSH2!(a,b); } + /* SWPr*: */ 0xEE => { MLIT2!(c,d); RPOP2!(a,b); RPSH2!(c,d); RPSH2!(a,b); } + /* ROTr*: */ 0xEF => { MLIT2!(e,f); RPOP2!(c,d); RPOP2!(a,b); RPSH2!(c,d); RPSH2!(e,f); RPSH2!(a,b); } + /* ADDr*: */ 0xF0 => { MLITD!(y); RPOPD!(x); RPSHD!(x.wrapping_add(y)); } + /* SUBr*: */ 0xF1 => { MLITD!(y); RPOPD!(x); RPSHD!(x.wrapping_sub(y)); } + /* INCr*: */ 0xF2 => { MLITD!(x); RPSHD!(x.wrapping_add(1)); } + /* DECr*: */ 0xF3 => { MLITD!(x); RPSHD!(x.wrapping_sub(1)); } + /* LTHr*: */ 0xF4 => { MLITD!(y); RPOPD!(x); RPSHB!(x < y); } + /* GTHr*: */ 0xF5 => { MLITD!(y); RPOPD!(x); RPSHB!(x > y); } + /* EQUr*: */ 0xF6 => { MLITD!(y); RPOPD!(x); RPSHB!(x==y); } + /* NQKr*: */ 0xF7 => { MLITD!(y); RGETD!(x); RPSHD!(y); RPSHB!(x!=y); } + /* IORr*: */ 0xF8 => { MLIT2!(x,y); math!(RGETV!(2); IOR x); math!(RGETV!(1); IOR y); } + /* XORr*: */ 0xF9 => { MLIT2!(x,y); math!(RGETV!(2); XOR x); math!(RGETV!(1); XOR y); } + /* ANDr*: */ 0xFA => { MLIT2!(x,y); math!(RGETV!(2); AND x); math!(RGETV!(1); AND y); } + /* NOTr*: */ 0xFB => { MLITD!(x); RPSHD!(x.not()); } + /* SHFr*: */ 0xFC => { MLIT1!(y); RPOPD!(x); RPSHD!(shf!(x,y)); } + /* SHCr*: */ 0xFD => { MLIT1!(y); RPOPD!(x); RPSHD!(shc!(x,y)); } + /* TALr*: */ 0xFE => { MLITD!(x); RPSH1!(x.count_ones() as u8); } + /* REVr*: */ 0xFF => { MLITD!(x); RPSHD!(x.reverse_bits()); } + } + } + + return None; + } +} diff --git a/src/components/program_memory.rs b/src/components/program_memory.rs new file mode 100644 index 0000000..bcfbcae --- /dev/null +++ b/src/components/program_memory.rs @@ -0,0 +1,51 @@ +pub struct ProgramMemory { + pub mem: [u8; 65536], + pub pc: u16, +} + +impl ProgramMemory { + pub fn new() -> Self { + Self { + mem: [0; 65536], + pc: 0, + } + } + + pub fn load_program(&mut self, bytecode: &[u8]) { + let length = std::cmp::min(bytecode.len(), 65536); + self.mem[..length].copy_from_slice(&bytecode[..length]); + self.mem[length..65536].fill(0); + } + + 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]) + } +} diff --git a/src/components/stack.rs b/src/components/stack.rs new file mode 100644 index 0000000..bbd7b68 --- /dev/null +++ b/src/components/stack.rs @@ -0,0 +1,39 @@ +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 [high, low] = u16::to_be_bytes(val); + self.mem[self.sp as usize] = high; + self.sp = self.sp.wrapping_add(1); + self.mem[self.sp as usize] = low; + self.sp = self.sp.wrapping_add(1); + } + + pub fn pop_u16(&mut self) -> u16 { + self.sp = self.sp.wrapping_sub(1); + let low = self.mem[self.sp as usize]; + self.sp = self.sp.wrapping_sub(1); + let high = self.mem[self.sp as usize]; + u16::from_be_bytes([high, low]) + } +} |