diff --git a/src/chip_definitions.rs b/src/chip_definitions.rs index 65d41c4..12d6218 100644 --- a/src/chip_definitions.rs +++ b/src/chip_definitions.rs @@ -52,3 +52,13 @@ pub const EIND: u16 = 0x03C; pub const SPL: u16 = 0x03D; pub const SPH: u16 = 0x03E; pub const SREG: u16 = 0x03F; + +pub const USARTC0_DATA: u16 = 0x8A0; +pub const USARTC0_STATUS: u16 = 0x8A1; +pub const USARTC0_CTRLA: u16 = 0x8A3; +pub const USARTC0_CTRLB: u16 = 0x8A4; +pub const USARTC0_CTRLC: u16 = 0x8A5; +pub const USARTC0_BAUDCTRLA: u16 = 0x8A6; +pub const USARTC0_BAUDCTRLB: u16 = 0x8A7; + +pub const OSC_STATUS: u16 = 0x051; \ No newline at end of file diff --git a/src/cpu.rs b/src/cpu.rs index adc00c5..ca4b92e 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -92,7 +92,7 @@ impl CPU { } fn set_clear_flag(&mut self, flag: StatusFlag, test: bool) { - print!("[{:?}->{}] ", flag, test); + print!("[{}->{}] ", flag, test); if test { self.set_flag(flag); } else { @@ -117,16 +117,49 @@ impl CPU { self.registers[r.as_usize()] = v; } - fn push(&mut self, ram: &mut [u8], val: u8) { - let sp = self.get_sp(&ram); - ram[sp as usize] = val; - self.set_sp(ram, sp.wrapping_sub(1)); + fn ram_write(&self, ram: &mut [u8], addr: u16, val: u8) -> Result<(), CPUError> { + print!("[RAMW:{:04X}={:02X}] ", addr, val); + if addr as usize >= ram.len() { + Err(CPUError::OutOfBoundsException) + } else { + // TODO: Hooks + if addr == chip_definitions::USARTC0_DATA { + panic!("Tring to write {} via USART!", val); + } + ram[addr as usize] = val; + Ok(()) + } } - fn pop(&mut self, ram: &mut [u8]) -> u8 { + fn ram_read(&self, ram: &[u8], addr: u16) -> Result { + print!("[RAMR:{:04X}] ", addr); + if addr as usize >= ram.len() { + Err(CPUError::OutOfBoundsException) + } else { + // TODO: Hooks + if addr == chip_definitions::USARTC0_DATA { + panic!("Tring to read from USART!"); + } else if addr == chip_definitions::USARTC0_STATUS { + panic!("Trying to read USART flags!"); + } else if addr == chip_definitions::OSC_STATUS { + // HACK: Osci is set right.. + return Ok(2); + } + Ok(ram[addr as usize]) + } + } + + fn push(&mut self, ram: &mut [u8], val: u8) -> Result<(), CPUError> { + let sp = self.get_sp(&ram); + self.ram_write(ram, sp, val)?; + self.set_sp(ram, sp.wrapping_sub(1)); + Ok(()) + } + + fn pop(&mut self, ram: &mut [u8]) -> Result { let sp = self.get_sp(&ram); self.set_sp(ram, sp.wrapping_add(1)); - ram[sp.wrapping_add(1) as usize] + self.ram_read(ram, sp.wrapping_add(1)) } fn update_flags(&mut self, mode: FlagUpdateMode, rd: u8, rr: u8, s: u8) { @@ -175,7 +208,7 @@ impl CPU { Ok(v) => v, Err(e) => return Err(CPUError::DecodingError(e)), }; - print!("CPU: pc={:06X} sp={:04X} Fetch: {:?} -> ", self.pc, self.get_sp(ram), ins); + print!("CPU: pc={:06X} sp={:04X} Fetch: {: <40} -> ", self.pc, self.get_sp(ram), format!("{}", ins)); self.pc += (ins.size() / 2) as u32; @@ -229,10 +262,7 @@ impl CPU { }, IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _), }; - if addr as usize >= ram.len() { - return Err(CPUError::OutOfBoundsException); - } - ram[addr as usize] = self.get_register(src_reg); + self.ram_write(ram, addr, self.get_register(src_reg))?; }, Instruction::LD(ref dst_reg, ref ptr, ref inc_mode) => { let base = self.get_register_pair(ptr); @@ -248,10 +278,7 @@ impl CPU { }, IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _), }; - if addr as usize >= ram.len() { - return Err(CPUError::OutOfBoundsException); - } - let v = ram[addr as usize]; + let v = self.ram_read(ram, addr)?; self.set_register(dst_reg, v); }, Instruction::ELPM(ref dst_reg, ref inc_mode) => { @@ -283,38 +310,39 @@ impl CPU { }, Instruction::OUT(ref addr, ref val) => { let val = self.get_register(val); - ram[*addr as usize] = val; + self.ram_write(ram, *addr, val)?; }, Instruction::IN(ref reg, ref addr) => { - self.set_register(reg, ram[*addr as usize]); + let v = self.ram_read(ram, *addr)?; + self.set_register(reg, v); } Instruction::CALL(ref addr) => { let ret_to = self.pc; - self.push(ram, ((ret_to >> 16) & 0xFF) as u8); - self.push(ram, ((ret_to >> 8) & 0xFF) as u8); - self.push(ram, (ret_to & 0xFF) as u8); + self.push(ram, ((ret_to >> 16) & 0xFF) as u8)?; + self.push(ram, ((ret_to >> 8) & 0xFF) as u8)?; + self.push(ram, (ret_to & 0xFF) as u8)?; self.pc = *addr; }, Instruction::RCALL(ref addr) => { let ret_to = self.pc; - self.push(ram, ((ret_to >> 16) & 0xFF) as u8); - self.push(ram, ((ret_to >> 8) & 0xFF) as u8); - self.push(ram, (ret_to & 0xFF) as u8); + self.push(ram, ((ret_to >> 16) & 0xFF) as u8)?; + self.push(ram, ((ret_to >> 8) & 0xFF) as u8)?; + self.push(ram, (ret_to & 0xFF) as u8)?; self.pc = (self.pc as i32 + *addr as i32) as u32; }, Instruction::RET => { - let mut ret_to = self.pop(ram) as u32; - ret_to += (self.pop(ram) as u32) << 8; - ret_to += (self.pop(ram) as u32) << 16; + let mut ret_to = self.pop(ram)? as u32; + ret_to += (self.pop(ram)? as u32) << 8; + ret_to += (self.pop(ram)? as u32) << 16; self.pc = ret_to as _; }, Instruction::POP(ref reg) => { - let v = self.pop(ram); + let v = self.pop(ram)?; self.registers[reg.as_usize()] = v; }, Instruction::PUSH(ref reg) => { let v = self.registers[reg.as_usize()]; - self.push(ram, v); + self.push(ram, v)?; }, Instruction::SUBI(ref reg, ref v) => { let v = self.registers[reg.as_usize()].wrapping_sub(*v); @@ -430,16 +458,18 @@ impl CPU { self.set_clear_flag(StatusFlag::Zero, v == 0); }, Instruction::STS16(ref addr, ref r) => { - ram[*addr as usize] = self.get_register(r); + self.ram_write(ram, *addr, self.get_register(r))?; }, Instruction::STS8(ref addr, ref r) => { - ram[*addr as usize] = self.get_register(r); + self.ram_write(ram, *addr as u16, self.get_register(r))?; }, Instruction::LDS16(ref r, ref addr) => { - self.set_register(r, ram[*addr as usize]); + let v = self.ram_read(ram, *addr)?; + self.set_register(r, v); }, Instruction::LDS8(ref r, ref addr) => { - self.set_register(r, ram[*addr as usize]); + let v = self.ram_read(ram, *addr as u16)?; + self.set_register(r, v); }, Instruction::LSL(ref r) => { let v = self.get_register(r); diff --git a/src/decoder.rs b/src/decoder.rs index 3d5641f..ff86efd 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -1,6 +1,8 @@ use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, IORegister, StatusFlag, PC}; +use std::fmt; + #[derive(Debug)] pub enum DecodingError { UndefinedInstruction(u16), @@ -101,6 +103,97 @@ pub enum Instruction { XCH(GeneralPurposeRegister), } + +impl fmt::Display for Instruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Instruction::ADC(ref r, ref d) => write!(f, "ADC {} {}", r, d), + Instruction::ADD(ref r, ref d) => write!(f, "ADD {} {}", r, d), + Instruction::ADIW(ref r, v) => write!(f, "ADIW {} {}", r, v), + Instruction::AND(ref r, ref d) => write!(f, "AND {} {}", r, d), + Instruction::ANDI(ref r, v) => write!(f, "ANDI {} {}", r, v), + Instruction::ASR(ref r) => write!(f, "ASR {}", r), + Instruction::BLD(ref r, v) => write!(f, "BLD {} {}", r, v), + Instruction::BREAK => write!(f, "BREAK"), + Instruction::BR_IF(rel, ref flag, tgt) => write!(f, "BR_IF {}, {:?}=={}", rel, flag, tgt), + Instruction::BST(ref r, v) => write!(f, "BST {} {}", r, v), + Instruction::CALL(pc) => write!(f, "CALL {:06X}", pc), + Instruction::CBI(ref ior, v) => write!(f, "CBI {} {}", ior, v), + Instruction::CLR_FLAG(flag) => write!(f, "CLR_FLAG {:?}", flag), + Instruction::CLR(ref r) => write!(f, "CLR {}", r), + Instruction::COM(ref r) => write!(f, "COM {}", r), + Instruction::CP(ref r, ref d) => write!(f, "CP {} {}", r, d), + Instruction::CPC(ref r, ref d) => write!(f, "CPC {} {}", r, d), + Instruction::CPI(ref r, v) => write!(f, "CPI {} {}", r, v), + Instruction::CPSE(ref r, ref d) => write!(f, "CPSE {} {}", r, d), + Instruction::DEC(ref r) => write!(f, "DEC {}", r), + Instruction::EICALL => write!(f, "EICALL"), + Instruction::EIJMP => write!(f, "EIJMP"), + Instruction::ELPM(ref r, ref mode) => write!(f, "ELPM[{:?}] {}", mode, r), + Instruction::EOR(ref r, ref d) => write!(f, "EOR {} {}", r, d), + Instruction::FMUL(ref r, ref d) => write!(f, "FMUL {} {}", r, d), + Instruction::FMULS(ref r, ref d) => write!(f, "FMULS {} {}", r, d), + Instruction::FMULSU(ref r, ref d) => write!(f, "FMULSU {} {}", r, d), + Instruction::ICALL => write!(f, "ICALL"), + Instruction::IJMP => write!(f, "IJMP"), + Instruction::IN(ref r, ref ior) => write!(f, "IN {}, {}", r, ior), + Instruction::INC(ref r) => write!(f, "INC {}", r), + Instruction::JMP(pc) => write!(f, "JMP {:06X}", pc), + Instruction::LAC(ref r) => write!(f, "LAC {}", r), + Instruction::LAS(ref r) => write!(f, "LAS {}", r), + Instruction::LAT(ref r) => write!(f, "LAT {}", r), + Instruction::LD(ref r, ref d, ref mode) => write!(f, "LD {}, [{} {:?}]", r, d, mode), + Instruction::LDI(ref r, v) => write!(f, "LDI {} {}", r, v), + Instruction::LDS8(ref r, v) => write!(f, "LDS8 {} {}", r, v), + Instruction::LDS16(ref r, v) => write!(f, "LDS16 {} {}", r, v), + Instruction::LPM(ref r, ref mode) => write!(f, "LPM {} {:?}", r, mode), + Instruction::LSL(ref r) => write!(f, "LSL {}", r), + Instruction::LSR(ref r) => write!(f, "LSR {}", r), + Instruction::MOV(ref r, ref d) => write!(f, "MOV {}, {}", r, d), + Instruction::MOVW(ref r, ref d) => write!(f, "MOVW {}, {}", r, d), + Instruction::MUL(ref r, ref d) => write!(f, "MUL {} {}", r, d), + Instruction::MULS(ref r, ref d) => write!(f, "MULS {} {}", r, d), + Instruction::MULSU(ref r, ref d) => write!(f, "MULSU {} {}", r, d), + Instruction::NEG(ref r) => write!(f, "NEG {}", r), + Instruction::NOP => write!(f, "NOP"), + Instruction::OR(ref r, ref d) => write!(f, "OR {} {}", r, d), + Instruction::ORI(ref r, v) => write!(f, "ORI {} {}", r, v), + Instruction::OUT(ref ior, ref d) => write!(f, "OUT {}, {}", ior, d), + Instruction::POP(ref r) => write!(f, "POP {}", r), + Instruction::PUSH(ref r) => write!(f, "PUSH {}", r), + Instruction::RCALL(rv) => write!(f, "RCALL {:X}", rv), + Instruction::RET => write!(f, "RET"), + Instruction::RETI => write!(f, "RETI"), + Instruction::RJMP(rv) => write!(f, "RJMP {:X}", rv), + Instruction::ROL(ref r) => write!(f, "ROL {}", r), + Instruction::ROR(ref r) => write!(f, "ROR {}", r), + Instruction::SBC(ref r, ref d) => write!(f, "SBC {} {}", r, d), + Instruction::SBCI(ref r, v) => write!(f, "SBCI {} {}", r, v), + Instruction::SBI(ref ior, v) => write!(f, "SBI {} {}", ior, v), + Instruction::SBIC(ref ior, v) => write!(f, "SBIC {} {}", ior, v), + Instruction::SBIS(ref ior, v) => write!(f, "SBIS {} {}", ior, v), + Instruction::SBIW(ref r, v) => write!(f, "SBIW {} {}", r, v), + Instruction::SBR(ref r, v) => write!(f, "SBR {} {}", r, v), + Instruction::SBRC(ref r, v) => write!(f, "SBRC {} {}", r, v), + Instruction::SBRS(ref r, v) => write!(f, "SBRS {} {}", r, v), + Instruction::SER(ref r) => write!(f, "SER {}", r), + Instruction::SET_FLAG(flag) => write!(f, "SET_FLAG {:?}", flag), + Instruction::SLEEP => write!(f, "SLEEP"), + Instruction::SPM(ref mode) => write!(f, "SPM {:?}", mode), + Instruction::ST(ref r, ref d, ref mode) => write!(f, "ST [{} {:?}], {}", r, mode, d), + Instruction::STS8(v, ref r) => write!(f, "STS8 {}, {}", v, r), + Instruction::STS16(v, ref r) => write!(f, "STS16 {}, {}", v, r), + Instruction::SUB(ref r, ref d) => write!(f, "SUB {} {}", r, d), + Instruction::SUBI(ref r, v) => write!(f, "SUBI {} {}", r, v), + Instruction::SWAP(ref r) => write!(f, "SWAP {}", r), + Instruction::TST(ref r) => write!(f, "TST {}", r), + Instruction::WDR => write!(f, "WDR"), + Instruction::XCH(ref r) => write!(f, "XCH {}", r), + } + } +} + + impl Instruction { // TODO: There are more // LDS32 STS32 @@ -435,7 +528,7 @@ pub fn decode(data: &[u8]) -> Result { 0b1111_0100_0000_0000 | 0b1111_0000_0000_0000 => { let flag_should_be_set = ((v >> 10) & 1) == 0; let flag = StatusFlag::try_from_idx((v & 0b111) as u8).unwrap(); - let mut k = (v >> 3) as i8; + let mut k = ((v >> 3) & 0b0111_1111) as i8; if k >= (1 << 6) { k = k.wrapping_sub(1 << 7); diff --git a/src/main.rs b/src/main.rs index cf3361a..33ce509 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,9 +15,24 @@ fn main() { let mut rom = read_file("rom.bin").unwrap(); let mut ram = [0u8; 8 * 1024 + 8 * 1024]; let mut cpu = cpu::CPU::new(); + + // Patch some loops cause we don't emulate the devices yet. + // (Wait for OSC_STATUS - currently fixed by setting the reg) + // rom[2 * 0x177] = 0x00; + // rom[2 * 0x177 + 1] = 0x00; + + // Some call (vprintf), to limit the bug surface? With this it crashes + // differently, so no real alternative :( + /* + rom[0x1d58] = 0x00; + rom[0x1d58 + 1] = 0x00; + rom[0x1d58 + 2] = 0x00; + rom[0x1d58 + 3] = 0x00; + */ + for _ in 0..280000 { let r = cpu.step(&mut rom, &mut ram); - print!("[{:02X} {:02X}] ", cpu.registers[28], cpu.registers[29]); + print!("[r28={:02X} r29={:02X}] ", cpu.registers[28], cpu.registers[29]); println!("{:?}", r); match r { Err(cpu::CPUError::OutOfBoundsException) => break, diff --git a/src/regs.rs b/src/regs.rs index e8b02c5..a5037f1 100644 --- a/src/regs.rs +++ b/src/regs.rs @@ -123,6 +123,14 @@ impl PartialEq for GeneralPurposeRegister { } } + +impl fmt::Display for GeneralPurposeRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "R{}", self.0) + } +} + + // Mostly the same as above, but we want to make it a different type. // type GeneralPurposeRegisterPair = struct(u8); #[derive(Debug)] @@ -159,6 +167,13 @@ impl GeneralPurposeRegisterPair { } } +impl fmt::Display for GeneralPurposeRegisterPair { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "R{}:R{}", self.high(), self.low()) + } +} + + pub type PC = u32; // TODO: Struct :)