summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2019-11-20 01:08:28 +0300
committerOxore <oxore@protonmail.com>2019-11-20 01:08:28 +0300
commitacc1902150bbfc7bcbb715a37484504048bb7000 (patch)
treed3a5f0ffeef9551cb8ebbadab53ae23b77e39290 /src
parent6bea1622ee07de01098aba586740625c88ad8eeb (diff)
Implement external memory, DPTR, MOVX and 16-bit MOVs
Diffstat (limited to 'src')
-rw-r--r--src/core.rs146
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",
+ }
+ )
}
}