Add device tree
This commit is contained in:
parent
243675342a
commit
37ef30d1a1
32
src/chip.rs
32
src/chip.rs
@ -1,27 +1,53 @@
|
|||||||
use cpu::CPU;
|
use cpu::CPU;
|
||||||
|
use devices;
|
||||||
|
|
||||||
use slog;
|
use slog;
|
||||||
|
|
||||||
|
|
||||||
pub struct Chip {
|
pub struct Chip {
|
||||||
log: slog::Logger,
|
log: slog::Logger,
|
||||||
pub cpu: CPU,
|
pub cpu: CPU,
|
||||||
pub rom: Box<[u8]>,
|
pub rom: Box<[u8]>,
|
||||||
pub ram: Box<[u8]>,
|
pub device_tree: devices::DeviceTree,
|
||||||
|
|
||||||
// TODO: List of devices
|
// TODO: List of devices
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chip {
|
impl Chip {
|
||||||
pub fn new(log: slog::Logger, rom: Box<[u8]>) -> Chip {
|
pub fn new(log: slog::Logger, rom: Box<[u8]>) -> Chip {
|
||||||
|
// Internal registers
|
||||||
|
let internal_regs = devices::ram::RAM::new(log.clone());
|
||||||
|
let ram_device = devices::ram::RAM::new(log.clone());
|
||||||
|
let usart_device = devices::usart::USART::new(log.clone());
|
||||||
|
let mut dev_tree = devices::DeviceTree::new(log.clone());
|
||||||
|
|
||||||
|
// Add RAM and USART
|
||||||
|
dev_tree.add_device(
|
||||||
|
devices::Device::new(Box::new(ram_device), 0x2000, 0x2000)
|
||||||
|
);
|
||||||
|
dev_tree.add_device(
|
||||||
|
devices::Device::new(Box::new(internal_regs), 0, 0x40)
|
||||||
|
);
|
||||||
|
dev_tree.add_device(
|
||||||
|
devices::Device::new(Box::new(usart_device), 0x8A0, 0x8A7 - 0x8A0 + 1)
|
||||||
|
);
|
||||||
|
dev_tree.add_device(
|
||||||
|
devices::Device::new(
|
||||||
|
Box::new(devices::oscillator::Oscillator::new(log.clone())),
|
||||||
|
0x50, 0x07
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
log: log.clone(),
|
log: log.clone(),
|
||||||
cpu: CPU::new(log),
|
cpu: CPU::new(log),
|
||||||
rom: rom,
|
rom: rom,
|
||||||
ram: Box::new([0u8; 0x4000]),
|
device_tree: dev_tree,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self) -> bool {
|
pub fn step(&mut self) -> bool {
|
||||||
match self.cpu.step(&mut self.rom, &mut self.ram) {
|
match self.cpu.step(&mut self.rom, &mut self.device_tree) {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
warn!(self.log, "Error occured: {:?}", e);
|
warn!(self.log, "Error occured: {:?}", e);
|
||||||
|
|||||||
266
src/cpu.rs
266
src/cpu.rs
@ -6,6 +6,8 @@ use decoder::{IncrementMode, Instruction};
|
|||||||
use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, StatusFlag};
|
use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, StatusFlag};
|
||||||
use chip_definitions;
|
use chip_definitions;
|
||||||
|
|
||||||
|
use devices::DeviceTree;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use slog;
|
use slog;
|
||||||
@ -73,14 +75,15 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sp(&self, mem: &[u8]) -> u16 {
|
pub fn get_sp(&self, mem: &mut DeviceTree) -> u16 {
|
||||||
u16::from(mem[chip_definitions::IOAdress::SPL as usize])
|
let spl: u16 = mem.read(chip_definitions::IOAdress::SPL as u32) as u16;
|
||||||
| (u16::from(mem[chip_definitions::IOAdress::SPH as usize]) << 8)
|
let sph: u16 = mem.read(chip_definitions::IOAdress::SPH as u32) as u16;
|
||||||
|
sph << 8 | spl
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sp(&self, mem: &mut [u8], val: u16) {
|
fn set_sp(&self, mem: &mut DeviceTree, val: u16) {
|
||||||
mem[chip_definitions::IOAdress::SPL as usize] = val as u8;
|
mem.write(chip_definitions::IOAdress::SPL as u32, val as u8);
|
||||||
mem[chip_definitions::IOAdress::SPH as usize] = (val >> 8) as u8;
|
mem.write(chip_definitions::IOAdress::SPH as u32, (val >> 8) as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_flag(&self, flag: StatusFlag) -> bool {
|
fn test_flag(&self, flag: StatusFlag) -> bool {
|
||||||
@ -121,163 +124,26 @@ impl CPU {
|
|||||||
self.registers[r.as_usize()] = v;
|
self.registers[r.as_usize()] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ram_write(&self, ram: &mut [u8], addr: u16, val: u8) -> Result<(), CPUError> {
|
fn ram_write(&self, device_tree: &mut DeviceTree, addr: u16, val: u8) -> Result<(), CPUError> {
|
||||||
if addr as usize >= ram.len() {
|
device_tree.write(addr as u32, val);
|
||||||
error!(self.logger, "Ram write OOB: {:04X}={:02X}] ", addr, val);
|
|
||||||
Err(CPUError::OutOfBoundsException)
|
|
||||||
} else {
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::IOAdress::USARTC0_DATA as _ {
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
return Ok(0x20); // Usart is ready to send.
|
|
||||||
}
|
|
||||||
} 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])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self, ram: &mut [u8]) -> Result<u8, CPUError> {
|
fn ram_read(&self, device_tree: &mut DeviceTree, addr: u16) -> Result<u8, CPUError> {
|
||||||
let sp = self.get_sp(ram);
|
Ok(device_tree.read(addr as u32))
|
||||||
self.set_sp(ram, sp.wrapping_add(1));
|
}
|
||||||
self.ram_read(ram, sp.wrapping_add(1))
|
|
||||||
|
fn push(&mut self, device_tree: &mut DeviceTree, val: u8) -> Result<(), CPUError> {
|
||||||
|
let sp = self.get_sp(device_tree);
|
||||||
|
self.ram_write(device_tree, sp, val)?;
|
||||||
|
self.set_sp(device_tree, sp.wrapping_sub(1));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self, device_tree: &mut DeviceTree) -> Result<u8, CPUError> {
|
||||||
|
let sp = self.get_sp(device_tree);
|
||||||
|
self.set_sp(device_tree, sp.wrapping_add(1));
|
||||||
|
self.ram_read(device_tree, sp.wrapping_add(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag update functions on a single value:
|
// Flag update functions on a single value:
|
||||||
@ -366,7 +232,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns # of ticks the executed instruction took
|
// Returns # of ticks the executed instruction took
|
||||||
pub fn step(&mut self, rom: &mut [u8], ram: &mut [u8]) -> Result<usize, CPUError> {
|
pub fn step(&mut self, rom: &mut [u8], device_tree: &mut DeviceTree) -> Result<usize, CPUError> {
|
||||||
// Instruction fetch
|
// Instruction fetch
|
||||||
if (self.pc as usize) * 2 >= rom.len() {
|
if (self.pc as usize) * 2 >= rom.len() {
|
||||||
return Err(CPUError::OutOfBoundsException);
|
return Err(CPUError::OutOfBoundsException);
|
||||||
@ -380,7 +246,7 @@ impl CPU {
|
|||||||
self.logger,
|
self.logger,
|
||||||
"CPU: pc={:06X} sp={:04X} Fetch: {: <40}",
|
"CPU: pc={:06X} sp={:04X} Fetch: {: <40}",
|
||||||
self.pc,
|
self.pc,
|
||||||
self.get_sp(ram),
|
self.get_sp(device_tree),
|
||||||
format!("{}", ins)
|
format!("{}", ins)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -449,10 +315,12 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
IncrementMode::ConstantOffset(o) => base.wrapping_add(u16::from(o)),
|
IncrementMode::ConstantOffset(o) => base.wrapping_add(u16::from(o)),
|
||||||
};
|
};
|
||||||
self.ram_write(ram, addr, self.get_register(src_reg))?;
|
self.ram_write(device_tree, 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);
|
||||||
|
/*
|
||||||
|
// TODO: RAMPX/Y/Z
|
||||||
if ptr.low() == 26 && ram[chip_definitions::IOAdress::RAMPX as usize] > 0 {
|
if ptr.low() == 26 && ram[chip_definitions::IOAdress::RAMPX as usize] > 0 {
|
||||||
panic!("Unexpected");
|
panic!("Unexpected");
|
||||||
} else if ptr.low() == 28 && ram[chip_definitions::IOAdress::RAMPY as usize] > 0 {
|
} else if ptr.low() == 28 && ram[chip_definitions::IOAdress::RAMPY as usize] > 0 {
|
||||||
@ -460,6 +328,7 @@ impl CPU {
|
|||||||
} else if ptr.low() == 30 && ram[chip_definitions::IOAdress::RAMPZ as usize] > 0 {
|
} else if ptr.low() == 30 && ram[chip_definitions::IOAdress::RAMPZ as usize] > 0 {
|
||||||
panic!("Unexpected");
|
panic!("Unexpected");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
let addr = match *inc_mode {
|
let addr = match *inc_mode {
|
||||||
IncrementMode::None => base,
|
IncrementMode::None => base,
|
||||||
IncrementMode::PreDecrement => {
|
IncrementMode::PreDecrement => {
|
||||||
@ -472,20 +341,21 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
IncrementMode::ConstantOffset(o) => base.wrapping_add(u16::from(o)),
|
IncrementMode::ConstantOffset(o) => base.wrapping_add(u16::from(o)),
|
||||||
};
|
};
|
||||||
let v = self.ram_read(ram, addr)?;
|
let v = self.ram_read(device_tree, 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 | (ram[chip_definitions::IOAdress::RAMPZ as usize] as usize) << 16;
|
Zb as usize |
|
||||||
|
(device_tree.read(chip_definitions::IOAdress::RAMPZ as u32) 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] =
|
device_tree.write(chip_definitions::IOAdress::RAMPZ as u32, (Z.wrapping_add(1) >> 16) as u8);
|
||||||
(Z.wrapping_add(1) >> 16) as u8;
|
},
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
// This instruction does only support None + PostIncrement
|
// This instruction does only support None + PostIncrement
|
||||||
}
|
}
|
||||||
@ -519,40 +389,40 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
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(device_tree, *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(device_tree, *addr)?;
|
||||||
self.set_register(reg, v);
|
self.set_register(reg, v);
|
||||||
}
|
}
|
||||||
Instruction::CALL(ref addr) => {
|
Instruction::CALL(ref addr) => {
|
||||||
let ret_to = self.pc;
|
let ret_to = self.pc;
|
||||||
self.push(ram, ((ret_to >> 16) & 0xFF) as u8)?;
|
self.push(device_tree, ((ret_to >> 16) & 0xFF) as u8)?;
|
||||||
self.push(ram, ((ret_to >> 8) & 0xFF) as u8)?;
|
self.push(device_tree, ((ret_to >> 8) & 0xFF) as u8)?;
|
||||||
self.push(ram, (ret_to & 0xFF) as u8)?;
|
self.push(device_tree, (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(device_tree, ((ret_to >> 16) & 0xFF) as u8)?;
|
||||||
self.push(ram, ((ret_to >> 8) & 0xFF) as u8)?;
|
self.push(device_tree, ((ret_to >> 8) & 0xFF) as u8)?;
|
||||||
self.push(ram, (ret_to & 0xFF) as u8)?;
|
self.push(device_tree, (ret_to & 0xFF) as u8)?;
|
||||||
self.pc = ((self.pc as i32) + i32::from(*addr)) as u32;
|
self.pc = (self.pc as i32 + *addr as i32) as u32;
|
||||||
}
|
},
|
||||||
Instruction::RET => {
|
Instruction::RET => {
|
||||||
let mut ret_to = u32::from(self.pop(ram)?);
|
let mut ret_to = self.pop(device_tree)? as u32;
|
||||||
ret_to += u32::from(self.pop(ram)?) << 8;
|
ret_to += (self.pop(device_tree)? as u32) << 8;
|
||||||
ret_to += u32::from(self.pop(ram)?) << 16;
|
ret_to += (self.pop(device_tree)? 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(device_tree)?;
|
||||||
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(device_tree, 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);
|
||||||
@ -675,25 +545,21 @@ impl CPU {
|
|||||||
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 = u32::from(ram[chip_definitions::IOAdress::RAMPD as usize]);
|
let rampd = device_tree.read(chip_definitions::IOAdress::RAMPD as u32);
|
||||||
if rampd != 0 {
|
if rampd != 0 { panic!("This is unexpected (for now)"); }
|
||||||
panic!("This is unexpected (for now)");
|
self.ram_write(device_tree, *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, u16::from(*addr), self.get_register(r))?;
|
self.ram_write(device_tree, *addr as u16, self.get_register(r))?;
|
||||||
}
|
},
|
||||||
Instruction::LDS16(ref r, ref addr) => {
|
Instruction::LDS16(ref r, ref addr) => {
|
||||||
let rampd = u32::from(ram[chip_definitions::IOAdress::RAMPD as usize]);
|
let rampd = device_tree.read(chip_definitions::IOAdress::RAMPD as u32);
|
||||||
if rampd != 0 {
|
if rampd != 0 { panic!("This is unexpected (for now)"); }
|
||||||
panic!("This is unexpected (for now)");
|
let v = self.ram_read(device_tree, *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, u16::from(*addr))?;
|
let v = self.ram_read(device_tree, *addr as u16)?;
|
||||||
self.set_register(r, v);
|
self.set_register(r, v);
|
||||||
}
|
}
|
||||||
Instruction::LSL(ref r) => {
|
Instruction::LSL(ref r) => {
|
||||||
|
|||||||
79
src/devices/mod.rs
Normal file
79
src/devices/mod.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// All devices are implemented here.
|
||||||
|
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
pub mod ram;
|
||||||
|
pub mod usart;
|
||||||
|
pub mod oscillator;
|
||||||
|
|
||||||
|
pub trait DeviceImpl {
|
||||||
|
/// addr relative to the start of the device memory map.
|
||||||
|
fn read(&mut self, addr: u32) -> u8;
|
||||||
|
/// addr relative to the start of the device memory map.
|
||||||
|
fn write(&mut self, addr: u32, value: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Device {
|
||||||
|
start_addr: u32,
|
||||||
|
addr_len: u32,
|
||||||
|
device: Box<DeviceImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device {
|
||||||
|
pub fn new(device: Box<DeviceImpl>, start_addr: u32, addr_len: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
start_addr: start_addr,
|
||||||
|
addr_len: addr_len,
|
||||||
|
device: device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handles_addr(&self, addr: u32) -> bool {
|
||||||
|
addr >= self.start_addr && addr - self.start_addr < self.addr_len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, addr: u32) -> u8 {
|
||||||
|
self.device.read(addr - self.start_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, addr: u32, val: u8) {
|
||||||
|
self.device.write(addr - self.start_addr, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DeviceTree {
|
||||||
|
log: Logger,
|
||||||
|
devices: Vec<Device>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceTree {
|
||||||
|
pub fn new(log: Logger) -> Self {
|
||||||
|
Self {
|
||||||
|
log: log,
|
||||||
|
devices: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_device(&mut self, device: Device) {
|
||||||
|
self.devices.push(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_device_for_addr(&mut self, addr: u32) -> Option<&mut Device> {
|
||||||
|
self.devices.iter_mut().filter(|d| d.handles_addr(addr)).nth(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, addr: u32) -> u8 {
|
||||||
|
if let Some(ref mut d) = self.get_device_for_addr(addr) {
|
||||||
|
return d.read(addr);
|
||||||
|
}
|
||||||
|
warn!(self.log, "Trying to read unmapped I/O: {:08X}", addr);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, addr: u32, val: u8) {
|
||||||
|
if let Some(ref mut d) = self.get_device_for_addr(addr) {
|
||||||
|
return d.write(addr, val);
|
||||||
|
}
|
||||||
|
warn!(self.log, "Trying to write unmapped I/O: {:08X} <- {:02X}", addr, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
120
src/devices/oscillator.rs
Normal file
120
src/devices/oscillator.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// Oscillator
|
||||||
|
use devices::DeviceImpl;
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
const OSC_CTRL: u32 = 0;
|
||||||
|
const OSC_STATUS: u32 = 1;
|
||||||
|
const OSC_XOSCCTRL: u32 = 2;
|
||||||
|
const OSC_XOSCFAIL: u32 = 3;
|
||||||
|
const OSC_RC32KCAL: u32 = 4;
|
||||||
|
const OSC_PLLCTRL: u32 = 5;
|
||||||
|
const OSC_DFLLCTRL: u32 = 6;
|
||||||
|
|
||||||
|
enum PllSrc {
|
||||||
|
RC2M,
|
||||||
|
RC32M,
|
||||||
|
XOSC,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Oscillator {
|
||||||
|
log: Logger,
|
||||||
|
reg_values: [u8; 7],
|
||||||
|
|
||||||
|
// Real attributes:
|
||||||
|
ctrl: u8,
|
||||||
|
status: u8,
|
||||||
|
xoscctrl: u8,
|
||||||
|
xoscfail: u8,
|
||||||
|
rs32kcal: u8,
|
||||||
|
pllsrc: PllSrc,
|
||||||
|
pllfac: u8,
|
||||||
|
dfllctrl: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Oscillator {
|
||||||
|
pub fn new(log: Logger) -> Self {
|
||||||
|
Self {
|
||||||
|
log: log,
|
||||||
|
reg_values: [0u8; 7],
|
||||||
|
|
||||||
|
ctrl: 0,
|
||||||
|
status: 0,
|
||||||
|
xoscctrl: 0,
|
||||||
|
xoscfail: 0,
|
||||||
|
rs32kcal: 0,
|
||||||
|
pllsrc: PllSrc::RC2M,
|
||||||
|
pllfac: 0,
|
||||||
|
dfllctrl: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceImpl for Oscillator {
|
||||||
|
fn read(&mut self, addr: u32) -> u8 {
|
||||||
|
match addr {
|
||||||
|
OSC_CTRL => {
|
||||||
|
// PLL and clock ready.
|
||||||
|
return self.ctrl | 0x30;
|
||||||
|
}
|
||||||
|
OSC_STATUS => {
|
||||||
|
return self.status | 0x30;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.reg_values[addr as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, addr: u32, value: u8) {
|
||||||
|
match addr {
|
||||||
|
OSC_CTRL => {
|
||||||
|
info!(self.log, "OSC_CTRL <= {:02X}", value);
|
||||||
|
self.ctrl = value & 0x1F;
|
||||||
|
self.status = value & 0x1F;
|
||||||
|
}
|
||||||
|
OSC_XOSCCTRL => {
|
||||||
|
self.xoscctrl = value & 0xEF;
|
||||||
|
}
|
||||||
|
OSC_XOSCFAIL => {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.reg_values[addr as usize] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
} else if(addr == 0x03) { // XOSCFAIL
|
||||||
|
XOSCFAIL vreg;
|
||||||
|
vreg.data = v & 0x03;
|
||||||
|
// XOSCFDEN
|
||||||
|
if(!xoscfail_.xoscfden && vreg.xoscfden) {
|
||||||
|
if(device_->ccpState() & Device::CCP_IOREG) {
|
||||||
|
xoscfail_.xoscfden = 1;
|
||||||
|
} else {
|
||||||
|
LOGF(ERROR, "cannot set XOSCFAIL.XOSCFDEN: protected by CCP");
|
||||||
|
}
|
||||||
|
} else if(xoscfail_.xoscfden && !vreg.xoscfden) {
|
||||||
|
LOGF(ERROR, "XOSCFAIL.XOSCFDEN cannot be cleared");
|
||||||
|
}
|
||||||
|
// XOSCFDIF
|
||||||
|
if(vreg.xoscfdif) {
|
||||||
|
xoscfail_.xoscfdif = 0;
|
||||||
|
}
|
||||||
|
} else if(addr == 0x04) { // RC32KCAL
|
||||||
|
rc32kcal_ = v;
|
||||||
|
} else if(addr == 0x05) { // PLLCTRL
|
||||||
|
if((v >> 6) == 1) {
|
||||||
|
LOGF(ERROR, "invalid PLLSRC value");
|
||||||
|
} else {
|
||||||
|
pllsrc_ = static_cast<PLLSRC>(v >> 6);
|
||||||
|
}
|
||||||
|
pllfac_ = v & 0x1F;
|
||||||
|
} else if(addr == 0x06) { // DFLLCTRL
|
||||||
|
//TODO no check nor handling is made here
|
||||||
|
dfllctrl_.data = v & 0x03;
|
||||||
|
} else {
|
||||||
|
LOGF(ERROR, "I/O write %s + 0x%02X: not writable") % name() % addr;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
27
src/devices/ram.rs
Normal file
27
src/devices/ram.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// RAM 'device'
|
||||||
|
use devices::DeviceImpl;
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
pub struct RAM {
|
||||||
|
log: Logger,
|
||||||
|
data: Box<[u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RAM {
|
||||||
|
pub fn new(log: Logger) -> Self {
|
||||||
|
Self {
|
||||||
|
log: log,
|
||||||
|
data: Box::new([0u8; 0x4000]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceImpl for RAM {
|
||||||
|
fn read(&mut self, addr: u32) -> u8 {
|
||||||
|
self.data[addr as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, addr: u32, value: u8) {
|
||||||
|
self.data[addr as usize] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/devices/usart.rs
Normal file
79
src/devices/usart.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use devices::DeviceImpl;
|
||||||
|
|
||||||
|
use std;
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
const USART_DATA: u32 = 0;
|
||||||
|
const USART_STATUS: u32 = 1;
|
||||||
|
const USART_CTRLA: u32 = 3;
|
||||||
|
const USART_CTRLB: u32 = 4;
|
||||||
|
const USART_CTRLC: u32 = 5;
|
||||||
|
const USART_BAUDCTRLA: u32 = 6;
|
||||||
|
const USART_BAUDCTRLB: u32 = 7;
|
||||||
|
|
||||||
|
pub struct USART {
|
||||||
|
/*
|
||||||
|
0x8A0: 'USARTC0_DATA',
|
||||||
|
0x8A1: 'USARTC0_STATUS',
|
||||||
|
0x8A3: 'USARTC0_CTRLA',
|
||||||
|
0x8A4: 'USARTC0_CTRLB',
|
||||||
|
0x8A5: 'USARTC0_CTRLC',
|
||||||
|
0x8A6: 'USARTC0_BAUDCTRLA',
|
||||||
|
0x8A7: 'USARTC0_BAUDCTRLB',
|
||||||
|
*/
|
||||||
|
log: Logger,
|
||||||
|
// Raw values:
|
||||||
|
status: u8,
|
||||||
|
ctrla: u8,
|
||||||
|
ctrlb: u8,
|
||||||
|
ctrlc: u8,
|
||||||
|
baudctrla: u8,
|
||||||
|
baudctrlb: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl USART {
|
||||||
|
pub fn new(log: Logger) -> Self {
|
||||||
|
Self {
|
||||||
|
log: log,
|
||||||
|
status: 0,
|
||||||
|
ctrla: 0,
|
||||||
|
ctrlb: 0,
|
||||||
|
ctrlc: 0,
|
||||||
|
baudctrla: 0,
|
||||||
|
baudctrlb: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceImpl for USART {
|
||||||
|
fn read(&mut self, addr: u32) -> u8 {
|
||||||
|
match addr {
|
||||||
|
USART_DATA => {
|
||||||
|
info!(self.log, "USART::Read(), not implemented");
|
||||||
|
0
|
||||||
|
},
|
||||||
|
USART_STATUS => self.status,
|
||||||
|
USART_CTRLA => self.ctrla,
|
||||||
|
USART_CTRLB => self.ctrlb,
|
||||||
|
USART_CTRLC => self.ctrlc,
|
||||||
|
USART_BAUDCTRLA => self.baudctrla,
|
||||||
|
USART_BAUDCTRLB => self.baudctrlb,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, addr: u32, value: u8) {
|
||||||
|
match addr {
|
||||||
|
USART_DATA => {
|
||||||
|
info!(self.log, "USART::Write({} / {:?})", value, std::char::from_u32(u32::from(value)));
|
||||||
|
},
|
||||||
|
USART_STATUS => self.status = value,
|
||||||
|
USART_CTRLA => self.ctrla = value,
|
||||||
|
USART_CTRLB => self.ctrlb = value,
|
||||||
|
USART_CTRLC => self.ctrlc = value,
|
||||||
|
USART_BAUDCTRLA => self.baudctrla = value,
|
||||||
|
USART_BAUDCTRLB => self.baudctrlb = value,
|
||||||
|
_ => panic!("Write to usart offset {} <- {:02X}", addr, value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -118,12 +118,12 @@ struct GDBStub<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GDBStub<'a> {
|
impl<'a> GDBStub<'a> {
|
||||||
fn stop_reply(&self) -> String {
|
fn stop_reply(&mut self) -> String {
|
||||||
// Send SIGTRAP along with SREG/SP/PC.
|
// Send SIGTRAP along with SREG/SP/PC.
|
||||||
format!(
|
format!(
|
||||||
"T0520:{:02X};21:{:04X};22:{:08X};",
|
"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(&mut self.chip.device_tree).swap_bytes(),
|
||||||
(2 * self.chip.cpu.pc).swap_bytes()
|
(2 * self.chip.cpu.pc).swap_bytes()
|
||||||
).to_string()
|
).to_string()
|
||||||
}
|
}
|
||||||
@ -217,15 +217,14 @@ impl<'a> GDBStub<'a> {
|
|||||||
"Xfer" => {
|
"Xfer" => {
|
||||||
response = format!(
|
response = format!(
|
||||||
"l<memory-map>\n\
|
"l<memory-map>\n\
|
||||||
<memory type='ram' start='0x800000' length='0x{:X}' />\n\
|
<memory type='ram' start='0x800000' length='0x{:X}' />\n\
|
||||||
<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.ram.len()*/ 0x4000,
|
||||||
self.chip.rom.len()
|
self.chip.rom.len()
|
||||||
).to_string()
|
).to_string().into();
|
||||||
.into();
|
},
|
||||||
}
|
|
||||||
"C" => response = "01".into(),
|
"C" => response = "01".into(),
|
||||||
query => {
|
query => {
|
||||||
warn!(self.log, "Unknown query: '{}'", query);
|
warn!(self.log, "Unknown query: '{}'", query);
|
||||||
@ -247,7 +246,7 @@ impl<'a> GDBStub<'a> {
|
|||||||
// SP
|
// SP
|
||||||
reg_vals.push(format!(
|
reg_vals.push(format!(
|
||||||
"{:04X}",
|
"{:04X}",
|
||||||
self.chip.cpu.get_sp(&self.chip.ram).swap_bytes()
|
self.chip.cpu.get_sp(&mut self.chip.device_tree).swap_bytes()
|
||||||
));
|
));
|
||||||
// PC
|
// PC
|
||||||
reg_vals.push(format!("{:08X}", (2 * self.chip.cpu.pc).swap_bytes()));
|
reg_vals.push(format!("{:08X}", (2 * self.chip.cpu.pc).swap_bytes()));
|
||||||
@ -292,14 +291,14 @@ impl<'a> GDBStub<'a> {
|
|||||||
if addr & 0x00f00000 > 0 {
|
if addr & 0x00f00000 > 0 {
|
||||||
// RAM:
|
// RAM:
|
||||||
let addr_i = addr & 0xFFFFF;
|
let addr_i = addr & 0xFFFFF;
|
||||||
if addr_i >= self.chip.ram.len() {
|
if addr_i >= 0x4000 {
|
||||||
// Partial read case.
|
// Partial read case.
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data.push(format!("{:02X}", self.chip.ram[addr_i]));
|
data.push(format!("{:02X}", self.chip.device_tree.read(addr_i as u32)));
|
||||||
} else {
|
} else {
|
||||||
// ROM
|
// ROM
|
||||||
if addr >= self.chip.rom.len() {
|
if addr >= self.chip.rom.len() {
|
||||||
@ -331,12 +330,11 @@ impl<'a> GDBStub<'a> {
|
|||||||
if addr & 0x00f00000 > 0 {
|
if addr & 0x00f00000 > 0 {
|
||||||
// RAM:
|
// RAM:
|
||||||
let addr_i = addr & 0xFFFFF;
|
let addr_i = addr & 0xFFFFF;
|
||||||
if addr_i >= self.chip.ram.len() {
|
if addr_i >= 0x4000 {
|
||||||
err = true;
|
err = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.chip.ram[addr_i] =
|
self.chip.device_tree.write(addr_i as u32, u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap_or(0));
|
||||||
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() {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use slog::Drain;
|
|||||||
mod cpu;
|
mod cpu;
|
||||||
mod regs;
|
mod regs;
|
||||||
mod decoder;
|
mod decoder;
|
||||||
|
mod devices;
|
||||||
mod chip;
|
mod chip;
|
||||||
mod chip_definitions;
|
mod chip_definitions;
|
||||||
mod gdbstub;
|
mod gdbstub;
|
||||||
@ -46,7 +47,8 @@ fn main() {
|
|||||||
while chip.step() {}
|
while chip.step() {}
|
||||||
}
|
}
|
||||||
warn!(log, "{}", &chip.cpu);
|
warn!(log, "{}", &chip.cpu);
|
||||||
write_file("ram.dmp", &chip.ram).unwrap();
|
// TODO: Figure out how to write an full ram dump easily.
|
||||||
|
// write_file("ram.dmp", &chip.ram).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
|
pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user