diff options
author | Oxore <oxore@protonmail.com> | 2019-11-10 23:54:23 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2019-11-10 23:54:23 +0300 |
commit | b04ff5229e6561851ad3a75cd0054f5d90d6d401 (patch) | |
tree | 2e56ed58bd8c248b80126a2add521356b54a011d /src/core.rs | |
parent | 2b85707f48e691d3b574a06aa511b182e7140d10 (diff) |
Improve core architecture, add more MOV instructions
Diffstat (limited to 'src/core.rs')
-rw-r--r-- | src/core.rs | 311 |
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, + }, + } } } |