Mini-disassembler, fixed fatal bug in branch instr

This commit is contained in:
Kevin Hamacher 2018-02-11 12:16:01 +01:00
parent 6470a28ad3
commit 73499e1b76
5 changed files with 198 additions and 35 deletions

View File

@ -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;

View File

@ -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<u8, CPUError> {
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<u8, CPUError> {
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);

View File

@ -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<Instruction, DecodingError> {
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);

View File

@ -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,

View File

@ -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 :)