diff options
author | Oxore <oxore@protonmail.com> | 2019-11-20 01:08:28 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2019-11-20 01:08:28 +0300 |
commit | acc1902150bbfc7bcbb715a37484504048bb7000 (patch) | |
tree | d3a5f0ffeef9551cb8ebbadab53ae23b77e39290 /src | |
parent | 6bea1622ee07de01098aba586740625c88ad8eeb (diff) |
Implement external memory, DPTR, MOVX and 16-bit MOVs
Diffstat (limited to 'src')
-rw-r--r-- | src/core.rs | 146 |
1 files changed, 143 insertions, 3 deletions
diff --git a/src/core.rs b/src/core.rs index dbe26f0..edbfecc 100644 --- a/src/core.rs +++ b/src/core.rs @@ -8,6 +8,9 @@ pub enum Opname { Ljmp, Jnz, Mov, + Mov16, + MovxTo, + MovxFrom, Push, Pop, Illegal, @@ -31,6 +34,9 @@ enum IncompleteOperand { Acc, Direct, Data, + Data16, + Dptr, + AtDptr, Indirect(Register), Register(Register), Reladdr, @@ -44,6 +50,9 @@ pub enum Operand { Direct(u8), Indirect(Register), Data(u8), + Data16(u16), + Dptr, + AtDptr, Register(Register), Reladdr(i8), Addr11(u16), @@ -70,9 +79,12 @@ pub struct Core { pc: u16, ram: [u8; u8::max_value() as usize + 1], rom: Rom, + extmem: [u8; u16::max_value() as usize + 1], } const RAM_OFFSET_ACC: u8 = 0xE0; +const RAM_OFFSET_DPH: u8 = 0x82; +const RAM_OFFSET_DPL: u8 = 0x83; const RAM_OFFSET_SP: u8 = 0x80; const RAM_OFFSET_R0: u8 = 0x00; const RAM_OFFSET_R1: u8 = 0x01; @@ -97,10 +109,12 @@ const OPCODE_MOV_A_DATA: u8 = 0x74; const OPCODE_MOV_DIRECT_DATA: u8 = 0x75; const OPCODE_SJMP: u8 = 0x80; const OPCODE_AJMP_P4: u8 = 0x81; +const OPCODE_MOV_DPTR_DATA16: u8 = 0x90; const OPCODE_AJMP_P5: u8 = 0xA1; const OPCODE_PUSH: u8 = 0xC0; const OPCODE_AJMP_P6: u8 = 0xC1; const OPCODE_POP: u8 = 0xD0; +const OPCODE_MOV_A_AT_DPTR: u8 = 0xE0; const OPCODE_AJMP_P7: u8 = 0xE1; const OPCODE_MOV_A_DIRECT: u8 = 0xE5; const OPCODE_MOV_A_INDIRECT_R0: u8 = 0xE6; @@ -113,6 +127,7 @@ const OPCODE_MOV_A_R4: u8 = 0xEC; const OPCODE_MOV_A_R5: u8 = 0xED; const OPCODE_MOV_A_R6: u8 = 0xEE; const OPCODE_MOV_A_R7: u8 = 0xEF; +const OPCODE_MOV_AT_DPTR_A: u8 = 0xF0; const OP_LUT: [IncompleteOp; u8::max_value() as usize + 1] = { let mut lut = [IncompleteOp { @@ -187,6 +202,12 @@ const OP_LUT: [IncompleteOp; u8::max_value() as usize + 1] = { operand1: Some(IncompleteOperand::Addr11(4)), operand2: None, }; + lut[OPCODE_MOV_DPTR_DATA16 as usize] = IncompleteOp { + opname: Opname::Mov16, + size: 3, + operand1: Some(IncompleteOperand::Dptr), + operand2: Some(IncompleteOperand::Data16), + }; lut[OPCODE_AJMP_P5 as usize] = IncompleteOp { opname: Opname::Ajmp, size: 2, @@ -211,6 +232,12 @@ const OP_LUT: [IncompleteOp; u8::max_value() as usize + 1] = { operand1: Some(IncompleteOperand::Direct), operand2: None, }; + lut[OPCODE_MOV_A_AT_DPTR as usize] = IncompleteOp { + opname: Opname::MovxFrom, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::AtDptr), + }; lut[OPCODE_AJMP_P7 as usize] = IncompleteOp { opname: Opname::Ajmp, size: 2, @@ -283,6 +310,12 @@ const OP_LUT: [IncompleteOp; u8::max_value() as usize + 1] = { operand1: Some(IncompleteOperand::Acc), operand2: Some(IncompleteOperand::Register(Register::R7)), }; + lut[OPCODE_MOV_AT_DPTR_A as usize] = IncompleteOp { + opname: Opname::MovxTo, + size: 1, + operand1: Some(IncompleteOperand::AtDptr), + operand2: Some(IncompleteOperand::Acc), + }; lut }; @@ -308,6 +341,9 @@ impl Operand { Operand::Direct(_) => 1, Operand::Indirect(_) => 0, Operand::Data(_) => 1, + Operand::Data16(_) => 2, + Operand::Dptr => 0, + Operand::AtDptr => 0, Operand::Register(_) => 0, Operand::Reladdr(_) => 1, Operand::Addr11(_) => 1, @@ -332,7 +368,13 @@ impl Core { Ok(value) => value, Err(err_string) => return Err(err_string), }; - Ok(Self { pc: 0, ram, rom }) + let extmem: [u8; u16::max_value() as usize + 1] = [0xFF; u16::max_value() as usize + 1]; + Ok(Self { + pc: 0, + ram, + rom, + extmem, + }) } /// Fetch and execute one instruction @@ -387,6 +429,18 @@ impl Core { op.operand1.expect("MOV has no first operand given"), op.operand2.expect("MOV has no second operand given"), ), + Opname::Mov16 => self.mov16( + op.operand1.expect("MOV has no first operand given"), + op.operand2.expect("MOV has no second operand given"), + ), + Opname::MovxTo => self.movx_to( + op.operand1.expect("MOVX has no first operand given"), + op.operand2.expect("MOVX has no second operand given"), + ), + Opname::MovxFrom => self.movx_from( + op.operand1.expect("MOVX has no first operand given"), + op.operand2.expect("MOVX has no second operand given"), + ), Opname::Illegal => (), Opname::Push => self.push(op.operand1.expect("PUSH has no operand given")), Opname::Pop => self.pop(op.operand1.expect("POP has no operand given")), @@ -405,6 +459,12 @@ impl Core { Operand::Direct(self.rom.array[(self.pc as usize + offset)]) } IncompleteOperand::Data => Operand::Data(self.rom.array[(self.pc as usize + offset)]), + IncompleteOperand::Data16 => Operand::Data16( + (u16::from(self.rom.array[(self.pc as usize + offset)]) << 8) + + u16::from(self.rom.array[(self.pc as usize + offset + 1)]), + ), + IncompleteOperand::Dptr => Operand::Dptr, + IncompleteOperand::AtDptr => Operand::AtDptr, IncompleteOperand::Indirect(r) => Operand::Indirect(r), IncompleteOperand::Register(r) => Operand::Register(r), IncompleteOperand::Reladdr => { @@ -432,13 +492,73 @@ impl Core { Operand::Acc => RAM_OFFSET_ACC, Operand::Direct(dir) => dir, Operand::Indirect(r) => self.ram[r.to_ram_offset() as usize], - Operand::Data(r) => r, + Operand::Data(data) => data, Operand::Register(r) => r.to_ram_offset(), other => panic!("MOV got incompatible second operand \"{:?}\"", other), }; self.ram[dest as usize] = value; } + fn mov16(&mut self, o1: Operand, o2: Operand) { + let dest = match o1 { + Operand::Dptr => RAM_OFFSET_DPH, + other => panic!("MOV (Mov16) got incompatible first operand \"{:?}\"", other), + }; + let value = match o2 { + Operand::Data16(data) => data, + other => panic!( + "MOV (Mov16) got incompatible second operand \"{:?}\"", + other + ), + }; + self.ram[dest as usize] = (value >> 8) as u8; + self.ram[dest as usize + 1] = value as u8; + } + + fn movx_to(&mut self, o1: Operand, o2: Operand) { + let dest = match o1 { + Operand::AtDptr => { + (u16::from(self.ram[RAM_OFFSET_DPH as usize]) << 8) + + u16::from(self.ram[RAM_OFFSET_DPL as usize]) + } + other => panic!( + "MOVX (MovxTo) got incompatible first operand \"{:?}\"", + other + ), + }; + let value = match o2 { + Operand::Acc => self.ram[RAM_OFFSET_ACC as usize], + other => panic!( + "MOVX (MovxTo) got incompatible second operand \"{:?}\"", + other + ), + }; + self.extmem[dest as usize] = value; + } + + fn movx_from(&mut self, o1: Operand, o2: Operand) { + let dest = match o1 { + Operand::Acc => RAM_OFFSET_ACC, + other => panic!( + "MOVX (MovxFrom) got incompatible first operand \"{:?}\"", + other + ), + }; + let value = match o2 { + Operand::AtDptr => { + let dph = u16::from(self.ram[RAM_OFFSET_DPH as usize]); + let dpl = u16::from(self.ram[RAM_OFFSET_DPL as usize]); + let dptr = (dph << 8) + dpl; + self.extmem[dptr as usize] + } + other => panic!( + "MOVX (MovxFrom) got incompatible second operand \"{:?}\"", + other + ), + }; + self.extmem[dest as usize] = value; + } + fn push(&mut self, o: Operand) { match o { Operand::Direct(offset) => { @@ -506,6 +626,9 @@ impl fmt::Display for Operand { Operand::Direct(dir) => format!("{:x}h", dir), Operand::Indirect(r) => format!("@{:?}", r), Operand::Data(data) => format!("#{}", data), + Operand::Data16(data) => format!("#{}", data), + Operand::Dptr => "DPTR".to_string(), + Operand::AtDptr => "@DPTR".to_string(), Operand::Register(r) => format!("{:?}", r), Operand::Reladdr(rel) => format!("{}", rel), Operand::Addr11(rel) => format!("{}", rel), @@ -531,6 +654,23 @@ impl fmt::Display for Op { impl fmt::Display for Opname { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) + write!( + f, + "{}", + match self { + Opname::Nop => "NOP", + Opname::Ajmp => "AJMP", + Opname::Ljmp => "LJMP", + Opname::Jnz => "JNZ", + Opname::Mov => "MOV", + Opname::Mov16 => "MOV", + Opname::MovxTo => "MOVX", + Opname::MovxFrom => "MOVX", + Opname::Push => "PUSH", + Opname::Pop => "POP", + Opname::Illegal => "<Illegal>", + Opname::Sjmp => "SJMP", + } + ) } } |