Add logging and random stuff
This commit is contained in:
parent
7b66f79278
commit
71fecb51a9
@ -4,3 +4,6 @@ version = "0.1.0"
|
||||
authors = ["Kevin Hamacher <kevin.hamacher@ruhr-uni-bochum.de>"]
|
||||
|
||||
[dependencies]
|
||||
slog = "2"
|
||||
slog-term = "2"
|
||||
slog-async = "2"
|
||||
|
||||
@ -55,6 +55,14 @@ pub enum IOAdress {
|
||||
SPL = 0x03D,
|
||||
SPH = 0x03E,
|
||||
SREG = 0x03F,
|
||||
|
||||
CLK_CTRL = 0x040,
|
||||
CLK_PSCTRL = 0x041,
|
||||
CLK_LOCK = 0x042,
|
||||
CLK_RTCCTRL = 0x043,
|
||||
CLK_USBCTRL = 0x044,
|
||||
|
||||
OSC_CTRL = 0x050,
|
||||
OSC_STATUS = 0x051,
|
||||
USARTC0_DATA = 0x8A0,
|
||||
USARTC0_STATUS = 0x8A1,
|
||||
|
||||
166
src/cpu.rs
166
src/cpu.rs
@ -8,6 +8,9 @@ use chip_definitions;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use slog;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CPUError {
|
||||
UnimplementedInstruction,
|
||||
@ -28,6 +31,8 @@ pub struct CPU {
|
||||
|
||||
// The same is true for the status register
|
||||
pub sreg: u8,
|
||||
|
||||
logger: slog::Logger,
|
||||
}
|
||||
|
||||
|
||||
@ -45,7 +50,7 @@ impl fmt::Display for CPU {
|
||||
}
|
||||
write!(f, "\n")?;
|
||||
for i in 0..32 {
|
||||
write!(f, " R{:-2} = 0x{:02X} ", i, self.registers[i])?;
|
||||
write!(f, " R{:-2}={:02X} ", i, self.registers[i])?;
|
||||
if (i + 1) % 10 == 0{
|
||||
write!(f, "\n")?;
|
||||
}
|
||||
@ -55,11 +60,12 @@ impl fmt::Display for CPU {
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(logger: slog::Logger) -> Self {
|
||||
CPU {
|
||||
registers: [0u8; 32],
|
||||
pc: 0, // Reset vector
|
||||
sreg: 0, // Uninitialized as well
|
||||
logger: logger
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,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 {
|
||||
@ -112,13 +118,63 @@ impl CPU {
|
||||
}
|
||||
|
||||
fn ram_write(&self, ram: &mut [u8], addr: u16, val: u8) -> Result<(), CPUError> {
|
||||
print!("[RAMW:{:04X}={:02X}] ", addr, val);
|
||||
// print!("[RAMW:{:04X}={:02X}] ", addr, val);
|
||||
if addr as usize >= ram.len() {
|
||||
Err(CPUError::OutOfBoundsException)
|
||||
} else {
|
||||
// TODO: Hooks
|
||||
if addr == chip_definitions::IOAdress::USARTC0_DATA as _ {
|
||||
print!("USART_OUT:{: <3} ({}) ", val, (val as char).escape_debug());
|
||||
if addr < 0x2000 {
|
||||
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);
|
||||
}
|
||||
if addr == chip_definitions::IOAdress::USARTC0_DATA as u16 {
|
||||
// print!("USART_OUT:{: <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::SPH as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::SREG as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::EIND as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPX as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPY as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPZ as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPD as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::OSC_CTRL as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::OSC_STATUS as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::CCP as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::CLK_CTRL as u16 {
|
||||
|
||||
} else if addr == 0x645 || addr == 0x641 || addr == 0x642 || addr == 0x646 { // PortC stuff
|
||||
|
||||
} else if addr == 0x8A3 || addr == 0x8A4 || addr == 0x8A5 || addr == 0x08A6 || addr == 0x8A7 { // Usart
|
||||
|
||||
} else if addr >= 0x1C0 && addr < 0x200 { // NVM
|
||||
|
||||
} else if addr == 0x600 || addr == 0x680 || addr == 0x626 || addr == 0x621 { // PortA/PortE
|
||||
|
||||
} else if addr == 0xA00 || addr == 0xA01 || addr == 0xA28 || addr == 0xA29 { // TCE0_CTRLA
|
||||
|
||||
} else if addr == 0xA2 { // PMIC
|
||||
|
||||
} else if addr == 0x43 { // CLK_RTCCTRL
|
||||
|
||||
} else if addr == 0x400 || addr == 0x401 || addr == 0x402 || addr == 0x40A || addr == 0x40B { // RTC_STATUS
|
||||
|
||||
} else if addr == 0x320 || addr == 0x321 || addr == 0x322 || addr == 0x328 || addr == 0x329 || addr == 0x32A || addr == 0x32B { // Dac
|
||||
//} else if addr == 0x238{
|
||||
|
||||
} else {
|
||||
return Err(CPUError::UnsupportedAddress);
|
||||
}*/
|
||||
}
|
||||
ram[addr as usize] = val;
|
||||
Ok(())
|
||||
@ -126,14 +182,18 @@ impl CPU {
|
||||
}
|
||||
|
||||
fn ram_read(&self, ram: &[u8], addr: u16) -> Result<u8, CPUError> {
|
||||
print!("[RAMR:{:04X}] ", addr);
|
||||
// print!("[RAMR:{:04X}] ", addr);
|
||||
if addr as usize >= ram.len() {
|
||||
Err(CPUError::OutOfBoundsException)
|
||||
} else {
|
||||
// TODO: Hooks
|
||||
if addr == chip_definitions::IOAdress::USARTC0_DATA as _ {
|
||||
return Err(CPUError::Exit);
|
||||
info!(self.logger, "Read from USART");
|
||||
// return Err(CPUError::Exit);
|
||||
// return Ok(b'\r')
|
||||
// return Ok(0);
|
||||
} else if addr == chip_definitions::IOAdress::USARTC0_STATUS as _ {
|
||||
// info!(self.logger, "Read from USART status");
|
||||
if self.pc == 0x5AC {
|
||||
// USART data check -> Yes, there is indeed data available!
|
||||
return Ok(0x80);
|
||||
@ -143,6 +203,52 @@ impl CPU {
|
||||
} else if addr == chip_definitions::IOAdress::OSC_STATUS as _ {
|
||||
// HACK: Osci is set right..
|
||||
return Ok(0x02);
|
||||
} else if addr < 0x2000 {
|
||||
if addr != chip_definitions::IOAdress::SPH as u16 && addr != chip_definitions::IOAdress::SPL as u16 {
|
||||
info!(self.logger, "Reading from IOR: {:04X}", addr);
|
||||
}
|
||||
/*
|
||||
if addr == chip_definitions::IOAdress::SPL as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::SPH as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::SREG as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::EIND as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPX as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPY as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPZ as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::RAMPD as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::OSC_CTRL as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::OSC_STATUS as u16 {
|
||||
|
||||
} else if addr == chip_definitions::IOAdress::CCP as u16 {
|
||||
|
||||
} else if addr > 0x1C0 && addr < 0x200 { // NVM status
|
||||
|
||||
} else if addr == 0x8A3 || addr == 0x8A4 { // Usart
|
||||
|
||||
} else if addr == 0xA2 { // PMIC
|
||||
|
||||
} else if addr == 0x402 { // RTC_INTCTRL
|
||||
|
||||
} else if addr == 0x400 || addr == 0x401 || addr == 0x402 { // RTC_CTRL
|
||||
|
||||
} else if addr == 0x320 || addr == 0x321 || addr == 0x322 {
|
||||
// DAC? @DD2E
|
||||
} else if addr == 0x230 || addr == 0x231 || addr == 0x234 || addr == 0x235 { // ADC
|
||||
} else if addr >= 0x1f00 {
|
||||
|
||||
} else {
|
||||
return Err(CPUError::UnsupportedAddress);
|
||||
}
|
||||
*/
|
||||
}
|
||||
Ok(ram[addr as usize])
|
||||
}
|
||||
@ -248,7 +354,7 @@ impl CPU {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(CPUError::DecodingError(e)),
|
||||
};
|
||||
print!("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;
|
||||
|
||||
@ -266,7 +372,13 @@ impl CPU {
|
||||
},
|
||||
Instruction::LDI(ref r, v) => self.set_register(r, v),
|
||||
Instruction::SER(ref r) => self.set_register(r, 0xFF),
|
||||
Instruction::RJMP(v) => self.pc = self.pc.wrapping_add(v as _),
|
||||
Instruction::RJMP(v) => {
|
||||
if v == -1 && self.test_flag(StatusFlag::GlobalInterruptEnable) == false {
|
||||
info!(self.logger, "HALTED ");
|
||||
return Err(CPUError::Exit);
|
||||
}
|
||||
self.pc = self.pc.wrapping_add(v as _);
|
||||
},
|
||||
Instruction::CLR_FLAG(v) => self.clear_flag(v),
|
||||
Instruction::SET_FLAG(v) => self.set_flag(v),
|
||||
Instruction::CPI(ref r, v) => {
|
||||
@ -313,6 +425,13 @@ impl CPU {
|
||||
},
|
||||
Instruction::LD(ref dst_reg, ref ptr, ref inc_mode) => {
|
||||
let base = self.get_register_pair(ptr);
|
||||
if ptr.low() == 26 && ram[chip_definitions::IOAdress::RAMPX as usize] > 0 {
|
||||
panic!("Unexpected");
|
||||
} else if ptr.low() == 28 && ram[chip_definitions::IOAdress::RAMPY as usize] > 0 {
|
||||
panic!("Unexpected");
|
||||
} else if ptr.low() == 30 && ram[chip_definitions::IOAdress::RAMPZ as usize] > 0 {
|
||||
panic!("Unexpected");
|
||||
}
|
||||
let addr = match *inc_mode {
|
||||
IncrementMode::None => base,
|
||||
IncrementMode::PreDecrement => {
|
||||
@ -329,18 +448,29 @@ impl CPU {
|
||||
self.set_register(dst_reg, v);
|
||||
},
|
||||
Instruction::ELPM(ref dst_reg, ref inc_mode) => {
|
||||
// TODO: RAMPZ
|
||||
let Z = self.get_register_pair(&30u8.into());
|
||||
let d = rom[Z as usize];
|
||||
self.set_register(dst_reg, d);
|
||||
|
||||
let Zb = self.get_register_pair(&30u8.into());
|
||||
// TODO: Only use required bits, other read as zero (according to datasheet)
|
||||
let Z =
|
||||
Zb as usize |
|
||||
(ram[chip_definitions::IOAdress::RAMPZ as usize] as usize) << 16
|
||||
;
|
||||
match *inc_mode {
|
||||
IncrementMode::PostIncrement => {
|
||||
self.set_register_pair(&30u8.into(), Z.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;
|
||||
},
|
||||
_ => {
|
||||
// This instruction does only support None + PostIncrement
|
||||
},
|
||||
}
|
||||
if Z >= rom.len() {
|
||||
warn!(self.logger, "ELPM OOB: RAMPZ={:02X} Z={:04X} len={:06X} ", Z >> 16, Zb, rom.len());
|
||||
// return Err(CPUError::OutOfBoundsException);
|
||||
return Ok(0xFF); // Hack I kno but emulator does it like that
|
||||
}
|
||||
let d = rom[Z as usize];
|
||||
self.set_register(dst_reg, d);
|
||||
},
|
||||
Instruction::LPM(ref dst_reg, ref inc_mode) => {
|
||||
let Z = self.get_register_pair(&30u8.into());
|
||||
@ -507,12 +637,16 @@ impl CPU {
|
||||
self.update_flags_zns_8(res);
|
||||
},
|
||||
Instruction::STS16(ref addr, ref r) => {
|
||||
let rampd = ram[chip_definitions::IOAdress::RAMPD as usize] as u32;
|
||||
if rampd != 0 { panic!("This is unexpected (for now)"); }
|
||||
self.ram_write(ram, *addr, self.get_register(r))?;
|
||||
},
|
||||
Instruction::STS8(ref addr, ref r) => {
|
||||
self.ram_write(ram, *addr as u16, self.get_register(r))?;
|
||||
},
|
||||
Instruction::LDS16(ref r, ref addr) => {
|
||||
let rampd = ram[chip_definitions::IOAdress::RAMPD as usize] as u32;
|
||||
if rampd != 0 { panic!("This is unexpected (for now)"); }
|
||||
let v = self.ram_read(ram, *addr)?;
|
||||
self.set_register(r, v);
|
||||
},
|
||||
|
||||
@ -547,13 +547,16 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
||||
|
||||
// STS return '1010 1kkk rrrr kkkk'.replace(' ', '')
|
||||
// LDS return '1010 0kkk dddd kkkk'.replace(' ', '')
|
||||
// 1010 0kkk dddd kkkk
|
||||
// ST_ return "10q0 qq1r rrrr 0qqq".replace(' ', '')
|
||||
// 10q0 qq1r rrrr 0qqq
|
||||
let r16 = (((v >> 4) & 0b1111) as u8).into();
|
||||
let k = (((v >> 4) & 0b111_0000) | (v & 0b1111)) as u8;
|
||||
match v & 0b1111_1000_0000_0000 {
|
||||
0b1011_1000_0000_0000 => return Ok(Instruction::OUT(A, r)),
|
||||
0b1011_0000_0000_0000 => return Ok(Instruction::IN(r, A)),
|
||||
0b1010_1000_0000_0000 => return Ok(Instruction::STS8(k, r16)),
|
||||
0b1010_0000_0000_0000 => return Ok(Instruction::LDS8(r16, k)),
|
||||
0b1010_1000_0000_0001 => return Ok(Instruction::STS8(k + 0x40, r16)), // Disabled, can't be used
|
||||
0b1010_0000_0000_0001 => return Ok(Instruction::LDS8(r16, k + 0x40)), // Disabled, can't be used
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
40
src/main.rs
40
src/main.rs
@ -4,6 +4,14 @@ use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::fs;
|
||||
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate slog_term;
|
||||
extern crate slog_async;
|
||||
|
||||
use slog::Drain;
|
||||
|
||||
|
||||
mod cpu;
|
||||
mod regs;
|
||||
mod decoder;
|
||||
@ -11,22 +19,32 @@ mod chip;
|
||||
mod chip_definitions;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let mut rom = read_file("rom.bin").unwrap();
|
||||
let mut ram = [0u8; 8 * 1024 + 8 * 1024];
|
||||
let mut cpu = cpu::CPU::new();
|
||||
let decorator = slog_term::PlainDecorator::new(std::io::stdout());
|
||||
let drain = slog_term::CompactFormat::new(decorator).build().fuse();
|
||||
let drain = slog_async::Async::new(drain).build().fuse();
|
||||
|
||||
for _ in 0..280000 {
|
||||
let log = slog::Logger::root(
|
||||
slog::LevelFilter::new(drain, slog::Level::Info).fuse(),
|
||||
o!("version" => "0.1")
|
||||
);
|
||||
info!(log, "AVREmu starting up");
|
||||
|
||||
let mut rom = read_file(
|
||||
std::env::args().nth(1).unwrap_or("rom.bin".to_string())).unwrap();
|
||||
let mut ram = [0u8; 8 * 1024 + 8 * 1024];
|
||||
let mut cpu = cpu::CPU::new(log.clone());
|
||||
|
||||
loop {
|
||||
let r = cpu.step(&mut rom, &mut ram);
|
||||
println!("{:?}", r);
|
||||
match r {
|
||||
Err(cpu::CPUError::OutOfBoundsException) => break,
|
||||
Err(cpu::CPUError::Exit) => break,
|
||||
Err(cpu::CPUError::UnimplementedInstruction) => break,
|
||||
_ => {}
|
||||
Ok(_) => {}
|
||||
Err(ref e) => {
|
||||
warn!(log, "Error occured: {:?}", e);
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
println!("{}", cpu);
|
||||
warn!(log, "{}", cpu);
|
||||
write_file("ram.dmp", &ram).unwrap();
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user