summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core.rs311
1 files changed, 247 insertions, 64 deletions
diff --git a/src/core.rs b/src/core.rs
index 20bf177..7779dab 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -2,40 +2,81 @@ use crate::ram::Ram;
use std::fmt;
#[derive(Debug, Clone)]
-pub enum Opcode {
- Nop,
- Mov,
- Push,
- Pop,
- Illegal,
- Sjmp,
+pub enum Register {
+ R0,
+ R1,
+ R2,
+ R3,
+ R4,
+ R5,
+ R6,
+ R7,
+}
+
+#[derive(Debug, Clone)]
+pub enum Operand {
+ Acc,
+ Direct(u8),
+ Indirect(Register),
+ Data(u8),
+ Register(Register),
+ Reladdr(i8),
}
#[derive(Debug, Clone)]
pub struct Op {
- opcode: Opcode,
+ opcode: Isa8051Opcode,
size: usize,
- operand1: Option<u8>,
- operand2: Option<u8>,
- operand3: Option<u8>,
+ operand1: Option<Operand>,
+ operand2: Option<Operand>,
}
const OPCODE_NOP: u8 = 0x00;
const OPCODE_MOV_A_DATA: u8 = 0x74;
-const OPCODE_MOV_DIR_DATA: u8 = 0x75;
+const OPCODE_MOV_DIRECT_DATA: u8 = 0x75;
+const OPCODE_MOV_A_DIRECT: u8 = 0xE5;
+const OPCODE_MOV_A_INDIRECT_R0: u8 = 0xE6;
+const OPCODE_MOV_A_INDIRECT_R1: u8 = 0xE7;
+const OPCODE_MOV_A_R0: u8 = 0xE8;
+const OPCODE_MOV_A_R1: u8 = 0xE9;
+const OPCODE_MOV_A_R2: u8 = 0xEA;
+const OPCODE_MOV_A_R3: u8 = 0xEB;
+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_PUSH: u8 = 0xC0;
const OPCODE_POP: u8 = 0xD0;
const OPCODE_SJMP: u8 = 0xD2;
-impl fmt::Display for Opcode {
+impl fmt::Display for Operand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{:?}", self)
+ write!(
+ f,
+ "{}",
+ match self {
+ Operand::Acc => format!("A"),
+ Operand::Direct(dir) => format!("{:x}h", dir),
+ Operand::Indirect(r) => format!("@{:?}", r),
+ Operand::Data(data) => format!("#{}", data),
+ Operand::Register(r) => format!("{:?}", r),
+ Operand::Reladdr(rel) => format!("{}", rel),
+ }
+ )
}
}
impl fmt::Display for Op {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{:?}", self)
+ let mut output = String::new();
+ output.push_str(&format!("{} ", self.opcode));
+ if let Some(op1) = &self.operand1 {
+ output.push_str(&format!("{}", op1));
+ }
+ if let Some(op2) = &self.operand2 {
+ output.push_str(&format!(",{}", op2));
+ }
+ write!(f, "{}", output)
}
}
@@ -66,10 +107,27 @@ impl Core {
}
///
- /// Get opcode of current instruction
+ /// Get current instruction
///
- pub fn op(&self) -> Opcode {
- self.ram.array[self.pc as usize].op().0
+ pub fn op(&self) -> Op {
+ let op = Isa8051Op::from_u8(self.ram.array[self.pc as usize]);
+ let operand1 = if let Some(operand) = op.operand1 {
+ Some(self.map_operand(operand, 1))
+ } else {
+ None
+ };
+ let operand2 = if let Some(operand) = op.operand2 {
+ // TODO: offset must be based on operand1's size
+ Some(self.map_operand(operand, 2))
+ } else {
+ None
+ };
+ Op {
+ opcode: op.opcode,
+ size: op.size,
+ operand1,
+ operand2,
+ }
}
///
@@ -77,20 +135,9 @@ impl Core {
/// Return the whole operation
///
fn fetch(&mut self) -> Op {
- let mut operand1 = None;
- let opcode = self.ram.array[self.pc as usize].opcode();
- let size = self.ram.array[self.pc as usize].opsize();
- if size == 2 {
- operand1 = Some(self.ram.array[self.pc as usize]);
- }
- self.pc += size as u16;
- Op {
- opcode,
- size,
- operand1,
- operand2: None,
- operand3: None,
- }
+ let op = self.op();
+ self.pc += op.size as u16;
+ return op;
}
///
@@ -98,51 +145,187 @@ impl Core {
///
fn exec(&mut self, op: Op) {
match op.opcode {
- Opcode::Nop => (),
- Opcode::Mov => (),
- Opcode::Illegal => (),
- Opcode::Push => (),
- Opcode::Pop => (),
- Opcode::Sjmp => self.sjmp(op.operand1.expect("SJMP has no operand given") as i8),
+ Isa8051Opcode::Nop => (),
+ Isa8051Opcode::Mov => (),
+ Isa8051Opcode::Illegal => (),
+ Isa8051Opcode::Push => (),
+ Isa8051Opcode::Pop => (),
+ Isa8051Opcode::Sjmp => {
+ if let Some(operand) = op.operand1 {
+ match operand {
+ Operand::Reladdr(reladdr) => self.sjmp(reladdr),
+ _ => panic!("SJMP got incompatible operand"),
+ }
+ } else {
+ panic!("SJMP has no operand given")
+ }
+ }
}
}
fn sjmp(&mut self, reladdr: i8) {
self.pc = (self.pc as i16 + reladdr as i16) as u16;
}
-}
-type Register = u8;
+ fn map_operand(&self, operand: Isa8051Operand, offset: usize) -> Operand {
+ match operand {
+ Isa8051Operand::Acc => Operand::Acc,
+ Isa8051Operand::Direct => Operand::Direct(self.ram.array[(self.pc as usize + offset)]),
+ Isa8051Operand::Data => Operand::Data(self.ram.array[(self.pc as usize + offset)]),
+ Isa8051Operand::Indirect(r) => Operand::Indirect(r),
+ Isa8051Operand::Register(r) => Operand::Register(r),
+ Isa8051Operand::Reladdr => {
+ Operand::Reladdr(self.ram.array[(self.pc as usize + offset)] as i8)
+ }
+ }
+ }
+}
-pub trait Isa8051 {
- fn op(&self) -> (Opcode, usize, Option<Register>);
- fn opcode(&self) -> Opcode;
- fn opsize(&self) -> usize;
- fn opreg(&self) -> Option<Register>;
+#[derive(Debug, Clone)]
+pub enum Isa8051Operand {
+ Acc,
+ Direct,
+ Data,
+ Indirect(Register),
+ Register(Register),
+ Reladdr,
}
-impl Isa8051 for u8 {
- fn op(&self) -> (Opcode, usize, Option<Register>) {
- match *self {
- OPCODE_NOP => (Opcode::Nop, 1, None),
- OPCODE_MOV_A_DATA => (Opcode::Mov, 2, None),
- OPCODE_MOV_DIR_DATA => (Opcode::Mov, 3, None),
- OPCODE_PUSH => (Opcode::Push, 2, None),
- OPCODE_POP => (Opcode::Pop, 2, None),
- OPCODE_SJMP => (Opcode::Sjmp, 2, None),
- _ => (Opcode::Illegal, 1, None),
- }
- }
+#[derive(Debug, Clone)]
+pub enum Isa8051Opcode {
+ Nop,
+ Mov,
+ Push,
+ Pop,
+ Illegal,
+ Sjmp,
+}
- fn opcode(&self) -> Opcode {
- self.op().0
+impl fmt::Display for Isa8051Opcode {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self)
}
+}
- fn opsize(&self) -> usize {
- self.op().1
- }
+#[derive(Debug, Clone)]
+pub struct Isa8051Op {
+ opcode: Isa8051Opcode,
+ size: usize,
+ operand1: Option<Isa8051Operand>,
+ operand2: Option<Isa8051Operand>,
+}
- fn opreg(&self) -> Option<Register> {
- self.op().2
+impl Isa8051Op {
+ fn from_u8(data: u8) -> Self {
+ match data {
+ OPCODE_NOP => Isa8051Op {
+ opcode: Isa8051Opcode::Nop,
+ size: 1,
+ operand1: None,
+ operand2: None,
+ },
+ OPCODE_MOV_A_DATA => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 2,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Data),
+ },
+ OPCODE_MOV_DIRECT_DATA => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 3,
+ operand1: Some(Isa8051Operand::Direct),
+ operand2: Some(Isa8051Operand::Data),
+ },
+ OPCODE_MOV_A_DIRECT => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 2,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Direct),
+ },
+ OPCODE_MOV_A_INDIRECT_R0 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Indirect(Register::R0)),
+ },
+ OPCODE_MOV_A_INDIRECT_R1 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Indirect(Register::R1)),
+ },
+ OPCODE_MOV_A_R0 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R0)),
+ },
+ OPCODE_MOV_A_R1 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R1)),
+ },
+ OPCODE_MOV_A_R2 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R2)),
+ },
+ OPCODE_MOV_A_R3 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R3)),
+ },
+ OPCODE_MOV_A_R4 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R4)),
+ },
+ OPCODE_MOV_A_R5 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R5)),
+ },
+ OPCODE_MOV_A_R6 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R6)),
+ },
+ OPCODE_MOV_A_R7 => Isa8051Op {
+ opcode: Isa8051Opcode::Mov,
+ size: 1,
+ operand1: Some(Isa8051Operand::Acc),
+ operand2: Some(Isa8051Operand::Register(Register::R7)),
+ },
+ OPCODE_PUSH => Isa8051Op {
+ opcode: Isa8051Opcode::Push,
+ size: 2,
+ operand1: Some(Isa8051Operand::Direct),
+ operand2: None,
+ },
+ OPCODE_POP => Isa8051Op {
+ opcode: Isa8051Opcode::Pop,
+ size: 2,
+ operand1: Some(Isa8051Operand::Direct),
+ operand2: None,
+ },
+ OPCODE_SJMP => Isa8051Op {
+ opcode: Isa8051Opcode::Sjmp,
+ size: 2,
+ operand1: Some(Isa8051Operand::Reladdr),
+ operand2: None,
+ },
+ _ => Isa8051Op {
+ opcode: Isa8051Opcode::Illegal,
+ size: 1,
+ operand1: None,
+ operand2: None,
+ },
+ }
}
}