diff --git a/vcore/src/cpu.rs b/vcore/src/cpu.rs index 2a6e5f6..6402fb1 100644 --- a/vcore/src/cpu.rs +++ b/vcore/src/cpu.rs @@ -208,8 +208,11 @@ impl CPU { } else { match instruction.opcode { Opcode::Nop => { /* No action required */ } - Opcode::Rand => { - todo!() + Opcode::Copy => { + let dest = self.pop_data(); + let src = self.pop_data(); + let len = self.pop_data(); + self.copy_region(len, dest, src); } Opcode::Not => { let x = self.pop_data(); @@ -417,6 +420,25 @@ impl CPU { ); } + fn copy_region(&mut self, len: Word, dest: Word, src: Word) { + // Degenerate cases: + if dest == src || len == 0 { return } + + // Now, check if we're moving to a greater or lesser address: + if dest > src { + // If the dest is greater, we need to move from the end of the range backwards, + // in case there's overlap: + for offset in (0..len.into()).rev() { + self.memory.poke(dest + offset, self.memory.peek(src + offset)) + } + } else { + // Dest is before src, so we'll move from low index to high, in case of overlap: + for offset in 0..len.into() { + self.memory.poke(dest + offset, self.memory.peek(src + offset)) + } + } + } + pub fn interrupt(&mut self, irq: usize, arg: Option) { if irq >= self.iv.len() { panic!("Invalid interrupt: {}", irq) @@ -685,6 +707,62 @@ mod tests { simple_opcode_test(vec![0x800010, 2], Arshift, vec![0xe00004]); } + #[test] + fn test_cpu_copy() { + // No overlap, forwards + memory_opcode_test( + vec![3, 2048, 2051], + vec![1, 2, 3, 4, 5, 6], + Copy, + vec![], + Some(vec![1, 2, 3, 1, 2, 3]), + ); + + // No overlap, backwards + memory_opcode_test( + vec![3, 2051, 2048], + vec![1, 2, 3, 4, 5, 6], + Copy, + vec![], + Some(vec![4, 5, 6, 4, 5, 6]), + ); + + // Overlap, move forward + memory_opcode_test( + vec![3, 2048, 2050], + vec![1, 2, 3, 4, 5, 6], + Copy, + vec![], + Some(vec![1, 2, 1, 2, 3, 6]), + ); + + // Overlap, move backwards + memory_opcode_test( + vec![3, 2051, 2049], + vec![1, 2, 3, 4, 5, 6], + Copy, + vec![], + Some(vec![1, 4, 5, 6, 5, 6]), + ); + + // Degenerate cases + memory_opcode_test( + vec![0, 2051, 2049], + vec![1, 2, 3, 4, 5, 6], + Copy, + vec![], + Some(vec![1, 2, 3, 4, 5, 6]), + ); + + memory_opcode_test( + vec![5, 2048, 2048], + vec![1, 2, 3, 4, 5, 6], + Copy, + vec![], + Some(vec![1, 2, 3, 4, 5, 6]), + ); + } + #[test] fn test_cpu_call_stack() { call_stack_opcode_test(vec![5000], vec![], Call, vec![], vec![1025], 5000.into()); diff --git a/vcore/src/opcodes.rs b/vcore/src/opcodes.rs index c79d239..4b962d2 100644 --- a/vcore/src/opcodes.rs +++ b/vcore/src/opcodes.rs @@ -9,7 +9,7 @@ pub enum Opcode { Mul, Div, Mod, - Rand, + Copy, And, Or, Xor, @@ -82,8 +82,8 @@ impl Display for Opcode { Opcode::Mod => { write!(f, "mod") } - Opcode::Rand => { - write!(f, "rand") + Opcode::Copy => { + write!(f, "copy") } Opcode::And => { write!(f, "and") @@ -206,7 +206,7 @@ impl TryFrom for Opcode { 3 => Mul, 4 => Div, 5 => Mod, - 6 => Rand, + 6 => Copy, 7 => And, 8 => Or, 9 => Xor, @@ -259,7 +259,7 @@ impl<'a> TryFrom<&'a str> for Opcode { "mul" => Mul, "div" => Div, "mod" => Mod, - "rand" => Rand, + "copy" => Copy, "and" => And, "or" => Or, "xor" => Xor, @@ -309,7 +309,7 @@ impl From for u8 { Opcode::Mul => 3, Opcode::Div => 4, Opcode::Mod => 5, - Opcode::Rand => 6, + Opcode::Copy => 6, Opcode::And => 7, Opcode::Or => 8, Opcode::Xor => 9, @@ -354,14 +354,14 @@ impl Opcode { pub fn arity(self) -> usize { use Opcode::*; match self { - Nop | Rand | Ret | Hlt | Sdp | Popr | Peekr | Debug => 0, + Nop | Ret | Hlt | Sdp | Popr | Peekr | Debug => 0, Not | Pop | Dup | Jmp | Jmpr | Call | Load | Loadw | Setint | Pushr | Pick => 1, Add | Sub | Mul | Div | Mod | And | Or | Xor | Gt | Lt | Agt | Alt | Lshift | Rshift | Arshift | Swap | Brz | Brnz | Store | Storew | Setsdp | Setiv => 2, - Rot => 3, + Rot | Copy => 3, } } @@ -372,7 +372,7 @@ impl Opcode { match self { Peekr | Popr | Ret => 1, - Nop | Rand | Hlt | Sdp | Debug | Not | Pop | Dup | Jmp | Jmpr | Call | Load | Loadw + Nop | Copy | Hlt | Sdp | Debug | Not | Pop | Dup | Jmp | Jmpr | Call | Load | Loadw | Setint | Setiv | Pushr | Add | Sub | Mul | Div | Mod | And | Or | Xor | Gt | Lt | Agt | Alt | Lshift | Rshift | Arshift | Swap | Brz | Brnz | Store | Storew | Setsdp | Rot | Pick => 0, @@ -397,7 +397,7 @@ impl Opcode { match self { Sdp => 2, - Peekr | Rand | Dup => 1, + Peekr | Dup => 1, Nop | Hlt | Debug | Not | Call | Load | Loadw | Pushr | Popr | Pick | Rot | Swap => 0, @@ -405,6 +405,8 @@ impl Opcode { | Alt | Lshift | Rshift | Arshift | Ret => -1, Setint | Store | Storew | Setsdp | Setiv | Brz | Brnz => -2, + + Copy => -3, } } }