From 7d4dfd8af842796c4eb8a88df0cc5ab30f99232d Mon Sep 17 00:00:00 2001 From: Oxore Date: Wed, 4 Mar 2020 03:17:25 +0300 Subject: Rename Core to Cpu8051 and Ram to ProgramMemory, etc. Adjust Readme.md --- Readme.md | 4 +- src/core.rs | 716 --------------------------------------------------------- src/cpu8051.rs | 716 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 26 +-- src/progmem.rs | 136 +++++++++++ src/rom.rs | 136 ----------- 6 files changed, 867 insertions(+), 867 deletions(-) delete mode 100644 src/core.rs create mode 100644 src/cpu8051.rs create mode 100644 src/progmem.rs delete mode 100644 src/rom.rs diff --git a/Readme.md b/Readme.md index 9f2c932..6b8af9e 100644 --- a/Readme.md +++ b/Readme.md @@ -12,9 +12,9 @@ - At least one I/O Port (P0) - Timer (with interrupts) - Serial UART (with interrupts) -- Cycle accurate emulation of program execution with synchronization of all the +- Cycle accurate emulation of program execution and synchronization with all peripherals. -- Can bind execution speed to real host machine time with speed multiplier (e.g. +- Locking execution speed to real host machine time with speed multiplier (e.g. 1 instruction per second, 1000 cycles per second). - Every peripheral produces event with information of it's state if it changes. CPU produces events on each step while in single step mode or when pause diff --git a/src/core.rs b/src/core.rs deleted file mode 100644 index 992f12c..0000000 --- a/src/core.rs +++ /dev/null @@ -1,716 +0,0 @@ -use crate::memory::Memory; -use crate::rom::Rom; -use std::fmt; - -#[derive(Debug, Clone, Copy)] -pub enum Opname { - Nop, - Ajmp, - Ljmp, - Jnz, - Mov, - Mov16, - MovxTo, - MovxFrom, - Push, - Pop, - Illegal, - Sjmp, -} - -#[derive(Debug, Clone, Copy)] -pub enum Register { - R0, - R1, - R2, - R3, - R4, - R5, - R6, - R7, -} - -#[derive(Debug, Clone, Copy)] -enum IncompleteOperand { - Acc, - Direct, - Data, - Data16, - Dptr, - AtDptr, - Indirect(Register), - Register(Register), - Reladdr, - Addr11(u8), - Addr16, -} - -#[derive(Debug, Clone)] -pub enum Operand { - Acc, - Direct(u8), - Indirect(Register), - Data(u8), - Data16(u16), - Dptr, - AtDptr, - Register(Register), - Reladdr(i8), - Addr11(u16), - Addr16(u16), -} - -#[derive(Debug, Clone, Copy)] -struct IncompleteOp { - opname: Opname, - size: usize, - operand1: Option, - operand2: Option, - operand3: Option, -} - -#[derive(Debug, Clone)] -pub struct Op { - opname: Opname, - size: usize, - operand1: Option, - operand2: Option, - operand3: Option, -} - -pub struct Core { - pc: u16, - ram: [u8; u8::max_value() as usize + 1], - progmem: 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; -const RAM_OFFSET_R2: u8 = 0x02; -const RAM_OFFSET_R3: u8 = 0x03; -const RAM_OFFSET_R4: u8 = 0x04; -const RAM_OFFSET_R5: u8 = 0x05; -const RAM_OFFSET_R6: u8 = 0x06; -const RAM_OFFSET_R7: u8 = 0x07; - -const RESET_VALUE_ACC: u8 = 0x00; -const RESET_VALUE_SP: u8 = 0x07; - -const OPCODE_NOP: u8 = 0x00; -const OPCODE_AJMP_P0: u8 = 0x01; -const OPCODE_LJMP: u8 = 0x02; -const OPCODE_AJMP_P1: u8 = 0x21; -const OPCODE_AJMP_P2: u8 = 0x41; -const OPCODE_AJMP_P3: u8 = 0x61; -const OPCODE_JNZ: u8 = 0x70; -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; -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_MOV_AT_DPTR_A: u8 = 0xF0; - -const OP_LUT: [IncompleteOp; u8::max_value() as usize + 1] = { - let mut lut = [IncompleteOp { - opname: Opname::Illegal, - size: 1, - operand1: None, - operand2: None, - operand3: None, - }; u8::max_value() as usize + 1]; - lut[OPCODE_NOP as usize] = IncompleteOp { - opname: Opname::Nop, - size: 1, - operand1: None, - operand2: None, - operand3: None, - }; - lut[OPCODE_AJMP_P0 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(0)), - operand2: None, - operand3: None, - }; - lut[OPCODE_LJMP as usize] = IncompleteOp { - opname: Opname::Ljmp, - size: 3, - operand1: Some(IncompleteOperand::Addr16), - operand2: None, - operand3: None, - }; - lut[OPCODE_AJMP_P1 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(1)), - operand2: None, - operand3: None, - }; - lut[OPCODE_AJMP_P2 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(2)), - operand2: None, - operand3: None, - }; - lut[OPCODE_AJMP_P3 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(3)), - operand2: None, - operand3: None, - }; - lut[OPCODE_JNZ as usize] = IncompleteOp { - opname: Opname::Jnz, - size: 2, - operand1: Some(IncompleteOperand::Reladdr), - operand2: None, - operand3: None, - }; - lut[OPCODE_MOV_A_DATA as usize] = IncompleteOp { - opname: Opname::Mov, - size: 2, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Data), - operand3: None, - }; - lut[OPCODE_MOV_DIRECT_DATA as usize] = IncompleteOp { - opname: Opname::Mov, - size: 3, - operand1: Some(IncompleteOperand::Direct), - operand2: Some(IncompleteOperand::Data), - operand3: None, - }; - lut[OPCODE_SJMP as usize] = IncompleteOp { - opname: Opname::Sjmp, - size: 2, - operand1: Some(IncompleteOperand::Reladdr), - operand2: None, - operand3: None, - }; - lut[OPCODE_AJMP_P4 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(4)), - operand2: None, - operand3: None, - }; - lut[OPCODE_MOV_DPTR_DATA16 as usize] = IncompleteOp { - opname: Opname::Mov16, - size: 3, - operand1: Some(IncompleteOperand::Dptr), - operand2: Some(IncompleteOperand::Data16), - operand3: None, - }; - lut[OPCODE_AJMP_P5 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(5)), - operand2: None, - operand3: None, - }; - lut[OPCODE_PUSH as usize] = IncompleteOp { - opname: Opname::Push, - size: 2, - operand1: Some(IncompleteOperand::Direct), - operand2: None, - operand3: None, - }; - lut[OPCODE_AJMP_P6 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(6)), - operand2: None, - operand3: None, - }; - lut[OPCODE_POP as usize] = IncompleteOp { - opname: Opname::Pop, - size: 2, - operand1: Some(IncompleteOperand::Direct), - operand2: None, - operand3: None, - }; - lut[OPCODE_MOV_A_AT_DPTR as usize] = IncompleteOp { - opname: Opname::MovxFrom, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::AtDptr), - operand3: None, - }; - lut[OPCODE_AJMP_P7 as usize] = IncompleteOp { - opname: Opname::Ajmp, - size: 2, - operand1: Some(IncompleteOperand::Addr11(7)), - operand2: None, - operand3: None, - }; - lut[OPCODE_MOV_A_DIRECT as usize] = IncompleteOp { - opname: Opname::Mov, - size: 2, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Direct), - operand3: None, - }; - lut[OPCODE_MOV_A_INDIRECT_R0 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Indirect(Register::R0)), - operand3: None, - }; - lut[OPCODE_MOV_A_INDIRECT_R1 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Indirect(Register::R1)), - operand3: None, - }; - lut[OPCODE_MOV_A_R0 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R0)), - operand3: None, - }; - lut[OPCODE_MOV_A_R1 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R1)), - operand3: None, - }; - lut[OPCODE_MOV_A_R2 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R2)), - operand3: None, - }; - lut[OPCODE_MOV_A_R3 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R3)), - operand3: None, - }; - lut[OPCODE_MOV_A_R4 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R4)), - operand3: None, - }; - lut[OPCODE_MOV_A_R5 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R5)), - operand3: None, - }; - lut[OPCODE_MOV_A_R6 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R6)), - operand3: None, - }; - lut[OPCODE_MOV_A_R7 as usize] = IncompleteOp { - opname: Opname::Mov, - size: 1, - operand1: Some(IncompleteOperand::Acc), - operand2: Some(IncompleteOperand::Register(Register::R7)), - operand3: None, - }; - lut[OPCODE_MOV_AT_DPTR_A as usize] = IncompleteOp { - opname: Opname::MovxTo, - size: 1, - operand1: Some(IncompleteOperand::AtDptr), - operand2: Some(IncompleteOperand::Acc), - operand3: None, - }; - lut -}; - -impl Register { - fn to_ram_offset(self) -> u8 { - match self { - Register::R0 => RAM_OFFSET_R0, - Register::R1 => RAM_OFFSET_R1, - Register::R2 => RAM_OFFSET_R2, - Register::R3 => RAM_OFFSET_R3, - Register::R4 => RAM_OFFSET_R4, - Register::R5 => RAM_OFFSET_R5, - Register::R6 => RAM_OFFSET_R6, - Register::R7 => RAM_OFFSET_R7, - } - } -} - -impl Operand { - fn size(&self) -> usize { - match self { - Operand::Acc => 0, - 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, - Operand::Addr16(_) => 2, - } - } -} - -impl IncompleteOp { - fn from_u8(data: u8) -> Self { - OP_LUT[data as usize] - } -} - -impl Core { - /// Constructor - pub fn new() -> Self { - let mut ram = [0; u8::max_value() as usize + 1]; - ram[RAM_OFFSET_SP as usize] = RESET_VALUE_SP; - ram[RAM_OFFSET_ACC as usize] = RESET_VALUE_ACC; - Self { - pc: 0, - ram, - progmem: Rom::new(), - extmem: [0xFF; u16::max_value() as usize + 1], - } - } - - pub fn rom(mut self, rom: Rom) -> Self { - self.progmem = rom; - self - } - - /// Fetch and execute one instruction - pub fn step(&mut self) -> u16 { - let op = self.fetch(); - self.exec(op); - self.pc - } - - /// Get current Program Counter value - pub fn pc(&self) -> u16 { - self.pc - } - - /// Get current instruction - pub fn op(&self) -> Op { - let op = IncompleteOp::from_u8(self.progmem.get(self.pc)); - let mut operands: Vec> = vec![op.operand1, op.operand2, op.operand3] - .iter() - .scan(1, |offset, &x| { - Some(if let Some(incomplete_operand) = x { - let operand = self.fetch_operand(incomplete_operand, *offset); - *offset += operand.size() as u16; - Some(operand) - } else { - None - }) - }) - .collect(); - Op { - opname: op.opname, - size: op.size, - operand3: operands.remove(2), - operand2: operands.remove(1), - operand1: operands.remove(0), - } - } - - /// Increment PC, return the whole operation - fn fetch(&mut self) -> Op { - let op = self.op(); - self.pc += op.size as u16; - op - } - - /// Execute one instruction without incrementing PC - fn exec(&mut self, op: Op) { - match op.opname { - Opname::Nop => (), - Opname::Mov => self.mov( - 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")), - Opname::Sjmp => self.sjmp(op.operand1.expect("SJMP has no operand given")), - Opname::Ajmp => self.ajmp(op.operand1.expect("AJMP has no operand given")), - Opname::Ljmp => self.ljmp(op.operand1.expect("LJMP has no operand given")), - Opname::Jnz => self.jnz(op.operand1.expect("JNZ has no operand given")), - } - } - - /// Get operand by offset, based on meta information - fn fetch_operand(&self, operand: IncompleteOperand, offset: u16) -> Operand { - match operand { - IncompleteOperand::Acc => Operand::Acc, - IncompleteOperand::Direct => Operand::Direct(self.progmem.get(self.pc + offset)), - IncompleteOperand::Data => Operand::Data(self.progmem.get(self.pc + offset)), - IncompleteOperand::Data16 => Operand::Data16({ - let high = self.progmem.get(self.pc + offset); - let low = self.progmem.get(self.pc + offset + 1); - u16::from(high) << 8 & u16::from(low) - }), - IncompleteOperand::Dptr => Operand::Dptr, - IncompleteOperand::AtDptr => Operand::AtDptr, - IncompleteOperand::Indirect(r) => Operand::Indirect(r), - IncompleteOperand::Register(r) => Operand::Register(r), - IncompleteOperand::Reladdr => { - Operand::Reladdr(self.progmem.get(self.pc + offset) as i8) - } - IncompleteOperand::Addr11(high) => Operand::Addr11({ - let low = self.progmem.get(self.pc + offset); - u16::from(high) << 8 & u16::from(low) - }), - IncompleteOperand::Addr16 => Operand::Addr16({ - let high = self.progmem.get(self.pc + offset); - let low = self.progmem.get(self.pc + offset + 1); - u16::from(high) << 8 & u16::from(low) - }), - } - } - - fn mov(&mut self, o1: Operand, o2: Operand) { - let dest = match o1 { - Operand::Acc => RAM_OFFSET_ACC, - Operand::Direct(dir) => dir, - Operand::Indirect(r) => self.ram[r.to_ram_offset() as usize], - Operand::Register(r) => r.to_ram_offset(), - other => panic!("MOV got incompatible first operand \"{:?}\"", other), - }; - let value = match o2 { - Operand::Acc => RAM_OFFSET_ACC, - Operand::Direct(dir) => dir, - Operand::Indirect(r) => self.ram[r.to_ram_offset() as usize], - 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 => { - let dph = self.ram[RAM_OFFSET_DPH as usize]; - let dpl = self.ram[RAM_OFFSET_DPL as usize]; - u16::from(dph) << 8 & u16::from(dpl) - } - 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, operand: Operand) { - match operand { - Operand::Direct(offset) => { - self.ram[RAM_OFFSET_SP as usize] += 1; - let value = self.ram[offset as usize]; - let sp = self.ram[RAM_OFFSET_SP as usize]; - self.ram[sp as usize] = value; - } - other => panic!("PUSH got incompatible operand \"{:?}\"", other), - } - } - - fn pop(&mut self, operand: Operand) { - match operand { - Operand::Direct(offset) => { - let sp = self.ram[RAM_OFFSET_SP as usize]; - self.ram[offset as usize] = self.ram[sp as usize]; - self.ram[RAM_OFFSET_SP as usize] -= 1; - } - other => panic!("POP got incompatible operand \"{:?}\"", other), - } - } - - fn sjmp(&mut self, operand: Operand) { - match operand { - Operand::Reladdr(reladdr) => { - self.pc = (self.pc as i16 + i16::from(reladdr)) as u16; - } - _ => panic!("SJMP got incompatible operand"), - } - } - - fn ajmp(&mut self, operand: Operand) { - match operand { - Operand::Addr11(addr11) => { - assert!(addr11 <= 0x4FFu16); - // Clear 11 low bits of PC and add address, that is within these 11 bits - self.pc = (self.pc & !0x4FFu16) & addr11; - } - _ => panic!("AJMP got incompatible operand"), - } - } - - fn ljmp(&mut self, operand: Operand) { - match operand { - Operand::Addr16(addr) => self.pc = addr, - _ => panic!("LJMP got incompatible operand"), - } - } - - fn jnz(&mut self, operand: Operand) { - match operand { - Operand::Reladdr(reladdr) => { - if self.ram[usize::from(RAM_OFFSET_ACC)] != 0 { - self.pc = (self.pc as i16 + i16::from(reladdr)) as u16; - } - } - _ => panic!("JNZ got incompatible operand"), - } - } -} - -impl fmt::Display for Operand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - Operand::Acc => "A".to_string(), - 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), - Operand::Addr16(rel) => format!("{}", rel), - } - ) - } -} - -impl fmt::Display for Op { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut output = String::new(); - output.push_str(&format!("{} ", self.opname)); - 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) - } -} - -impl fmt::Display for Opname { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - 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 => "", - Opname::Sjmp => "SJMP", - } - ) - } -} diff --git a/src/cpu8051.rs b/src/cpu8051.rs new file mode 100644 index 0000000..2a0fbe8 --- /dev/null +++ b/src/cpu8051.rs @@ -0,0 +1,716 @@ +use crate::memory::Memory; +use crate::progmem::ProgramMemory; +use std::fmt; + +#[derive(Debug, Clone, Copy)] +pub enum Opname { + Nop, + Ajmp, + Ljmp, + Jnz, + Mov, + Mov16, + MovxTo, + MovxFrom, + Push, + Pop, + Illegal, + Sjmp, +} + +#[derive(Debug, Clone, Copy)] +pub enum Register { + R0, + R1, + R2, + R3, + R4, + R5, + R6, + R7, +} + +#[derive(Debug, Clone, Copy)] +enum IncompleteOperand { + Acc, + Direct, + Data, + Data16, + Dptr, + AtDptr, + Indirect(Register), + Register(Register), + Reladdr, + Addr11(u8), + Addr16, +} + +#[derive(Debug, Clone)] +pub enum Operand { + Acc, + Direct(u8), + Indirect(Register), + Data(u8), + Data16(u16), + Dptr, + AtDptr, + Register(Register), + Reladdr(i8), + Addr11(u16), + Addr16(u16), +} + +#[derive(Debug, Clone, Copy)] +struct IncompleteOp { + opname: Opname, + size: usize, + operand1: Option, + operand2: Option, + operand3: Option, +} + +#[derive(Debug, Clone)] +pub struct Op { + opname: Opname, + size: usize, + operand1: Option, + operand2: Option, + operand3: Option, +} + +pub struct Cpu8051 { + pc: u16, + ram: [u8; u8::max_value() as usize + 1], + progmem: ProgramMemory, + 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; +const RAM_OFFSET_R2: u8 = 0x02; +const RAM_OFFSET_R3: u8 = 0x03; +const RAM_OFFSET_R4: u8 = 0x04; +const RAM_OFFSET_R5: u8 = 0x05; +const RAM_OFFSET_R6: u8 = 0x06; +const RAM_OFFSET_R7: u8 = 0x07; + +const RESET_VALUE_ACC: u8 = 0x00; +const RESET_VALUE_SP: u8 = 0x07; + +const OPCODE_NOP: u8 = 0x00; +const OPCODE_AJMP_P0: u8 = 0x01; +const OPCODE_LJMP: u8 = 0x02; +const OPCODE_AJMP_P1: u8 = 0x21; +const OPCODE_AJMP_P2: u8 = 0x41; +const OPCODE_AJMP_P3: u8 = 0x61; +const OPCODE_JNZ: u8 = 0x70; +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; +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_MOV_AT_DPTR_A: u8 = 0xF0; + +const OP_LUT: [IncompleteOp; u8::max_value() as usize + 1] = { + let mut lut = [IncompleteOp { + opname: Opname::Illegal, + size: 1, + operand1: None, + operand2: None, + operand3: None, + }; u8::max_value() as usize + 1]; + lut[OPCODE_NOP as usize] = IncompleteOp { + opname: Opname::Nop, + size: 1, + operand1: None, + operand2: None, + operand3: None, + }; + lut[OPCODE_AJMP_P0 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(0)), + operand2: None, + operand3: None, + }; + lut[OPCODE_LJMP as usize] = IncompleteOp { + opname: Opname::Ljmp, + size: 3, + operand1: Some(IncompleteOperand::Addr16), + operand2: None, + operand3: None, + }; + lut[OPCODE_AJMP_P1 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(1)), + operand2: None, + operand3: None, + }; + lut[OPCODE_AJMP_P2 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(2)), + operand2: None, + operand3: None, + }; + lut[OPCODE_AJMP_P3 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(3)), + operand2: None, + operand3: None, + }; + lut[OPCODE_JNZ as usize] = IncompleteOp { + opname: Opname::Jnz, + size: 2, + operand1: Some(IncompleteOperand::Reladdr), + operand2: None, + operand3: None, + }; + lut[OPCODE_MOV_A_DATA as usize] = IncompleteOp { + opname: Opname::Mov, + size: 2, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Data), + operand3: None, + }; + lut[OPCODE_MOV_DIRECT_DATA as usize] = IncompleteOp { + opname: Opname::Mov, + size: 3, + operand1: Some(IncompleteOperand::Direct), + operand2: Some(IncompleteOperand::Data), + operand3: None, + }; + lut[OPCODE_SJMP as usize] = IncompleteOp { + opname: Opname::Sjmp, + size: 2, + operand1: Some(IncompleteOperand::Reladdr), + operand2: None, + operand3: None, + }; + lut[OPCODE_AJMP_P4 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(4)), + operand2: None, + operand3: None, + }; + lut[OPCODE_MOV_DPTR_DATA16 as usize] = IncompleteOp { + opname: Opname::Mov16, + size: 3, + operand1: Some(IncompleteOperand::Dptr), + operand2: Some(IncompleteOperand::Data16), + operand3: None, + }; + lut[OPCODE_AJMP_P5 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(5)), + operand2: None, + operand3: None, + }; + lut[OPCODE_PUSH as usize] = IncompleteOp { + opname: Opname::Push, + size: 2, + operand1: Some(IncompleteOperand::Direct), + operand2: None, + operand3: None, + }; + lut[OPCODE_AJMP_P6 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(6)), + operand2: None, + operand3: None, + }; + lut[OPCODE_POP as usize] = IncompleteOp { + opname: Opname::Pop, + size: 2, + operand1: Some(IncompleteOperand::Direct), + operand2: None, + operand3: None, + }; + lut[OPCODE_MOV_A_AT_DPTR as usize] = IncompleteOp { + opname: Opname::MovxFrom, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::AtDptr), + operand3: None, + }; + lut[OPCODE_AJMP_P7 as usize] = IncompleteOp { + opname: Opname::Ajmp, + size: 2, + operand1: Some(IncompleteOperand::Addr11(7)), + operand2: None, + operand3: None, + }; + lut[OPCODE_MOV_A_DIRECT as usize] = IncompleteOp { + opname: Opname::Mov, + size: 2, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Direct), + operand3: None, + }; + lut[OPCODE_MOV_A_INDIRECT_R0 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Indirect(Register::R0)), + operand3: None, + }; + lut[OPCODE_MOV_A_INDIRECT_R1 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Indirect(Register::R1)), + operand3: None, + }; + lut[OPCODE_MOV_A_R0 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R0)), + operand3: None, + }; + lut[OPCODE_MOV_A_R1 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R1)), + operand3: None, + }; + lut[OPCODE_MOV_A_R2 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R2)), + operand3: None, + }; + lut[OPCODE_MOV_A_R3 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R3)), + operand3: None, + }; + lut[OPCODE_MOV_A_R4 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R4)), + operand3: None, + }; + lut[OPCODE_MOV_A_R5 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R5)), + operand3: None, + }; + lut[OPCODE_MOV_A_R6 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R6)), + operand3: None, + }; + lut[OPCODE_MOV_A_R7 as usize] = IncompleteOp { + opname: Opname::Mov, + size: 1, + operand1: Some(IncompleteOperand::Acc), + operand2: Some(IncompleteOperand::Register(Register::R7)), + operand3: None, + }; + lut[OPCODE_MOV_AT_DPTR_A as usize] = IncompleteOp { + opname: Opname::MovxTo, + size: 1, + operand1: Some(IncompleteOperand::AtDptr), + operand2: Some(IncompleteOperand::Acc), + operand3: None, + }; + lut +}; + +impl Register { + fn to_ram_offset(self) -> u8 { + match self { + Register::R0 => RAM_OFFSET_R0, + Register::R1 => RAM_OFFSET_R1, + Register::R2 => RAM_OFFSET_R2, + Register::R3 => RAM_OFFSET_R3, + Register::R4 => RAM_OFFSET_R4, + Register::R5 => RAM_OFFSET_R5, + Register::R6 => RAM_OFFSET_R6, + Register::R7 => RAM_OFFSET_R7, + } + } +} + +impl Operand { + fn size(&self) -> usize { + match self { + Operand::Acc => 0, + 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, + Operand::Addr16(_) => 2, + } + } +} + +impl IncompleteOp { + fn from_u8(data: u8) -> Self { + OP_LUT[data as usize] + } +} + +impl Cpu8051 { + /// Constructor + pub fn new() -> Self { + let mut ram = [0; u8::max_value() as usize + 1]; + ram[RAM_OFFSET_SP as usize] = RESET_VALUE_SP; + ram[RAM_OFFSET_ACC as usize] = RESET_VALUE_ACC; + Self { + pc: 0, + ram, + progmem: ProgramMemory::new(), + extmem: [0xFF; u16::max_value() as usize + 1], + } + } + + pub fn rom(mut self, rom: ProgramMemory) -> Self { + self.progmem = rom; + self + } + + /// Fetch and execute one instruction + pub fn step(&mut self) -> u16 { + let op = self.fetch(); + self.exec(op); + self.pc + } + + /// Get current Program Counter value + pub fn pc(&self) -> u16 { + self.pc + } + + /// Get current instruction + pub fn op(&self) -> Op { + let op = IncompleteOp::from_u8(self.progmem.get(self.pc)); + let mut operands: Vec> = vec![op.operand1, op.operand2, op.operand3] + .iter() + .scan(1, |offset, &x| { + Some(if let Some(incomplete_operand) = x { + let operand = self.fetch_operand(incomplete_operand, *offset); + *offset += operand.size() as u16; + Some(operand) + } else { + None + }) + }) + .collect(); + Op { + opname: op.opname, + size: op.size, + operand3: operands.remove(2), + operand2: operands.remove(1), + operand1: operands.remove(0), + } + } + + /// Increment PC, return the whole operation + fn fetch(&mut self) -> Op { + let op = self.op(); + self.pc += op.size as u16; + op + } + + /// Execute one instruction without incrementing PC + fn exec(&mut self, op: Op) { + match op.opname { + Opname::Nop => (), + Opname::Mov => self.mov( + 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")), + Opname::Sjmp => self.sjmp(op.operand1.expect("SJMP has no operand given")), + Opname::Ajmp => self.ajmp(op.operand1.expect("AJMP has no operand given")), + Opname::Ljmp => self.ljmp(op.operand1.expect("LJMP has no operand given")), + Opname::Jnz => self.jnz(op.operand1.expect("JNZ has no operand given")), + } + } + + /// Get operand by offset, based on meta information + fn fetch_operand(&self, operand: IncompleteOperand, offset: u16) -> Operand { + match operand { + IncompleteOperand::Acc => Operand::Acc, + IncompleteOperand::Direct => Operand::Direct(self.progmem.get(self.pc + offset)), + IncompleteOperand::Data => Operand::Data(self.progmem.get(self.pc + offset)), + IncompleteOperand::Data16 => Operand::Data16({ + let high = self.progmem.get(self.pc + offset); + let low = self.progmem.get(self.pc + offset + 1); + u16::from(high) << 8 & u16::from(low) + }), + IncompleteOperand::Dptr => Operand::Dptr, + IncompleteOperand::AtDptr => Operand::AtDptr, + IncompleteOperand::Indirect(r) => Operand::Indirect(r), + IncompleteOperand::Register(r) => Operand::Register(r), + IncompleteOperand::Reladdr => { + Operand::Reladdr(self.progmem.get(self.pc + offset) as i8) + } + IncompleteOperand::Addr11(high) => Operand::Addr11({ + let low = self.progmem.get(self.pc + offset); + u16::from(high) << 8 & u16::from(low) + }), + IncompleteOperand::Addr16 => Operand::Addr16({ + let high = self.progmem.get(self.pc + offset); + let low = self.progmem.get(self.pc + offset + 1); + u16::from(high) << 8 & u16::from(low) + }), + } + } + + fn mov(&mut self, o1: Operand, o2: Operand) { + let dest = match o1 { + Operand::Acc => RAM_OFFSET_ACC, + Operand::Direct(dir) => dir, + Operand::Indirect(r) => self.ram[r.to_ram_offset() as usize], + Operand::Register(r) => r.to_ram_offset(), + other => panic!("MOV got incompatible first operand \"{:?}\"", other), + }; + let value = match o2 { + Operand::Acc => RAM_OFFSET_ACC, + Operand::Direct(dir) => dir, + Operand::Indirect(r) => self.ram[r.to_ram_offset() as usize], + 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 => { + let dph = self.ram[RAM_OFFSET_DPH as usize]; + let dpl = self.ram[RAM_OFFSET_DPL as usize]; + u16::from(dph) << 8 & u16::from(dpl) + } + 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, operand: Operand) { + match operand { + Operand::Direct(offset) => { + self.ram[RAM_OFFSET_SP as usize] += 1; + let value = self.ram[offset as usize]; + let sp = self.ram[RAM_OFFSET_SP as usize]; + self.ram[sp as usize] = value; + } + other => panic!("PUSH got incompatible operand \"{:?}\"", other), + } + } + + fn pop(&mut self, operand: Operand) { + match operand { + Operand::Direct(offset) => { + let sp = self.ram[RAM_OFFSET_SP as usize]; + self.ram[offset as usize] = self.ram[sp as usize]; + self.ram[RAM_OFFSET_SP as usize] -= 1; + } + other => panic!("POP got incompatible operand \"{:?}\"", other), + } + } + + fn sjmp(&mut self, operand: Operand) { + match operand { + Operand::Reladdr(reladdr) => { + self.pc = (self.pc as i16 + i16::from(reladdr)) as u16; + } + _ => panic!("SJMP got incompatible operand"), + } + } + + fn ajmp(&mut self, operand: Operand) { + match operand { + Operand::Addr11(addr11) => { + assert!(addr11 <= 0x4FFu16); + // Clear 11 low bits of PC and add address, that is within these 11 bits + self.pc = (self.pc & !0x4FFu16) & addr11; + } + _ => panic!("AJMP got incompatible operand"), + } + } + + fn ljmp(&mut self, operand: Operand) { + match operand { + Operand::Addr16(addr) => self.pc = addr, + _ => panic!("LJMP got incompatible operand"), + } + } + + fn jnz(&mut self, operand: Operand) { + match operand { + Operand::Reladdr(reladdr) => { + if self.ram[usize::from(RAM_OFFSET_ACC)] != 0 { + self.pc = (self.pc as i16 + i16::from(reladdr)) as u16; + } + } + _ => panic!("JNZ got incompatible operand"), + } + } +} + +impl fmt::Display for Operand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Operand::Acc => "A".to_string(), + 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), + Operand::Addr16(rel) => format!("{}", rel), + } + ) + } +} + +impl fmt::Display for Op { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut output = String::new(); + output.push_str(&format!("{} ", self.opname)); + 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) + } +} + +impl fmt::Display for Opname { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + 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 => "", + Opname::Sjmp => "SJMP", + } + ) + } +} diff --git a/src/main.rs b/src/main.rs index b23d31d..f43a33e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,12 +7,12 @@ use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use std::time::Duration; -mod core; +mod cpu8051; mod memory; -mod rom; +mod progmem; -use self::core::Core; -use self::rom::Rom; +use self::cpu8051::Cpu8051; +use self::progmem::ProgramMemory; enum Control { Run(bool), @@ -25,16 +25,16 @@ struct BoundController { _rx: Receiver, } -struct BoundCore { +struct BoundEmu { _tx: Sender, rx: Receiver, } -fn new_bound_pair() -> (BoundCore, BoundController) { +fn new_bound_pair() -> (BoundEmu, BoundController) { let (tx_c, rx_c): (Sender, Receiver) = channel(); let (tx_d, rx_d): (Sender, Receiver) = channel(); ( - BoundCore { + BoundEmu { _tx: tx_d, rx: rx_c, }, @@ -76,7 +76,7 @@ fn new_controller(name: &str) -> Result<&dyn Fn(BoundController), i32> { } } -fn core_worker(mut core: Core, bound: BoundCore) { +fn emu_worker(mut cpu: Cpu8051, bound: BoundEmu) { let mut should_stop = false; loop { if should_stop { @@ -86,8 +86,8 @@ fn core_worker(mut core: Core, bound: BoundCore) { } } } else { - println!("0x{:08x}: {}", core.pc(), core.op()); - core.step(); + println!("0x{:08x}: {}", cpu.pc(), cpu.op()); + cpu.step(); if let Ok(msg) = bound.rx.recv_timeout(Duration::from_millis(1000)) { match msg { Control::Run(run) => should_stop = !run, @@ -134,7 +134,7 @@ fn main() { let data = fs::read_to_string(filename).unwrap_or_else(|_| panic!("Unable to read file {}", filename)); - let core = Core::new().rom(match Rom::from_hex(data) { + let cpu = Cpu8051::new().rom(match ProgramMemory::from_hex(data) { Ok(value) => value, Err(err_string) => { println!("{}", err_string); @@ -142,11 +142,11 @@ fn main() { } }); - /* Run core worker and controller */ + /* Run cpu worker and controller */ let (bound_core, bound_controller) = new_bound_pair(); - core_worker(core, bound_core); + emu_worker(cpu, bound_core); thread::spawn(move || { let controller = { diff --git a/src/progmem.rs b/src/progmem.rs new file mode 100644 index 0000000..325eab1 --- /dev/null +++ b/src/progmem.rs @@ -0,0 +1,136 @@ +use crate::memory::Memory; +use std::fmt; + +pub struct ProgramMemory { + array: [u8; u16::max_value() as usize + 1], +} + +impl fmt::Debug for ProgramMemory { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut v: Vec = vec![]; + for (c, x) in self.array.iter().enumerate() { + for hex_char in format!("{:02X}", *x).chars() { + v.push(hex_char); + } + v.push(' '); + if c % 8 == 7 { + v.push('\n'); + } + } + write!(f, "{}", v.iter().collect::()) + } +} + +enum Rectyp { + Data, + EndOfFile, + //ExtendedSegAddr, + //StartSegAddr, + //ExtendedLinearAddr, + //StartLinearAddr, +} + +struct HexLine { + rectyp: Rectyp, + offset: u16, + data: Vec, +} + +impl HexLine { + fn from(s: &str) -> Result { + // The shortest possible sequence is EOF (:00000001FF) + if s.len() < 11 { + return Err(usize::max_value()); + } + if &s[0..1] != ":" { + return Err(0); + } + let offset = match u16::from_str_radix(&s[3..7], 16) { + Ok(value) => value, + Err(_) => return Err(3), + }; + let bytecount = match usize::from_str_radix(&s[1..3], 16) { + Ok(value) => value, + Err(_) => return Err(1), + }; + + // If EOF reached + if &s[7..9] == "01" { + return Ok(HexLine { + rectyp: Rectyp::EndOfFile, + offset, + data: vec![0], + }); + } else if &s[7..9] == "00" { + let mut counter = 9; + let mut data = vec![]; + while counter < s.len() - 2 && counter < (9 + bytecount * 2) { + data.push(match u8::from_str_radix(&s[counter..counter + 2], 16) { + Ok(value) => value, + Err(_) => return Err(counter), + }); + counter += 2; + } + // TODO: check checksum + return Ok(HexLine { + rectyp: Rectyp::Data, + offset, + data, + }); + } + + Err(3) + } +} + +impl ProgramMemory { + /// Empty constructor + pub fn new() -> Self { + Self { + array: [0; u16::max_value() as usize + 1], + } + } + + /// Constructor from hex + pub fn from_hex(hex: String) -> Result { + Self::new().hex(hex) + } + + /// Method for sequential consuming building + pub fn hex(mut self, hex: String) -> Result { + match self.load_hex(hex) { + Ok(_) => Ok(self), + Err(string) => Err(string), + } + } + + /// Method for occasional incremental hex loading + pub fn load_hex(&mut self, hex: String) -> Result<(), String> { + for (linenum, line) in hex.lines().enumerate() { + let hex_line = match HexLine::from(line) { + Ok(value) => value, + Err(charnum) => return Err(format!("ihex parsing error {}:{}", linenum, charnum)), + }; + let offset = hex_line.offset; + match hex_line.rectyp { + Rectyp::Data => { + for (ptr, byte) in hex_line.data.iter().enumerate() { + self.array[ptr + offset as usize] = *byte; + } + } + Rectyp::EndOfFile => {} + } + } + Ok(()) + } +} + +impl Memory for ProgramMemory { + fn get(&self, a: u16) -> u8 { + self.array[a as usize] + } + + fn set(&mut self, a: u16, v: u8) { + self.array[a as usize] = v; + } +} diff --git a/src/rom.rs b/src/rom.rs deleted file mode 100644 index 82775a4..0000000 --- a/src/rom.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::memory::Memory; -use std::fmt; - -pub struct Rom { - array: [u8; u16::max_value() as usize + 1], -} - -impl fmt::Debug for Rom { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut v: Vec = vec![]; - for (c, x) in self.array.iter().enumerate() { - for hex_char in format!("{:02X}", *x).chars() { - v.push(hex_char); - } - v.push(' '); - if c % 8 == 7 { - v.push('\n'); - } - } - write!(f, "{}", v.iter().collect::()) - } -} - -enum Rectyp { - Data, - EndOfFile, - //ExtendedSegAddr, - //StartSegAddr, - //ExtendedLinearAddr, - //StartLinearAddr, -} - -struct HexLine { - rectyp: Rectyp, - offset: u16, - data: Vec, -} - -impl HexLine { - fn from(s: &str) -> Result { - // The shortest possible sequence is EOF (:00000001FF) - if s.len() < 11 { - return Err(usize::max_value()); - } - if &s[0..1] != ":" { - return Err(0); - } - let offset = match u16::from_str_radix(&s[3..7], 16) { - Ok(value) => value, - Err(_) => return Err(3), - }; - let bytecount = match usize::from_str_radix(&s[1..3], 16) { - Ok(value) => value, - Err(_) => return Err(1), - }; - - // If EOF reached - if &s[7..9] == "01" { - return Ok(HexLine { - rectyp: Rectyp::EndOfFile, - offset, - data: vec![0], - }); - } else if &s[7..9] == "00" { - let mut counter = 9; - let mut data = vec![]; - while counter < s.len() - 2 && counter < (9 + bytecount * 2) { - data.push(match u8::from_str_radix(&s[counter..counter + 2], 16) { - Ok(value) => value, - Err(_) => return Err(counter), - }); - counter += 2; - } - // TODO: check checksum - return Ok(HexLine { - rectyp: Rectyp::Data, - offset, - data, - }); - } - - Err(3) - } -} - -impl Rom { - /// Empty constructor - pub fn new() -> Self { - Self { - array: [0; u16::max_value() as usize + 1], - } - } - - /// Constructor from hex - pub fn from_hex(hex: String) -> Result { - Self::new().hex(hex) - } - - /// Method for sequential consuming building - pub fn hex(mut self, hex: String) -> Result { - match self.load_hex(hex) { - Ok(_) => Ok(self), - Err(string) => Err(string), - } - } - - /// Method for occasional incremental hex loading - pub fn load_hex(&mut self, hex: String) -> Result<(), String> { - for (linenum, line) in hex.lines().enumerate() { - let hex_line = match HexLine::from(line) { - Ok(value) => value, - Err(charnum) => return Err(format!("ihex parsing error {}:{}", linenum, charnum)), - }; - let offset = hex_line.offset; - match hex_line.rectyp { - Rectyp::Data => { - for (ptr, byte) in hex_line.data.iter().enumerate() { - self.array[ptr + offset as usize] = *byte; - } - } - Rectyp::EndOfFile => {} - } - } - Ok(()) - } -} - -impl Memory for Rom { - fn get(&self, a: u16) -> u8 { - self.array[a as usize] - } - - fn set(&mut self, a: u16, v: u8) { - self.array[a as usize] = v; - } -} -- cgit v1.2.3