Rustfmt ahoi
This commit is contained in:
parent
a5e24ddf89
commit
d96f4b9ad5
@ -7,7 +7,6 @@ pub struct Chip {
|
|||||||
pub cpu: CPU,
|
pub cpu: CPU,
|
||||||
pub rom: Box<[u8]>,
|
pub rom: Box<[u8]>,
|
||||||
pub ram: Box<[u8]>,
|
pub ram: Box<[u8]>,
|
||||||
|
|
||||||
// TODO: List of devices
|
// TODO: List of devices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
221
src/cpu.rs
221
src/cpu.rs
@ -3,14 +3,13 @@
|
|||||||
|
|
||||||
use decoder;
|
use decoder;
|
||||||
use decoder::{IncrementMode, Instruction};
|
use decoder::{IncrementMode, Instruction};
|
||||||
use regs::{StatusFlag, GeneralPurposeRegister, GeneralPurposeRegisterPair};
|
use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, StatusFlag};
|
||||||
use chip_definitions;
|
use chip_definitions;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use slog;
|
use slog;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CPUError {
|
pub enum CPUError {
|
||||||
UnimplementedInstruction,
|
UnimplementedInstruction,
|
||||||
@ -36,10 +35,14 @@ pub struct CPU {
|
|||||||
logger: slog::Logger,
|
logger: slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for CPU {
|
impl fmt::Display for CPU {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "CPU @ 0x{:X} (file offset = 0x{:X}) ", self.pc, 2 * self.pc)?;
|
write!(
|
||||||
|
f,
|
||||||
|
"CPU @ 0x{:X} (file offset = 0x{:X}) ",
|
||||||
|
self.pc,
|
||||||
|
2 * self.pc
|
||||||
|
)?;
|
||||||
write!(f, "SREG: 0x{:02X}: ", self.sreg)?;
|
write!(f, "SREG: 0x{:02X}: ", self.sreg)?;
|
||||||
for i in 0..7 {
|
for i in 0..7 {
|
||||||
let t = self.sreg & (1 << i);
|
let t = self.sreg & (1 << i);
|
||||||
@ -66,12 +69,13 @@ impl CPU {
|
|||||||
registers: [0u8; 32],
|
registers: [0u8; 32],
|
||||||
pc: 0, // Reset vector
|
pc: 0, // Reset vector
|
||||||
sreg: 0, // Uninitialized as well
|
sreg: 0, // Uninitialized as well
|
||||||
logger: logger
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sp(&self, mem: &[u8]) -> u16 {
|
pub fn get_sp(&self, mem: &[u8]) -> u16 {
|
||||||
mem[chip_definitions::IOAdress::SPL as usize] as u16 | ((mem[chip_definitions::IOAdress::SPH as usize] as u16) << 8)
|
mem[chip_definitions::IOAdress::SPL as usize] as u16
|
||||||
|
| ((mem[chip_definitions::IOAdress::SPH as usize] as u16) << 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sp(&self, mem: &mut [u8], val: u16) {
|
fn set_sp(&self, mem: &mut [u8], val: u16) {
|
||||||
@ -79,7 +83,6 @@ impl CPU {
|
|||||||
mem[chip_definitions::IOAdress::SPH as usize] = (val >> 8) as u8;
|
mem[chip_definitions::IOAdress::SPH as usize] = (val >> 8) as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn test_flag(&self, flag: StatusFlag) -> bool {
|
fn test_flag(&self, flag: StatusFlag) -> bool {
|
||||||
(self.sreg & (flag as u8)) > 0
|
(self.sreg & (flag as u8)) > 0
|
||||||
}
|
}
|
||||||
@ -124,12 +127,19 @@ impl CPU {
|
|||||||
Err(CPUError::OutOfBoundsException)
|
Err(CPUError::OutOfBoundsException)
|
||||||
} else {
|
} else {
|
||||||
if addr < 0x2000 {
|
if addr < 0x2000 {
|
||||||
if addr != chip_definitions::IOAdress::SPH as u16 && addr != chip_definitions::IOAdress::SPL as u16 {
|
if addr != chip_definitions::IOAdress::SPH as u16
|
||||||
|
&& addr != chip_definitions::IOAdress::SPL as u16
|
||||||
|
{
|
||||||
// info!(self.logger, "Writing to IOR: {:04X} = {:02X}", addr, val);
|
// info!(self.logger, "Writing to IOR: {:04X} = {:02X}", addr, val);
|
||||||
}
|
}
|
||||||
if addr == chip_definitions::IOAdress::USARTC0_DATA as u16 {
|
if addr == chip_definitions::IOAdress::USARTC0_DATA as u16 {
|
||||||
// print!("USART_OUT:{: <3} ({}) ", val, (val as char).escape_debug());
|
// print!("USART_OUT:{: <3} ({}) ", val, (val as char).escape_debug());
|
||||||
info!(self.logger, "UART output: {: <3} ({})", val, (val as char).escape_debug());
|
info!(
|
||||||
|
self.logger,
|
||||||
|
"UART output: {: <3} ({})",
|
||||||
|
val,
|
||||||
|
(val as char).escape_debug()
|
||||||
|
);
|
||||||
} /* else if addr == chip_definitions::IOAdress::SPL as u16 {
|
} /* else if addr == chip_definitions::IOAdress::SPL as u16 {
|
||||||
|
|
||||||
} else if addr == chip_definitions::IOAdress::SPH as u16 {
|
} else if addr == chip_definitions::IOAdress::SPH as u16 {
|
||||||
@ -205,7 +215,9 @@ impl CPU {
|
|||||||
// HACK: Osci is set right..
|
// HACK: Osci is set right..
|
||||||
return Ok(0x02);
|
return Ok(0x02);
|
||||||
} else if addr < 0x2000 {
|
} else if addr < 0x2000 {
|
||||||
if addr != chip_definitions::IOAdress::SPH as u16 && addr != chip_definitions::IOAdress::SPL as u16 {
|
if addr != chip_definitions::IOAdress::SPH as u16
|
||||||
|
&& addr != chip_definitions::IOAdress::SPL as u16
|
||||||
|
{
|
||||||
info!(self.logger, "Reading from IOR: {:04X}", addr);
|
info!(self.logger, "Reading from IOR: {:04X}", addr);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -288,7 +300,10 @@ impl CPU {
|
|||||||
let add_carry = (d & r) | (r & !result) | (!result & d);
|
let add_carry = (d & r) | (r & !result) | (!result & d);
|
||||||
self.set_clear_flag(StatusFlag::HalfCarry, add_carry & 0b1000 != 0);
|
self.set_clear_flag(StatusFlag::HalfCarry, add_carry & 0b1000 != 0);
|
||||||
self.set_clear_flag(StatusFlag::Carry, add_carry & 0b1000_0000 != 0);
|
self.set_clear_flag(StatusFlag::Carry, add_carry & 0b1000_0000 != 0);
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, ((d & r & !result) | (!d & !r & result)) & 0x80 == 0x80);
|
self.set_clear_flag(
|
||||||
|
StatusFlag::TwosComplementOverflow,
|
||||||
|
((d & r & !result) | (!d & !r & result)) & 0x80 == 0x80,
|
||||||
|
);
|
||||||
self.update_flags_zns_8(result);
|
self.update_flags_zns_8(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +311,10 @@ impl CPU {
|
|||||||
let sub_carry = (!d & r) | (r & result) | (result & !d);
|
let sub_carry = (!d & r) | (r & result) | (result & !d);
|
||||||
self.set_clear_flag(StatusFlag::HalfCarry, sub_carry & 0b1000 != 0);
|
self.set_clear_flag(StatusFlag::HalfCarry, sub_carry & 0b1000 != 0);
|
||||||
self.set_clear_flag(StatusFlag::Carry, sub_carry & 0b1000_0000 != 0);
|
self.set_clear_flag(StatusFlag::Carry, sub_carry & 0b1000_0000 != 0);
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, ((d & !r & !result) | (!d & r & result)) & 0x80 == 0x80);
|
self.set_clear_flag(
|
||||||
|
StatusFlag::TwosComplementOverflow,
|
||||||
|
((d & !r & !result) | (!d & r & result)) & 0x80 == 0x80,
|
||||||
|
);
|
||||||
self.update_flags_zns_8(result);
|
self.update_flags_zns_8(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +331,10 @@ impl CPU {
|
|||||||
let sub_carry = (!d & r) | (r & result) | (result & !d);
|
let sub_carry = (!d & r) | (r & result) | (result & !d);
|
||||||
self.set_clear_flag(StatusFlag::HalfCarry, sub_carry & 0b1000 != 0);
|
self.set_clear_flag(StatusFlag::HalfCarry, sub_carry & 0b1000 != 0);
|
||||||
self.set_clear_flag(StatusFlag::Carry, sub_carry & 0b1000_0000 != 0);
|
self.set_clear_flag(StatusFlag::Carry, sub_carry & 0b1000_0000 != 0);
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, ((d & !r & !result) | (!d & r & result)) & 0x80 == 0x80);
|
self.set_clear_flag(
|
||||||
|
StatusFlag::TwosComplementOverflow,
|
||||||
|
((d & !r & !result) | (!d & r & result)) & 0x80 == 0x80,
|
||||||
|
);
|
||||||
self.update_flags_Rzns(result);
|
self.update_flags_Rzns(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +376,13 @@ impl CPU {
|
|||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => return Err(CPUError::DecodingError(e)),
|
Err(e) => return Err(CPUError::DecodingError(e)),
|
||||||
};
|
};
|
||||||
debug!(self.logger, "CPU: pc={:06X} sp={:04X} Fetch: {: <40}", self.pc, self.get_sp(ram), format!("{}", ins));
|
debug!(
|
||||||
|
self.logger,
|
||||||
|
"CPU: pc={:06X} sp={:04X} Fetch: {: <40}",
|
||||||
|
self.pc,
|
||||||
|
self.get_sp(ram),
|
||||||
|
format!("{}", ins)
|
||||||
|
);
|
||||||
|
|
||||||
self.pc += (ins.size() / 2) as u32;
|
self.pc += (ins.size() / 2) as u32;
|
||||||
|
|
||||||
@ -365,12 +392,12 @@ impl CPU {
|
|||||||
Instruction::CLR(ref r) => {
|
Instruction::CLR(ref r) => {
|
||||||
self.set_register(r, 0);
|
self.set_register(r, 0);
|
||||||
self.update_flags_znv0s(0);
|
self.update_flags_znv0s(0);
|
||||||
},
|
}
|
||||||
Instruction::EOR(ref d, ref r) => {
|
Instruction::EOR(ref d, ref r) => {
|
||||||
self.registers[d.as_usize()] ^= self.registers[r.as_usize()];
|
self.registers[d.as_usize()] ^= self.registers[r.as_usize()];
|
||||||
let r = self.registers[d.as_usize()];
|
let r = self.registers[d.as_usize()];
|
||||||
self.update_flags_znv0s(r);
|
self.update_flags_znv0s(r);
|
||||||
},
|
}
|
||||||
Instruction::LDI(ref r, v) => self.set_register(r, v),
|
Instruction::LDI(ref r, v) => self.set_register(r, v),
|
||||||
Instruction::SER(ref r) => self.set_register(r, 0xFF),
|
Instruction::SER(ref r) => self.set_register(r, 0xFF),
|
||||||
Instruction::RJMP(v) => {
|
Instruction::RJMP(v) => {
|
||||||
@ -379,18 +406,18 @@ impl CPU {
|
|||||||
info!(self.logger, "HALTED ");
|
info!(self.logger, "HALTED ");
|
||||||
return Err(CPUError::Exit);
|
return Err(CPUError::Exit);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Instruction::CLR_FLAG(v) => self.clear_flag(v),
|
Instruction::CLR_FLAG(v) => self.clear_flag(v),
|
||||||
Instruction::SET_FLAG(v) => self.set_flag(v),
|
Instruction::SET_FLAG(v) => self.set_flag(v),
|
||||||
Instruction::CPI(ref r, v) => {
|
Instruction::CPI(ref r, v) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
self.update_flags_sub_zns(rv.wrapping_sub(v), rv, v);
|
self.update_flags_sub_zns(rv.wrapping_sub(v), rv, v);
|
||||||
},
|
}
|
||||||
Instruction::CP(ref r, ref i) => {
|
Instruction::CP(ref r, ref i) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let iv = self.get_register(i);
|
let iv = self.get_register(i);
|
||||||
self.update_flags_sub_zns(rv.wrapping_sub(iv), rv, iv);
|
self.update_flags_sub_zns(rv.wrapping_sub(iv), rv, iv);
|
||||||
},
|
}
|
||||||
Instruction::CPC(ref d, ref r) => {
|
Instruction::CPC(ref d, ref r) => {
|
||||||
let rd: u8 = self.get_register(d);
|
let rd: u8 = self.get_register(d);
|
||||||
let rr: u8 = self.get_register(r);
|
let rr: u8 = self.get_register(r);
|
||||||
@ -402,12 +429,12 @@ impl CPU {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.update_flags_sub_Rzns(s, rd, rr);
|
self.update_flags_sub_Rzns(s, rd, rr);
|
||||||
},
|
}
|
||||||
Instruction::BR_IF(offset, flag, test) => {
|
Instruction::BR_IF(offset, flag, test) => {
|
||||||
if self.test_flag(flag) == test {
|
if self.test_flag(flag) == test {
|
||||||
self.pc = self.pc.wrapping_add(offset as _);
|
self.pc = self.pc.wrapping_add(offset as _);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Instruction::ST(ref ptr, ref src_reg, ref inc_mode) => {
|
Instruction::ST(ref ptr, ref src_reg, ref inc_mode) => {
|
||||||
let base = self.get_register_pair(ptr);
|
let base = self.get_register_pair(ptr);
|
||||||
let addr = match *inc_mode {
|
let addr = match *inc_mode {
|
||||||
@ -415,15 +442,15 @@ impl CPU {
|
|||||||
IncrementMode::PreDecrement => {
|
IncrementMode::PreDecrement => {
|
||||||
self.set_register_pair(ptr, base.wrapping_sub(1));
|
self.set_register_pair(ptr, base.wrapping_sub(1));
|
||||||
base.wrapping_sub(1)
|
base.wrapping_sub(1)
|
||||||
},
|
}
|
||||||
IncrementMode::PostIncrement => {
|
IncrementMode::PostIncrement => {
|
||||||
self.set_register_pair(ptr, base.wrapping_add(1));
|
self.set_register_pair(ptr, base.wrapping_add(1));
|
||||||
base
|
base
|
||||||
},
|
}
|
||||||
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
||||||
};
|
};
|
||||||
self.ram_write(ram, addr, 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) => {
|
Instruction::LD(ref dst_reg, ref ptr, ref inc_mode) => {
|
||||||
let base = self.get_register_pair(ptr);
|
let base = self.get_register_pair(ptr);
|
||||||
if ptr.low() == 26 && ram[chip_definitions::IOAdress::RAMPX as usize] > 0 {
|
if ptr.low() == 26 && ram[chip_definitions::IOAdress::RAMPX as usize] > 0 {
|
||||||
@ -438,41 +465,45 @@ impl CPU {
|
|||||||
IncrementMode::PreDecrement => {
|
IncrementMode::PreDecrement => {
|
||||||
self.set_register_pair(ptr, base.wrapping_sub(1));
|
self.set_register_pair(ptr, base.wrapping_sub(1));
|
||||||
base.wrapping_sub(1)
|
base.wrapping_sub(1)
|
||||||
},
|
}
|
||||||
IncrementMode::PostIncrement => {
|
IncrementMode::PostIncrement => {
|
||||||
self.set_register_pair(ptr, base.wrapping_add(1));
|
self.set_register_pair(ptr, base.wrapping_add(1));
|
||||||
base
|
base
|
||||||
},
|
}
|
||||||
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
||||||
};
|
};
|
||||||
let v = self.ram_read(ram, addr)?;
|
let v = self.ram_read(ram, addr)?;
|
||||||
self.set_register(dst_reg, v);
|
self.set_register(dst_reg, v);
|
||||||
},
|
}
|
||||||
Instruction::ELPM(ref dst_reg, ref inc_mode) => {
|
Instruction::ELPM(ref dst_reg, ref inc_mode) => {
|
||||||
|
|
||||||
let Zb = self.get_register_pair(&30u8.into());
|
let Zb = self.get_register_pair(&30u8.into());
|
||||||
// TODO: Only use required bits, other read as zero (according to datasheet)
|
// TODO: Only use required bits, other read as zero (according to datasheet)
|
||||||
let Z =
|
let Z =
|
||||||
Zb as usize |
|
Zb as usize | (ram[chip_definitions::IOAdress::RAMPZ as usize] as usize) << 16;
|
||||||
(ram[chip_definitions::IOAdress::RAMPZ as usize] as usize) << 16
|
|
||||||
;
|
|
||||||
match *inc_mode {
|
match *inc_mode {
|
||||||
IncrementMode::PostIncrement => {
|
IncrementMode::PostIncrement => {
|
||||||
self.set_register_pair(&30u8.into(), Zb.wrapping_add(1));
|
self.set_register_pair(&30u8.into(), Zb.wrapping_add(1));
|
||||||
ram[chip_definitions::IOAdress::RAMPZ as usize] = (Z.wrapping_add(1) >> 16) as u8;
|
ram[chip_definitions::IOAdress::RAMPZ as usize] =
|
||||||
},
|
(Z.wrapping_add(1) >> 16) as u8;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// This instruction does only support None + PostIncrement
|
// This instruction does only support None + PostIncrement
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
if Z >= rom.len() {
|
if Z >= rom.len() {
|
||||||
warn!(self.logger, "ELPM OOB: RAMPZ={:02X} Z={:04X} len={:06X} ", Z >> 16, Zb, rom.len());
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"ELPM OOB: RAMPZ={:02X} Z={:04X} len={:06X} ",
|
||||||
|
Z >> 16,
|
||||||
|
Zb,
|
||||||
|
rom.len()
|
||||||
|
);
|
||||||
// return Err(CPUError::OutOfBoundsException);
|
// return Err(CPUError::OutOfBoundsException);
|
||||||
return Ok(0xFF); // Hack I kno but emulator does it like that
|
return Ok(0xFF); // Hack I kno but emulator does it like that
|
||||||
}
|
}
|
||||||
let d = rom[Z as usize];
|
let d = rom[Z as usize];
|
||||||
self.set_register(dst_reg, d);
|
self.set_register(dst_reg, d);
|
||||||
},
|
}
|
||||||
Instruction::LPM(ref dst_reg, ref inc_mode) => {
|
Instruction::LPM(ref dst_reg, ref inc_mode) => {
|
||||||
let Z = self.get_register_pair(&30u8.into());
|
let Z = self.get_register_pair(&30u8.into());
|
||||||
let d = rom[Z as usize];
|
let d = rom[Z as usize];
|
||||||
@ -480,16 +511,16 @@ impl CPU {
|
|||||||
match *inc_mode {
|
match *inc_mode {
|
||||||
IncrementMode::PostIncrement => {
|
IncrementMode::PostIncrement => {
|
||||||
self.set_register_pair(&30u8.into(), Z.wrapping_add(1));
|
self.set_register_pair(&30u8.into(), Z.wrapping_add(1));
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// This instruction does only support None + PostIncrement
|
// This instruction does only support None + PostIncrement
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Instruction::OUT(ref addr, ref val) => {
|
Instruction::OUT(ref addr, ref val) => {
|
||||||
let val = self.get_register(val);
|
let val = self.get_register(val);
|
||||||
self.ram_write(ram, *addr, val)?;
|
self.ram_write(ram, *addr, val)?;
|
||||||
},
|
}
|
||||||
Instruction::IN(ref reg, ref addr) => {
|
Instruction::IN(ref reg, ref addr) => {
|
||||||
let v = self.ram_read(ram, *addr)?;
|
let v = self.ram_read(ram, *addr)?;
|
||||||
self.set_register(reg, v);
|
self.set_register(reg, v);
|
||||||
@ -500,35 +531,35 @@ impl CPU {
|
|||||||
self.push(ram, ((ret_to >> 8) & 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 & 0xFF) as u8)?;
|
||||||
self.pc = *addr;
|
self.pc = *addr;
|
||||||
},
|
}
|
||||||
Instruction::RCALL(ref addr) => {
|
Instruction::RCALL(ref addr) => {
|
||||||
let ret_to = self.pc;
|
let ret_to = self.pc;
|
||||||
self.push(ram, ((ret_to >> 16) & 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 >> 8) & 0xFF) as u8)?;
|
||||||
self.push(ram, (ret_to & 0xFF) as u8)?;
|
self.push(ram, (ret_to & 0xFF) as u8)?;
|
||||||
self.pc = (self.pc as i32 + *addr as i32) as u32;
|
self.pc = (self.pc as i32 + *addr as i32) as u32;
|
||||||
},
|
}
|
||||||
Instruction::RET => {
|
Instruction::RET => {
|
||||||
let mut ret_to = self.pop(ram)? as u32;
|
let mut ret_to = self.pop(ram)? as u32;
|
||||||
ret_to += (self.pop(ram)? as u32) << 8;
|
ret_to += (self.pop(ram)? as u32) << 8;
|
||||||
ret_to += (self.pop(ram)? as u32) << 16;
|
ret_to += (self.pop(ram)? as u32) << 16;
|
||||||
self.pc = ret_to as _;
|
self.pc = ret_to as _;
|
||||||
},
|
}
|
||||||
Instruction::POP(ref reg) => {
|
Instruction::POP(ref reg) => {
|
||||||
let v = self.pop(ram)?;
|
let v = self.pop(ram)?;
|
||||||
self.registers[reg.as_usize()] = v;
|
self.registers[reg.as_usize()] = v;
|
||||||
},
|
}
|
||||||
Instruction::PUSH(ref reg) => {
|
Instruction::PUSH(ref reg) => {
|
||||||
let v = self.registers[reg.as_usize()];
|
let v = self.registers[reg.as_usize()];
|
||||||
self.push(ram, v)?;
|
self.push(ram, v)?;
|
||||||
},
|
}
|
||||||
Instruction::SUBI(ref d, ref v) => {
|
Instruction::SUBI(ref d, ref v) => {
|
||||||
let dv = self.get_register(d);
|
let dv = self.get_register(d);
|
||||||
let vres = dv.wrapping_sub(*v);
|
let vres = dv.wrapping_sub(*v);
|
||||||
|
|
||||||
self.update_flags_sub_zns(vres, dv, *v);
|
self.update_flags_sub_zns(vres, dv, *v);
|
||||||
self.set_register(d, vres);
|
self.set_register(d, vres);
|
||||||
},
|
}
|
||||||
Instruction::SBC(ref d, ref r) => {
|
Instruction::SBC(ref d, ref r) => {
|
||||||
let dv = self.get_register(d);
|
let dv = self.get_register(d);
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
@ -539,7 +570,7 @@ impl CPU {
|
|||||||
|
|
||||||
self.update_flags_sub_Rzns(vres, dv, rv);
|
self.update_flags_sub_Rzns(vres, dv, rv);
|
||||||
self.set_register(d, vres);
|
self.set_register(d, vres);
|
||||||
},
|
}
|
||||||
Instruction::SBCI(ref d, ref v) => {
|
Instruction::SBCI(ref d, ref v) => {
|
||||||
let dv = self.get_register(d);
|
let dv = self.get_register(d);
|
||||||
let mut vres = dv.wrapping_sub(*v);
|
let mut vres = dv.wrapping_sub(*v);
|
||||||
@ -549,11 +580,11 @@ impl CPU {
|
|||||||
|
|
||||||
self.update_flags_sub_Rzns(vres, dv, *v);
|
self.update_flags_sub_Rzns(vres, dv, *v);
|
||||||
self.set_register(d, vres);
|
self.set_register(d, vres);
|
||||||
},
|
}
|
||||||
Instruction::MOVW(ref d, ref r) => {
|
Instruction::MOVW(ref d, ref r) => {
|
||||||
let t = self.get_register_pair(r);
|
let t = self.get_register_pair(r);
|
||||||
self.set_register_pair(d, t);
|
self.set_register_pair(d, t);
|
||||||
},
|
}
|
||||||
Instruction::OR(ref d, ref r) => {
|
Instruction::OR(ref d, ref r) => {
|
||||||
let t = self.get_register(d) | self.get_register(r);
|
let t = self.get_register(d) | self.get_register(r);
|
||||||
self.set_register(d, t);
|
self.set_register(d, t);
|
||||||
@ -563,28 +594,28 @@ impl CPU {
|
|||||||
let t = self.get_register(d) | *v;
|
let t = self.get_register(d) | *v;
|
||||||
self.set_register(d, t);
|
self.set_register(d, t);
|
||||||
self.update_flags_znv0s(t);
|
self.update_flags_znv0s(t);
|
||||||
},
|
}
|
||||||
Instruction::AND(ref d, ref r) => {
|
Instruction::AND(ref d, ref r) => {
|
||||||
let t = self.get_register(d) & self.get_register(r);
|
let t = self.get_register(d) & self.get_register(r);
|
||||||
self.set_register(d, t);
|
self.set_register(d, t);
|
||||||
self.update_flags_znv0s(t);
|
self.update_flags_znv0s(t);
|
||||||
},
|
}
|
||||||
Instruction::TST(ref r) => {
|
Instruction::TST(ref r) => {
|
||||||
let t = self.get_register(r);
|
let t = self.get_register(r);
|
||||||
self.update_flags_znv0s(t);
|
self.update_flags_znv0s(t);
|
||||||
},
|
}
|
||||||
Instruction::ANDI(ref d, ref v) => {
|
Instruction::ANDI(ref d, ref v) => {
|
||||||
let t = self.get_register(d) & *v;
|
let t = self.get_register(d) & *v;
|
||||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||||
self.set_register(d, t);
|
self.set_register(d, t);
|
||||||
},
|
}
|
||||||
Instruction::ADD(ref d, ref r) => {
|
Instruction::ADD(ref d, ref r) => {
|
||||||
let t = self.get_register(d).wrapping_add(self.get_register(r));
|
let t = self.get_register(d).wrapping_add(self.get_register(r));
|
||||||
let dd = self.get_register(d);
|
let dd = self.get_register(d);
|
||||||
self.set_clear_flag(StatusFlag::Carry, t < dd);
|
self.set_clear_flag(StatusFlag::Carry, t < dd);
|
||||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||||
self.set_register(d, t);
|
self.set_register(d, t);
|
||||||
},
|
}
|
||||||
Instruction::ADC(ref d, ref r) => {
|
Instruction::ADC(ref d, ref r) => {
|
||||||
let mut t = self.get_register(d).wrapping_add(self.get_register(r));
|
let mut t = self.get_register(d).wrapping_add(self.get_register(r));
|
||||||
if self.test_flag(StatusFlag::Carry) {
|
if self.test_flag(StatusFlag::Carry) {
|
||||||
@ -594,41 +625,47 @@ impl CPU {
|
|||||||
self.set_clear_flag(StatusFlag::Carry, t < dd);
|
self.set_clear_flag(StatusFlag::Carry, t < dd);
|
||||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||||
self.set_register(d, t);
|
self.set_register(d, t);
|
||||||
},
|
}
|
||||||
Instruction::SUB(ref d, ref r) => {
|
Instruction::SUB(ref d, ref r) => {
|
||||||
let dv = self.get_register(d);
|
let dv = self.get_register(d);
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let res = dv.wrapping_sub(rv);
|
let res = dv.wrapping_sub(rv);
|
||||||
self.update_flags_sub_zns(res, dv, rv);
|
self.update_flags_sub_zns(res, dv, rv);
|
||||||
self.set_register(d, res);
|
self.set_register(d, res);
|
||||||
},
|
}
|
||||||
Instruction::MOV(ref d, ref r) => {
|
Instruction::MOV(ref d, ref r) => {
|
||||||
let v = self.get_register(r);
|
let v = self.get_register(r);
|
||||||
self.set_register(d, v);
|
self.set_register(d, v);
|
||||||
},
|
}
|
||||||
Instruction::ADIW(ref d, ref v) => {
|
Instruction::ADIW(ref d, ref v) => {
|
||||||
let dv = self.get_register_pair(d);
|
let dv = self.get_register_pair(d);
|
||||||
let res = dv.wrapping_add(*v);
|
let res = dv.wrapping_add(*v);
|
||||||
self.set_register_pair(d, res);
|
self.set_register_pair(d, res);
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, (dv & !res) & 0x8000 == 0x8000);
|
self.set_clear_flag(
|
||||||
|
StatusFlag::TwosComplementOverflow,
|
||||||
|
(dv & !res) & 0x8000 == 0x8000,
|
||||||
|
);
|
||||||
self.set_clear_flag(StatusFlag::Carry, (!dv & res) & 0x8000 == 0x8000);
|
self.set_clear_flag(StatusFlag::Carry, (!dv & res) & 0x8000 == 0x8000);
|
||||||
self.update_flags_zns_16(res);
|
self.update_flags_zns_16(res);
|
||||||
},
|
}
|
||||||
Instruction::SBIW(ref d, ref v) => {
|
Instruction::SBIW(ref d, ref v) => {
|
||||||
let dv = self.get_register_pair(d);
|
let dv = self.get_register_pair(d);
|
||||||
let res = dv.wrapping_sub(*v as _);
|
let res = dv.wrapping_sub(*v as _);
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, (!dv & res) & 0x8000 == 0x8000);
|
self.set_clear_flag(
|
||||||
|
StatusFlag::TwosComplementOverflow,
|
||||||
|
(!dv & res) & 0x8000 == 0x8000,
|
||||||
|
);
|
||||||
self.set_clear_flag(StatusFlag::Carry, (dv & !res) & 0x8000 == 0x8000);
|
self.set_clear_flag(StatusFlag::Carry, (dv & !res) & 0x8000 == 0x8000);
|
||||||
self.update_flags_zns_16(res);
|
self.update_flags_zns_16(res);
|
||||||
self.set_register_pair(d, res);
|
self.set_register_pair(d, res);
|
||||||
},
|
}
|
||||||
Instruction::DEC(ref r) => {
|
Instruction::DEC(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let res = rv.wrapping_sub(1);
|
let res = rv.wrapping_sub(1);
|
||||||
self.set_register(r, res);
|
self.set_register(r, res);
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, res == 0x7F);
|
self.set_clear_flag(StatusFlag::TwosComplementOverflow, res == 0x7F);
|
||||||
self.update_flags_zns_8(res);
|
self.update_flags_zns_8(res);
|
||||||
},
|
}
|
||||||
Instruction::INC(ref r) => {
|
Instruction::INC(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let res = rv.wrapping_add(1);
|
let res = rv.wrapping_add(1);
|
||||||
@ -636,82 +673,94 @@ impl CPU {
|
|||||||
|
|
||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, res == 0x80);
|
self.set_clear_flag(StatusFlag::TwosComplementOverflow, res == 0x80);
|
||||||
self.update_flags_zns_8(res);
|
self.update_flags_zns_8(res);
|
||||||
},
|
}
|
||||||
Instruction::STS16(ref addr, ref r) => {
|
Instruction::STS16(ref addr, ref r) => {
|
||||||
let rampd = ram[chip_definitions::IOAdress::RAMPD as usize] as u32;
|
let rampd = ram[chip_definitions::IOAdress::RAMPD as usize] as u32;
|
||||||
if rampd != 0 { panic!("This is unexpected (for now)"); }
|
if rampd != 0 {
|
||||||
|
panic!("This is unexpected (for now)");
|
||||||
|
}
|
||||||
self.ram_write(ram, *addr, self.get_register(r))?;
|
self.ram_write(ram, *addr, self.get_register(r))?;
|
||||||
},
|
}
|
||||||
Instruction::STS8(ref addr, ref r) => {
|
Instruction::STS8(ref addr, ref r) => {
|
||||||
self.ram_write(ram, *addr as u16, self.get_register(r))?;
|
self.ram_write(ram, *addr as u16, self.get_register(r))?;
|
||||||
},
|
}
|
||||||
Instruction::LDS16(ref r, ref addr) => {
|
Instruction::LDS16(ref r, ref addr) => {
|
||||||
let rampd = ram[chip_definitions::IOAdress::RAMPD as usize] as u32;
|
let rampd = ram[chip_definitions::IOAdress::RAMPD as usize] as u32;
|
||||||
if rampd != 0 { panic!("This is unexpected (for now)"); }
|
if rampd != 0 {
|
||||||
|
panic!("This is unexpected (for now)");
|
||||||
|
}
|
||||||
let v = self.ram_read(ram, *addr)?;
|
let v = self.ram_read(ram, *addr)?;
|
||||||
self.set_register(r, v);
|
self.set_register(r, v);
|
||||||
},
|
}
|
||||||
Instruction::LDS8(ref r, ref addr) => {
|
Instruction::LDS8(ref r, ref addr) => {
|
||||||
let v = self.ram_read(ram, *addr as u16)?;
|
let v = self.ram_read(ram, *addr as u16)?;
|
||||||
self.set_register(r, v);
|
self.set_register(r, v);
|
||||||
},
|
}
|
||||||
Instruction::LSL(ref r) => {
|
Instruction::LSL(ref r) => {
|
||||||
let v = self.get_register(r);
|
let v = self.get_register(r);
|
||||||
self.set_clear_flag(StatusFlag::Carry, v & 0x80 == 0x80);
|
self.set_clear_flag(StatusFlag::Carry, v & 0x80 == 0x80);
|
||||||
self.set_register(r, v << 1);
|
self.set_register(r, v << 1);
|
||||||
self.set_clear_flag(StatusFlag::Zero, (v << 1) == 0);
|
self.set_clear_flag(StatusFlag::Zero, (v << 1) == 0);
|
||||||
},
|
}
|
||||||
Instruction::ROL(ref r) => {
|
Instruction::ROL(ref r) => {
|
||||||
let v = self.get_register(r);
|
let v = self.get_register(r);
|
||||||
let c = if self.test_flag(StatusFlag::Carry) { 1 } else { 0 };
|
let c = if self.test_flag(StatusFlag::Carry) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
self.set_clear_flag(StatusFlag::Carry, v & 0x80 == 0x80);
|
self.set_clear_flag(StatusFlag::Carry, v & 0x80 == 0x80);
|
||||||
self.set_register(r, v << 1 | c);
|
self.set_register(r, v << 1 | c);
|
||||||
self.set_clear_flag(StatusFlag::Zero, (v << 1) | c == 0);
|
self.set_clear_flag(StatusFlag::Zero, (v << 1) | c == 0);
|
||||||
},
|
}
|
||||||
Instruction::ASR(ref r) => {
|
Instruction::ASR(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let res = rv >> 1 | (rv & 0x80);
|
let res = rv >> 1 | (rv & 0x80);
|
||||||
self.set_register(r, res);
|
self.set_register(r, res);
|
||||||
self.update_flags_zcnvs(res, rv);
|
self.update_flags_zcnvs(res, rv);
|
||||||
},
|
}
|
||||||
Instruction::LSR(ref r) => {
|
Instruction::LSR(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
self.set_register(r, rv >> 1);
|
self.set_register(r, rv >> 1);
|
||||||
self.clear_flag(StatusFlag::Negative);
|
self.clear_flag(StatusFlag::Negative);
|
||||||
self.update_flags_zcvs(rv >> 1, rv);
|
self.update_flags_zcvs(rv >> 1, rv);
|
||||||
},
|
}
|
||||||
Instruction::ROR(ref r) => {
|
Instruction::ROR(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let c = if self.test_flag(StatusFlag::Carry) { 0x80 } else { 0 };
|
let c = if self.test_flag(StatusFlag::Carry) {
|
||||||
|
0x80
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
let res = rv >> 1 | c;
|
let res = rv >> 1 | c;
|
||||||
self.set_register(r, res);
|
self.set_register(r, res);
|
||||||
self.update_flags_zcnvs(res, rv);
|
self.update_flags_zcnvs(res, rv);
|
||||||
},
|
}
|
||||||
Instruction::SBRS(ref r, ref bit) => {
|
Instruction::SBRS(ref r, ref bit) => {
|
||||||
let r = self.get_register(r);
|
let r = self.get_register(r);
|
||||||
if (r & (1 << *bit)) > 0 {
|
if (r & (1 << *bit)) > 0 {
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Instruction::SBRC(ref r, ref bit) => {
|
Instruction::SBRC(ref r, ref bit) => {
|
||||||
let r = self.get_register(r);
|
let r = self.get_register(r);
|
||||||
if (r & (1 << *bit)) == 0 {
|
if (r & (1 << *bit)) == 0 {
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Instruction::CPSE(ref r, ref d) => {
|
Instruction::CPSE(ref r, ref d) => {
|
||||||
if self.get_register(r) == self.get_register(d) {
|
if self.get_register(r) == self.get_register(d) {
|
||||||
// TODO: assume 2b instruction after this one.
|
// TODO: assume 2b instruction after this one.
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Instruction::COM(ref r) => {
|
Instruction::COM(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let res = 0xFFu8.wrapping_sub(rv);
|
let res = 0xFFu8.wrapping_sub(rv);
|
||||||
self.set_register(r, res);
|
self.set_register(r, res);
|
||||||
self.update_flags_znv0s(res);
|
self.update_flags_znv0s(res);
|
||||||
self.set_flag(StatusFlag::Carry);
|
self.set_flag(StatusFlag::Carry);
|
||||||
},
|
}
|
||||||
Instruction::NEG(ref r) => {
|
Instruction::NEG(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
let res = 0u8.wrapping_sub(rv);
|
let res = 0u8.wrapping_sub(rv);
|
||||||
@ -720,7 +769,7 @@ impl CPU {
|
|||||||
self.set_clear_flag(StatusFlag::TwosComplementOverflow, res == 0x80);
|
self.set_clear_flag(StatusFlag::TwosComplementOverflow, res == 0x80);
|
||||||
self.set_clear_flag(StatusFlag::Carry, res != 0);
|
self.set_clear_flag(StatusFlag::Carry, res != 0);
|
||||||
self.update_flags_zns_8(rv);
|
self.update_flags_zns_8(rv);
|
||||||
},
|
}
|
||||||
Instruction::MUL(ref r, ref d) => {
|
Instruction::MUL(ref r, ref d) => {
|
||||||
// R1:R0 ← Rd × Rr(unsigned ← unsigned × unsigned)
|
// R1:R0 ← Rd × Rr(unsigned ← unsigned × unsigned)
|
||||||
let r = self.get_register(r) as u16;
|
let r = self.get_register(r) as u16;
|
||||||
@ -730,20 +779,20 @@ impl CPU {
|
|||||||
self.registers[1] = ((v >> 8) & 0xFF) as u8;
|
self.registers[1] = ((v >> 8) & 0xFF) as u8;
|
||||||
self.set_clear_flag(StatusFlag::Carry, v & 0x80 == 0x80);
|
self.set_clear_flag(StatusFlag::Carry, v & 0x80 == 0x80);
|
||||||
self.set_clear_flag(StatusFlag::Zero, v == 0);
|
self.set_clear_flag(StatusFlag::Zero, v == 0);
|
||||||
},
|
}
|
||||||
Instruction::BST(ref r, ref v) => {
|
Instruction::BST(ref r, ref v) => {
|
||||||
let r = self.get_register(r);
|
let r = self.get_register(r);
|
||||||
self.set_clear_flag(StatusFlag::BitCopyStorage, r & (1 << *v) != 0);
|
self.set_clear_flag(StatusFlag::BitCopyStorage, r & (1 << *v) != 0);
|
||||||
},
|
}
|
||||||
Instruction::SWAP(ref r) => {
|
Instruction::SWAP(ref r) => {
|
||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
self.set_register(r, rv >> 4 | ((rv << 4) & 0xF0));
|
self.set_register(r, rv >> 4 | ((rv << 4) & 0xF0));
|
||||||
},
|
}
|
||||||
Instruction::BREAK => {
|
Instruction::BREAK => {
|
||||||
return Err(CPUError::Breakpoint);
|
return Err(CPUError::Breakpoint);
|
||||||
}
|
}
|
||||||
Instruction::NOP => {},
|
Instruction::NOP => {}
|
||||||
_ => return Err(CPUError::UnimplementedInstruction)
|
_ => return Err(CPUError::UnimplementedInstruction),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ins.cycles())
|
Ok(ins.cycles())
|
||||||
|
|||||||
180
src/decoder.rs
180
src/decoder.rs
@ -1,5 +1,4 @@
|
|||||||
use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, IORegister,
|
use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, IORegister, StatusFlag, PC};
|
||||||
StatusFlag, PC};
|
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@ -55,7 +54,11 @@ pub enum Instruction {
|
|||||||
LAC(GeneralPurposeRegister),
|
LAC(GeneralPurposeRegister),
|
||||||
LAS(GeneralPurposeRegister),
|
LAS(GeneralPurposeRegister),
|
||||||
LAT(GeneralPurposeRegister),
|
LAT(GeneralPurposeRegister),
|
||||||
LD(GeneralPurposeRegister, GeneralPurposeRegisterPair, IncrementMode),
|
LD(
|
||||||
|
GeneralPurposeRegister,
|
||||||
|
GeneralPurposeRegisterPair,
|
||||||
|
IncrementMode,
|
||||||
|
),
|
||||||
LDI(GeneralPurposeRegister, u8),
|
LDI(GeneralPurposeRegister, u8),
|
||||||
LDS8(GeneralPurposeRegister, u8), // Two variants, with u8 and u16
|
LDS8(GeneralPurposeRegister, u8), // Two variants, with u8 and u16
|
||||||
LDS16(GeneralPurposeRegister, u16),
|
LDS16(GeneralPurposeRegister, u16),
|
||||||
@ -93,7 +96,11 @@ pub enum Instruction {
|
|||||||
SET_FLAG(StatusFlag), // TODO how is it really called? (CLR)
|
SET_FLAG(StatusFlag), // TODO how is it really called? (CLR)
|
||||||
SLEEP,
|
SLEEP,
|
||||||
SPM(IncrementMode), // Only supports PostIncrement
|
SPM(IncrementMode), // Only supports PostIncrement
|
||||||
ST(GeneralPurposeRegisterPair, GeneralPurposeRegister, IncrementMode),
|
ST(
|
||||||
|
GeneralPurposeRegisterPair,
|
||||||
|
GeneralPurposeRegister,
|
||||||
|
IncrementMode,
|
||||||
|
),
|
||||||
STS8(u8, GeneralPurposeRegister), // Two variants, u8/u16
|
STS8(u8, GeneralPurposeRegister), // Two variants, u8/u16
|
||||||
STS16(u16, GeneralPurposeRegister),
|
STS16(u16, GeneralPurposeRegister),
|
||||||
SUB(GeneralPurposeRegister, GeneralPurposeRegister),
|
SUB(GeneralPurposeRegister, GeneralPurposeRegister),
|
||||||
@ -104,7 +111,6 @@ pub enum Instruction {
|
|||||||
XCH(GeneralPurposeRegister),
|
XCH(GeneralPurposeRegister),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for Instruction {
|
impl fmt::Display for Instruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
@ -116,7 +122,9 @@ impl fmt::Display for Instruction {
|
|||||||
Instruction::ASR(ref r) => write!(f, "ASR {}", r),
|
Instruction::ASR(ref r) => write!(f, "ASR {}", r),
|
||||||
Instruction::BLD(ref r, v) => write!(f, "BLD {}, {}", r, v),
|
Instruction::BLD(ref r, v) => write!(f, "BLD {}, {}", r, v),
|
||||||
Instruction::BREAK => write!(f, "BREAK"),
|
Instruction::BREAK => write!(f, "BREAK"),
|
||||||
Instruction::BR_IF(rel, ref flag, tgt) => write!(f, "BR_IF {}, {:?}=={}", rel, flag, tgt),
|
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::BST(ref r, v) => write!(f, "BST {}, {}", r, v),
|
||||||
Instruction::CALL(pc) => write!(f, "CALL {:06X}", pc),
|
Instruction::CALL(pc) => write!(f, "CALL {:06X}", pc),
|
||||||
Instruction::CBI(ref ior, v) => write!(f, "CBI {}, {}", ior, v),
|
Instruction::CBI(ref ior, v) => write!(f, "CBI {}, {}", ior, v),
|
||||||
@ -193,7 +201,6 @@ impl fmt::Display for Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
// TODO: There are more
|
// TODO: There are more
|
||||||
// LDS32 STS32
|
// LDS32 STS32
|
||||||
@ -201,7 +208,7 @@ impl Instruction {
|
|||||||
match *self {
|
match *self {
|
||||||
Instruction::JMP(_) | Instruction::CALL(_) => 4,
|
Instruction::JMP(_) | Instruction::CALL(_) => 4,
|
||||||
Instruction::STS16(_, _) | Instruction::LDS16(_, _) => 4,
|
Instruction::STS16(_, _) | Instruction::LDS16(_, _) => 4,
|
||||||
_ => 2
|
_ => 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,12 +237,16 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
0b1001_0100_1000_1000 => {
|
0b1001_0100_1000_1000 => {
|
||||||
// CLR_FLAG TODO HOW IS IT CALLED
|
// CLR_FLAG TODO HOW IS IT CALLED
|
||||||
let idx = ((v & 0b0000_0000_0111_0000) >> 4) as u8;
|
let idx = ((v & 0b0000_0000_0111_0000) >> 4) as u8;
|
||||||
return Ok(Instruction::CLR_FLAG(StatusFlag::try_from_idx(idx).unwrap()));
|
return Ok(Instruction::CLR_FLAG(
|
||||||
},
|
StatusFlag::try_from_idx(idx).unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
0b1001_0100_0000_1000 => {
|
0b1001_0100_0000_1000 => {
|
||||||
// SET_FLAG TODO HOW IS IT CALLED
|
// SET_FLAG TODO HOW IS IT CALLED
|
||||||
let idx = ((v & 0b0000_0000_0111_0000) >> 4) as u8;
|
let idx = ((v & 0b0000_0000_0111_0000) >> 4) as u8;
|
||||||
return Ok(Instruction::SET_FLAG(StatusFlag::try_from_idx(idx).unwrap()));
|
return Ok(Instruction::SET_FLAG(
|
||||||
|
StatusFlag::try_from_idx(idx).unwrap(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -301,16 +312,22 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
let A = ((v & 0b1111_1000) >> 3) as u16;
|
let A = ((v & 0b1111_1000) >> 3) as u16;
|
||||||
let b = (v & 0b0111) as u8;
|
let b = (v & 0b0111) as u8;
|
||||||
match v & 0b1111_1111_0000_0000 {
|
match v & 0b1111_1111_0000_0000 {
|
||||||
0b1001_0110_0000_0000 => return Ok(Instruction::ADIW(((d & 0b11) * 2 + 24).into(), K as u16)),
|
0b1001_0110_0000_0000 => {
|
||||||
|
return Ok(Instruction::ADIW(((d & 0b11) * 2 + 24).into(), K as u16))
|
||||||
|
}
|
||||||
0b0000_0001_0000_0000 => return Ok(Instruction::MOVW((d * 2).into(), (r * 2).into())),
|
0b0000_0001_0000_0000 => return Ok(Instruction::MOVW((d * 2).into(), (r * 2).into())),
|
||||||
0b0000_0010_0000_0000 => return Ok(Instruction::MULS((d + 16).into(), (r + 16).into())),
|
0b0000_0010_0000_0000 => return Ok(Instruction::MULS((d + 16).into(), (r + 16).into())),
|
||||||
0b1001_0111_0000_0000 => return Ok(Instruction::SBIW(((d & 0b11) * 2 + 24).into(), K as u16)),
|
0b1001_0111_0000_0000 => {
|
||||||
0b1110_1111_0000_0000 => if r == 0b1111 { return Ok(Instruction::SER((d + 16).into())) }
|
return Ok(Instruction::SBIW(((d & 0b11) * 2 + 24).into(), K as u16))
|
||||||
|
}
|
||||||
|
0b1110_1111_0000_0000 => if r == 0b1111 {
|
||||||
|
return Ok(Instruction::SER((d + 16).into()));
|
||||||
|
},
|
||||||
0b1001_1010_0000_0000 => return Ok(Instruction::SBI(A, b)),
|
0b1001_1010_0000_0000 => return Ok(Instruction::SBI(A, b)),
|
||||||
0b1001_1011_0000_0000 => return Ok(Instruction::SBIS(A, b)),
|
0b1001_1011_0000_0000 => return Ok(Instruction::SBIS(A, b)),
|
||||||
0b1001_1001_0000_0000 => return Ok(Instruction::SBIC(A, b)),
|
0b1001_1001_0000_0000 => return Ok(Instruction::SBIC(A, b)),
|
||||||
0b1001_1000_0000_0000 => return Ok(Instruction::CBI(A, b)),
|
0b1001_1000_0000_0000 => return Ok(Instruction::CBI(A, b)),
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,31 +342,72 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
// mode: 00 -> None, 01 -> PostIncrement, 10 -> PreDecrement
|
// mode: 00 -> None, 01 -> PostIncrement, 10 -> PreDecrement
|
||||||
let mode = v & 0b11;
|
let mode = v & 0b11;
|
||||||
let do_store = v & 0b0010_0000_0000 != 0;
|
let do_store = v & 0b0010_0000_0000 != 0;
|
||||||
match (do_store, v & 0b0001_0000_0000_0000 > 0, (v >> 2) & 0b11, mode) {
|
match (
|
||||||
|
do_store,
|
||||||
|
v & 0b0001_0000_0000_0000 > 0,
|
||||||
|
(v >> 2) & 0b11,
|
||||||
|
mode,
|
||||||
|
) {
|
||||||
// LD X
|
// LD X
|
||||||
(false, true, 0b11, 0b00) => return Ok(Instruction::LD(dr, 26.into(), IncrementMode::None)),
|
(false, true, 0b11, 0b00) => {
|
||||||
(false, true, 0b11, 0b01) => return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PostIncrement)),
|
return Ok(Instruction::LD(dr, 26.into(), IncrementMode::None))
|
||||||
(false, true, 0b11, 0b10) => return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PreDecrement)),
|
}
|
||||||
|
(false, true, 0b11, 0b01) => {
|
||||||
|
return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
|
(false, true, 0b11, 0b10) => {
|
||||||
|
return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PreDecrement))
|
||||||
|
}
|
||||||
// LD Y
|
// LD Y
|
||||||
(false, false, 0b10, 0b00) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::None)),
|
(false, false, 0b10, 0b00) => {
|
||||||
(false, true, 0b10, 0b01) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PostIncrement)),
|
return Ok(Instruction::LD(dr, 28.into(), IncrementMode::None))
|
||||||
(false, true, 0b10, 0b10) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PreDecrement)),
|
}
|
||||||
|
(false, true, 0b10, 0b01) => {
|
||||||
|
return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
|
(false, true, 0b10, 0b10) => {
|
||||||
|
return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PreDecrement))
|
||||||
|
}
|
||||||
// LD Z
|
// LD Z
|
||||||
(false, false, 0b00, 0b00) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::None)),
|
(false, false, 0b00, 0b00) => {
|
||||||
(false, true, 0b00, 0b01) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PostIncrement)),
|
return Ok(Instruction::LD(dr, 30.into(), IncrementMode::None))
|
||||||
(false, true, 0b00, 0b10) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PreDecrement)),
|
}
|
||||||
|
(false, true, 0b00, 0b01) => {
|
||||||
|
return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
|
(false, true, 0b00, 0b10) => {
|
||||||
|
return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PreDecrement))
|
||||||
|
}
|
||||||
// ST X
|
// ST X
|
||||||
(true, true, 0b11, 0b00) => return Ok(Instruction::ST(26.into(), dr, IncrementMode::None)),
|
(true, true, 0b11, 0b00) => {
|
||||||
(true, true, 0b11, 0b01) => return Ok(Instruction::ST(26.into(), dr, IncrementMode::PostIncrement)),
|
return Ok(Instruction::ST(26.into(), dr, IncrementMode::None))
|
||||||
(true, true, 0b11, 0b10) => return Ok(Instruction::ST(26.into(), dr, IncrementMode::PreDecrement)),
|
}
|
||||||
|
(true, true, 0b11, 0b01) => {
|
||||||
|
return Ok(Instruction::ST(26.into(), dr, IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
|
(true, true, 0b11, 0b10) => {
|
||||||
|
return Ok(Instruction::ST(26.into(), dr, IncrementMode::PreDecrement))
|
||||||
|
}
|
||||||
// ST Y
|
// ST Y
|
||||||
(true, false, 0b10, 0b00) => return Ok(Instruction::ST(28.into(), dr, IncrementMode::None)),
|
(true, false, 0b10, 0b00) => {
|
||||||
(true, true, 0b10, 0b01) => return Ok(Instruction::ST(28.into(), dr, IncrementMode::PostIncrement)),
|
return Ok(Instruction::ST(28.into(), dr, IncrementMode::None))
|
||||||
(true, true, 0b10, 0b10) => return Ok(Instruction::ST(28.into(), dr, IncrementMode::PreDecrement)),
|
}
|
||||||
|
(true, true, 0b10, 0b01) => {
|
||||||
|
return Ok(Instruction::ST(28.into(), dr, IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
|
(true, true, 0b10, 0b10) => {
|
||||||
|
return Ok(Instruction::ST(28.into(), dr, IncrementMode::PreDecrement))
|
||||||
|
}
|
||||||
// ST Z
|
// ST Z
|
||||||
(true, false, 0b00, 0b00) => return Ok(Instruction::ST(30.into(), dr, IncrementMode::None)),
|
(true, false, 0b00, 0b00) => {
|
||||||
(true, true, 0b00, 0b01) => return Ok(Instruction::ST(30.into(), dr, IncrementMode::PostIncrement)),
|
return Ok(Instruction::ST(30.into(), dr, IncrementMode::None))
|
||||||
(true, true, 0b00, 0b10) => return Ok(Instruction::ST(30.into(), dr, IncrementMode::PreDecrement)),
|
}
|
||||||
|
(true, true, 0b00, 0b01) => {
|
||||||
|
return Ok(Instruction::ST(30.into(), dr, IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
|
(true, true, 0b00, 0b10) => {
|
||||||
|
return Ok(Instruction::ST(30.into(), dr, IncrementMode::PreDecrement))
|
||||||
|
}
|
||||||
|
|
||||||
// POP: 1001 000d dddd 1111
|
// POP: 1001 000d dddd 1111
|
||||||
(false, true, 0b11, 0b11) => return Ok(Instruction::POP(dr)),
|
(false, true, 0b11, 0b11) => return Ok(Instruction::POP(dr)),
|
||||||
@ -366,11 +424,15 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
// ELPM (2) 1001 000d dddd 0110
|
// ELPM (2) 1001 000d dddd 0110
|
||||||
(false, true, 0b01, 0b10) => return Ok(Instruction::ELPM(dr, IncrementMode::None)),
|
(false, true, 0b01, 0b10) => return Ok(Instruction::ELPM(dr, IncrementMode::None)),
|
||||||
// ELPM (3) 1001 000d dddd 0111
|
// ELPM (3) 1001 000d dddd 0111
|
||||||
(false, true, 0b01, 0b11) => return Ok(Instruction::ELPM(dr, IncrementMode::PostIncrement)),
|
(false, true, 0b01, 0b11) => {
|
||||||
|
return Ok(Instruction::ELPM(dr, IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
// LPM (2): 1001 000d dddd 0100
|
// LPM (2): 1001 000d dddd 0100
|
||||||
(false, true, 0b01, 0b00) => return Ok(Instruction::LPM(dr, IncrementMode::None)),
|
(false, true, 0b01, 0b00) => return Ok(Instruction::LPM(dr, IncrementMode::None)),
|
||||||
// LPM (3): 1001 000d dddd 0101
|
// LPM (3): 1001 000d dddd 0101
|
||||||
(false, true, 0b01, 0b01) => return Ok(Instruction::LPM(dr, IncrementMode::PostIncrement)),
|
(false, true, 0b01, 0b01) => {
|
||||||
|
return Ok(Instruction::LPM(dr, IncrementMode::PostIncrement))
|
||||||
|
}
|
||||||
// TODO: LDS32 STS32
|
// TODO: LDS32 STS32
|
||||||
// STS32 1001 001r rrrr 0000 kkkk kkkk kkkk kkkk
|
// STS32 1001 001r rrrr 0000 kkkk kkkk kkkk kkkk
|
||||||
(true, true, 0, 0) => {
|
(true, true, 0, 0) => {
|
||||||
@ -379,7 +441,7 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
Some(k) => return Ok(Instruction::STS16(k, dr)),
|
Some(k) => return Ok(Instruction::STS16(k, dr)),
|
||||||
None => return Err(DecodingError::TruncatedInstruction),
|
None => return Err(DecodingError::TruncatedInstruction),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// LDS32 1001 000d dddd 0000 kkkk kkkk kkkk kkkk
|
// LDS32 1001 000d dddd 0000 kkkk kkkk kkkk kkkk
|
||||||
(false, true, 0, 0) => {
|
(false, true, 0, 0) => {
|
||||||
//LDS32
|
//LDS32
|
||||||
@ -422,7 +484,7 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
return Ok(Instruction::SBRS(r, b));
|
return Ok(Instruction::SBRS(r, b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// BLD '1111 100d dddd 0bbb'
|
// BLD '1111 100d dddd 0bbb'
|
||||||
// BST '1111 101d dddd 0bbb'
|
// BST '1111 101d dddd 0bbb'
|
||||||
0b1111_1000_0000_0000 | 0b1111_1010_0000_0000 => {
|
0b1111_1000_0000_0000 | 0b1111_1010_0000_0000 => {
|
||||||
@ -475,10 +537,10 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -492,14 +554,14 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
} else {
|
} else {
|
||||||
return Ok(Instruction::ADC(d5, r5));
|
return Ok(Instruction::ADC(d5, r5));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
0b0000_1100_0000_0000 => {
|
0b0000_1100_0000_0000 => {
|
||||||
if d5 == r5 {
|
if d5 == r5 {
|
||||||
return Ok(Instruction::LSL(d5));
|
return Ok(Instruction::LSL(d5));
|
||||||
} else {
|
} else {
|
||||||
return Ok(Instruction::ADD(d5, r5));
|
return Ok(Instruction::ADD(d5, r5));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
0b0000_1000_0000_0000 => return Ok(Instruction::SBC(d5, r5)),
|
0b0000_1000_0000_0000 => return Ok(Instruction::SBC(d5, r5)),
|
||||||
0b0000_0100_0000_0000 => return Ok(Instruction::CPC(d5, r5)),
|
0b0000_0100_0000_0000 => return Ok(Instruction::CPC(d5, r5)),
|
||||||
0b1001_1100_0000_0000 => return Ok(Instruction::MUL(d5, r5)),
|
0b1001_1100_0000_0000 => return Ok(Instruction::MUL(d5, r5)),
|
||||||
@ -608,11 +670,35 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
let dr = (((v >> 4) & 0b11111) as u8).into();
|
let dr = (((v >> 4) & 0b11111) as u8).into();
|
||||||
let q = (((v >> 8) & 0b10_0000) | ((v >> 7) & 0b1_1000) | (v & 0b111)) as u8;
|
let q = (((v >> 8) & 0b10_0000) | ((v >> 7) & 0b1_1000) | (v & 0b111)) as u8;
|
||||||
match (v & 0b1000, w) {
|
match (v & 0b1000, w) {
|
||||||
(0b1000, false) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::ConstantOffset(q))),
|
(0b1000, false) => {
|
||||||
(0b1000, true) => return Ok(Instruction::ST(28.into(), dr, IncrementMode::ConstantOffset(q))),
|
return Ok(Instruction::LD(
|
||||||
(0b0000, false) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::ConstantOffset(q))),
|
dr,
|
||||||
(0b0000, true) => return Ok(Instruction::ST(30.into(), dr, IncrementMode::ConstantOffset(q))),
|
28.into(),
|
||||||
_ => {},
|
IncrementMode::ConstantOffset(q),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(0b1000, true) => {
|
||||||
|
return Ok(Instruction::ST(
|
||||||
|
28.into(),
|
||||||
|
dr,
|
||||||
|
IncrementMode::ConstantOffset(q),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(0b0000, false) => {
|
||||||
|
return Ok(Instruction::LD(
|
||||||
|
dr,
|
||||||
|
30.into(),
|
||||||
|
IncrementMode::ConstantOffset(q),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(0b0000, true) => {
|
||||||
|
return Ok(Instruction::ST(
|
||||||
|
30.into(),
|
||||||
|
dr,
|
||||||
|
IncrementMode::ConstantOffset(q),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(DecodingError::UndefinedInstruction(v))
|
Err(DecodingError::UndefinedInstruction(v))
|
||||||
|
|||||||
@ -57,11 +57,11 @@ impl GDBPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let checksum = u8::from_str_radix(
|
let checksum = u8::from_str_radix(
|
||||||
std::str::from_utf8(&checksum)
|
std::str::from_utf8(&checksum).map_err(|_| (GDBPacketError::InvalidFormat))?,
|
||||||
.map_err(|_| (GDBPacketError::InvalidFormat))?, 16)
|
16,
|
||||||
.map_err(|_| (GDBPacketError::InvalidFormat))?;
|
).map_err(|_| (GDBPacketError::InvalidFormat))?;
|
||||||
let p = GDBPacket {
|
let p = GDBPacket {
|
||||||
raw_data: decoded_data.clone()
|
raw_data: decoded_data.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if p.gen_checksum() == checksum {
|
if p.gen_checksum() == checksum {
|
||||||
@ -79,8 +79,11 @@ impl GDBPacket {
|
|||||||
let mut r = Vec::new();
|
let mut r = Vec::new();
|
||||||
for e in self.raw_data.iter() {
|
for e in self.raw_data.iter() {
|
||||||
match *e {
|
match *e {
|
||||||
b'$' | b'#' | b'}' | b'*' => { r.push(b'}'); r.push(*e ^ 0x20); }
|
b'$' | b'#' | b'}' | b'*' => {
|
||||||
_ => r.push(*e)
|
r.push(b'}');
|
||||||
|
r.push(*e ^ 0x20);
|
||||||
|
}
|
||||||
|
_ => r.push(*e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r
|
r
|
||||||
@ -117,7 +120,8 @@ struct GDBStub<'a> {
|
|||||||
impl<'a> GDBStub<'a> {
|
impl<'a> GDBStub<'a> {
|
||||||
fn stop_reply(&self) -> String {
|
fn stop_reply(&self) -> String {
|
||||||
// Send SIGTRAP along with SREG/SP/PC.
|
// Send SIGTRAP along with SREG/SP/PC.
|
||||||
format!("T0520:{:02X};21:{:04X};22:{:08X};",
|
format!(
|
||||||
|
"T0520:{:02X};21:{:04X};22:{:08X};",
|
||||||
self.chip.cpu.sreg,
|
self.chip.cpu.sreg,
|
||||||
self.chip.cpu.get_sp(&self.chip.ram).swap_bytes(),
|
self.chip.cpu.get_sp(&self.chip.ram).swap_bytes(),
|
||||||
(2 * self.chip.cpu.pc).swap_bytes()
|
(2 * self.chip.cpu.pc).swap_bytes()
|
||||||
@ -135,7 +139,9 @@ impl<'a> GDBStub<'a> {
|
|||||||
panic!("Connection closed?")
|
panic!("Connection closed?")
|
||||||
}
|
}
|
||||||
// Wait for beginning of pkg.
|
// Wait for beginning of pkg.
|
||||||
if buf.len() == 0 && s[0] != b'$' { continue; }
|
if buf.len() == 0 && s[0] != b'$' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
buf.push(s[0]);
|
buf.push(s[0]);
|
||||||
|
|
||||||
if !has_checksum {
|
if !has_checksum {
|
||||||
@ -145,7 +151,10 @@ impl<'a> GDBStub<'a> {
|
|||||||
if n_checksum_bytes == 2 {
|
if n_checksum_bytes == 2 {
|
||||||
// Can we parse the packet?
|
// Can we parse the packet?
|
||||||
match GDBPacket::from_packet(&buf) {
|
match GDBPacket::from_packet(&buf) {
|
||||||
Ok(p) => { pkg = Some(p); break 'rx_loop; },
|
Ok(p) => {
|
||||||
|
pkg = Some(p);
|
||||||
|
break 'rx_loop;
|
||||||
|
}
|
||||||
Err(_) => panic!("Could not parse pkg: {:?}", buf),
|
Err(_) => panic!("Could not parse pkg: {:?}", buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,17 +163,22 @@ impl<'a> GDBStub<'a> {
|
|||||||
let pkg = pkg.unwrap();
|
let pkg = pkg.unwrap();
|
||||||
// Try to parse the string.
|
// Try to parse the string.
|
||||||
let response = std::str::from_utf8(&pkg.raw_data)
|
let response = std::str::from_utf8(&pkg.raw_data)
|
||||||
.map_err(|_| ())?.to_string();
|
.map_err(|_| ())?
|
||||||
|
.to_string();
|
||||||
|
|
||||||
// Split it into command and values.
|
// Split it into command and values.
|
||||||
if response.chars().nth(0).ok_or(())? == 'v' {
|
if response.chars().nth(0).ok_or(())? == 'v' {
|
||||||
// Multibyte word, up to the first ; (or others?).
|
// Multibyte word, up to the first ; (or others?).
|
||||||
let word_payload = response.split(";").collect::<Vec<_>>();
|
let word_payload = response.split(";").collect::<Vec<_>>();
|
||||||
Ok((word_payload[0].to_string(),
|
Ok((
|
||||||
word_payload[1..].join(";").to_string()))
|
word_payload[0].to_string(),
|
||||||
|
word_payload[1..].join(";").to_string(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((response.chars().nth(0).ok_or(())?.to_string(),
|
Ok((
|
||||||
response.chars().skip(1).collect::<String>()))
|
response.chars().nth(0).ok_or(())?.to_string(),
|
||||||
|
response.chars().skip(1).collect::<String>(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,11 +208,12 @@ impl<'a> GDBStub<'a> {
|
|||||||
let query_data = split_definitions(&payload);
|
let query_data = split_definitions(&payload);
|
||||||
match &*query_data[0].0 {
|
match &*query_data[0].0 {
|
||||||
"Supported" => {
|
"Supported" => {
|
||||||
response = "qXfer:memory-map:read+;PacketSize=1024".into();
|
response =
|
||||||
},
|
"qXfer:memory-map:read+;PacketSize=1024,hwbreak+,swbreak+".into();
|
||||||
|
}
|
||||||
"Attached" => {
|
"Attached" => {
|
||||||
response = "1".into();
|
response = "1".into();
|
||||||
},
|
}
|
||||||
"Xfer" => {
|
"Xfer" => {
|
||||||
response = format!(
|
response = format!(
|
||||||
"l<memory-map>\n\
|
"l<memory-map>\n\
|
||||||
@ -206,41 +221,40 @@ impl<'a> GDBStub<'a> {
|
|||||||
<memory type='flash' start='0' length='0x{:X}'>\n\
|
<memory type='flash' start='0' length='0x{:X}'>\n\
|
||||||
<property name='blocksize'>0x80</property>\n\
|
<property name='blocksize'>0x80</property>\n\
|
||||||
</memory></memory-map>",
|
</memory></memory-map>",
|
||||||
self.chip.ram.len(), self.chip.rom.len()
|
self.chip.ram.len(),
|
||||||
).to_string().into();
|
self.chip.rom.len()
|
||||||
},
|
).to_string()
|
||||||
|
.into();
|
||||||
|
}
|
||||||
"C" => response = "01".into(),
|
"C" => response = "01".into(),
|
||||||
query => {
|
query => {
|
||||||
warn!(self.log, "Unknown query: '{}'", query);
|
warn!(self.log, "Unknown query: '{}'", query);
|
||||||
response = "".into();
|
response = "".into();
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"H" => response = "OK".into(),
|
"H" => response = "OK".into(),
|
||||||
"?" => response = "S05".into(),
|
"?" => response = self.stop_reply().into(),
|
||||||
"g" => {
|
"g" => {
|
||||||
// Read registers.
|
// Read registers.
|
||||||
let mut reg_vals = Vec::new();
|
let mut reg_vals = Vec::new();
|
||||||
// R0-R31
|
// R0-R31
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
reg_vals.push(
|
reg_vals.push(format!("{:02X}", self.chip.cpu.registers[i]));
|
||||||
format!("{:02X}", self.chip.cpu.registers[i]));
|
|
||||||
}
|
}
|
||||||
// SREG
|
// SREG
|
||||||
reg_vals.push(format!("{:02X}", self.chip.cpu.sreg));
|
reg_vals.push(format!("{:02X}", self.chip.cpu.sreg));
|
||||||
// SP
|
// SP
|
||||||
reg_vals.push(
|
reg_vals.push(format!(
|
||||||
format!(
|
|
||||||
"{:04X}",
|
"{:04X}",
|
||||||
self.chip.cpu.get_sp(&self.chip.ram).swap_bytes()
|
self.chip.cpu.get_sp(&self.chip.ram).swap_bytes()
|
||||||
)
|
));
|
||||||
);
|
|
||||||
// PC
|
// PC
|
||||||
reg_vals.push(
|
reg_vals.push(format!("{:08X}", (2 * self.chip.cpu.pc).swap_bytes()));
|
||||||
format!("{:08X}", (2 * self.chip.cpu.pc).swap_bytes()));
|
|
||||||
|
|
||||||
response = reg_vals.join("").into();
|
response = reg_vals.join("").into();
|
||||||
},
|
}
|
||||||
|
// TODO: G (for setting all regs).
|
||||||
"s" | "c" => {
|
"s" | "c" => {
|
||||||
// Step / Continue
|
// Step / Continue
|
||||||
// Parse resume from.
|
// Parse resume from.
|
||||||
@ -265,7 +279,7 @@ impl<'a> GDBStub<'a> {
|
|||||||
}
|
}
|
||||||
// Send a stop reply.
|
// Send a stop reply.
|
||||||
response = self.stop_reply().into();
|
response = self.stop_reply().into();
|
||||||
},
|
}
|
||||||
"m" => {
|
"m" => {
|
||||||
// Read memory.
|
// Read memory.
|
||||||
let parts = payload.split(",").collect::<Vec<_>>();
|
let parts = payload.split(",").collect::<Vec<_>>();
|
||||||
@ -275,7 +289,6 @@ impl<'a> GDBStub<'a> {
|
|||||||
let mut err = false;
|
let mut err = false;
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let addr = mem_addr.wrapping_add(i);
|
let addr = mem_addr.wrapping_add(i);
|
||||||
// TODO: Overflow checks.
|
|
||||||
if addr & 0x00f00000 > 0 {
|
if addr & 0x00f00000 > 0 {
|
||||||
// RAM:
|
// RAM:
|
||||||
let addr_i = addr & 0xFFFFF;
|
let addr_i = addr & 0xFFFFF;
|
||||||
@ -304,7 +317,7 @@ impl<'a> GDBStub<'a> {
|
|||||||
} else {
|
} else {
|
||||||
response = data.join("").into();
|
response = data.join("").into();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"M" => {
|
"M" => {
|
||||||
// Write memory.
|
// Write memory.
|
||||||
let addrlen_content = payload.split(":").collect::<Vec<_>>();
|
let addrlen_content = payload.split(":").collect::<Vec<_>>();
|
||||||
@ -315,7 +328,6 @@ impl<'a> GDBStub<'a> {
|
|||||||
let mut err = false;
|
let mut err = false;
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let addr = mem_addr.wrapping_add(i);
|
let addr = mem_addr.wrapping_add(i);
|
||||||
// TODO: Overflow checks.
|
|
||||||
if addr & 0x00f00000 > 0 {
|
if addr & 0x00f00000 > 0 {
|
||||||
// RAM:
|
// RAM:
|
||||||
let addr_i = addr & 0xFFFFF;
|
let addr_i = addr & 0xFFFFF;
|
||||||
@ -323,14 +335,16 @@ impl<'a> GDBStub<'a> {
|
|||||||
err = true;
|
err = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.chip.ram[addr_i] = u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap_or(0);
|
self.chip.ram[addr_i] =
|
||||||
|
u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap_or(0);
|
||||||
} else {
|
} else {
|
||||||
// ROM
|
// ROM
|
||||||
if addr >= self.chip.rom.len() {
|
if addr >= self.chip.rom.len() {
|
||||||
err = true;
|
err = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.chip.rom[addr] = u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap_or(0);
|
self.chip.rom[addr] =
|
||||||
|
u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap_or(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err {
|
if err {
|
||||||
@ -338,7 +352,7 @@ impl<'a> GDBStub<'a> {
|
|||||||
} else {
|
} else {
|
||||||
response = "OK".into();
|
response = "OK".into();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"z" | "Z" => {
|
"z" | "Z" => {
|
||||||
// insert(Z)/remove(z) breakpoint.
|
// insert(Z)/remove(z) breakpoint.
|
||||||
let values = payload.split(",").collect::<Vec<_>>();
|
let values = payload.split(",").collect::<Vec<_>>();
|
||||||
@ -357,7 +371,7 @@ impl<'a> GDBStub<'a> {
|
|||||||
} else {
|
} else {
|
||||||
response = "E05".into(); // TODO: Which error would be correct?
|
response = "E05".into(); // TODO: Which error would be correct?
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"vMustReplyEmpty" => response = "".into(),
|
"vMustReplyEmpty" => response = "".into(),
|
||||||
_ => {
|
_ => {
|
||||||
info!(self.log, "Unknown cmd: {} {}", cmd, payload);
|
info!(self.log, "Unknown cmd: {} {}", cmd, payload);
|
||||||
@ -365,7 +379,9 @@ impl<'a> GDBStub<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!(self.log, "-> {}", response);
|
info!(self.log, "-> {}", response);
|
||||||
let response = GDBPacket { raw_data: response.as_bytes().to_vec() };
|
let response = GDBPacket {
|
||||||
|
raw_data: response.as_bytes().to_vec(),
|
||||||
|
};
|
||||||
conn.write_all(&response.to_packet_format()).unwrap();
|
conn.write_all(&response.to_packet_format()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/regs.rs
14
src/regs.rs
@ -22,10 +22,12 @@ pub enum StatusFlag {
|
|||||||
Carry = 1 << 0,
|
Carry = 1 << 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for StatusFlag {
|
impl fmt::Display for StatusFlag {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", match *self {
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match *self {
|
||||||
StatusFlag::GlobalInterruptEnable => "I",
|
StatusFlag::GlobalInterruptEnable => "I",
|
||||||
StatusFlag::BitCopyStorage => "T",
|
StatusFlag::BitCopyStorage => "T",
|
||||||
StatusFlag::HalfCarry => "H",
|
StatusFlag::HalfCarry => "H",
|
||||||
@ -34,7 +36,8 @@ impl fmt::Display for StatusFlag {
|
|||||||
StatusFlag::Negative => "N",
|
StatusFlag::Negative => "N",
|
||||||
StatusFlag::Zero => "Z",
|
StatusFlag::Zero => "Z",
|
||||||
StatusFlag::Carry => "C",
|
StatusFlag::Carry => "C",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +84,7 @@ impl StatusFlag {
|
|||||||
StatusFlag::SignBit,
|
StatusFlag::SignBit,
|
||||||
StatusFlag::HalfCarry,
|
StatusFlag::HalfCarry,
|
||||||
StatusFlag::BitCopyStorage,
|
StatusFlag::BitCopyStorage,
|
||||||
StatusFlag::GlobalInterruptEnable
|
StatusFlag::GlobalInterruptEnable,
|
||||||
][i as usize])
|
][i as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,14 +126,12 @@ impl PartialEq for GeneralPurposeRegister {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for GeneralPurposeRegister {
|
impl fmt::Display for GeneralPurposeRegister {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "R{}", self.0)
|
write!(f, "R{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Mostly the same as above, but we want to make it a different type.
|
// Mostly the same as above, but we want to make it a different type.
|
||||||
// type GeneralPurposeRegisterPair = struct(u8);
|
// type GeneralPurposeRegisterPair = struct(u8);
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -173,7 +174,6 @@ impl fmt::Display for GeneralPurposeRegisterPair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub type PC = u32;
|
pub type PC = u32;
|
||||||
|
|
||||||
// TODO: Struct :)
|
// TODO: Struct :)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user