mirror of
https://github.com/transistorfet/moa.git
synced 2025-01-21 10:32:23 +00:00
Added a bunch of unit tests
This commit is contained in:
parent
39ecd1b0d9
commit
91825e1cb9
@ -4,6 +4,7 @@ use crate::system::System;
|
||||
use crate::memory::{Address, Addressable};
|
||||
|
||||
use super::state::M68k;
|
||||
use super::decode::M68kDecoder;
|
||||
|
||||
pub struct StackTracer {
|
||||
pub calls: Vec<u32>,
|
||||
@ -47,10 +48,12 @@ impl M68kDebugger {
|
||||
}
|
||||
|
||||
impl M68k {
|
||||
#[allow(dead_code)]
|
||||
pub fn enable_tracing(&mut self) {
|
||||
self.debugger.use_tracing = true;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add_breakpoint(&mut self, addr: Address) {
|
||||
self.debugger.breakpoints.push(addr as u32);
|
||||
}
|
||||
@ -119,6 +122,10 @@ impl M68k {
|
||||
println!(" {:08x}", system.get_bus().read_beu32(*addr as Address)?);
|
||||
}
|
||||
},
|
||||
"dis" | "disassemble" => {
|
||||
let mut decoder = M68kDecoder::new(self.cputype, 0, 0);
|
||||
decoder.dump_disassembly(system, self.state.pc, 0x1000);
|
||||
},
|
||||
"so" | "stepout" => {
|
||||
self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1);
|
||||
return Ok(true);
|
||||
|
@ -1,67 +1,242 @@
|
||||
|
||||
use crate::system::System;
|
||||
use crate::devices::{Steppable, wrap_addressable};
|
||||
use crate::memory::{Address, Addressable, MemoryBlock};
|
||||
|
||||
use super::decode::Instruction;
|
||||
use super::state::{M68k, M68kType};
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
|
||||
fn init_test() -> (M68k, System) {
|
||||
let mut system = System::new();
|
||||
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap();
|
||||
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
|
||||
|
||||
let mut cpu = M68k::new(M68kType::MC68010);
|
||||
cpu.step(&system).unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.msp, INIT_STACK as u32);
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
||||
(cpu, system)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::devices::Steppable;
|
||||
use crate::memory::{Address, Addressable};
|
||||
mod decode_tests {
|
||||
use crate::system::System;
|
||||
use crate::devices::{Steppable, AddressableDeviceBox, wrap_addressable};
|
||||
use crate::memory::{Address, Addressable, MemoryBlock};
|
||||
|
||||
use super::{init_test, INIT_ADDR};
|
||||
use super::super::decode::{Instruction, Target, Size, Sign, ShiftDirection};
|
||||
use crate::cpus::m68k::{M68k, M68kType};
|
||||
use crate::cpus::m68k::decode::{Instruction, Target, Size, Sign, RegisterType, ShiftDirection};
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
|
||||
fn init_decode_test() -> (M68k, System) {
|
||||
let mut system = System::new();
|
||||
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap();
|
||||
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
|
||||
|
||||
// Initialize the CPU and make sure it's in the expected state
|
||||
let mut cpu = M68k::new(M68kType::MC68010);
|
||||
cpu.init(&system).unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.msp, INIT_STACK as u32);
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
||||
(cpu, system)
|
||||
}
|
||||
|
||||
fn get_decode_memory(cpu: &mut M68k, system: &System) -> AddressableDeviceBox {
|
||||
let (memory, relative_addr) = system.get_bus().get_device_at(INIT_ADDR, 12).unwrap();
|
||||
cpu.decoder.init((INIT_ADDR - relative_addr) as u32, INIT_ADDR as u32);
|
||||
memory
|
||||
}
|
||||
|
||||
//
|
||||
// Addressing Mode Target Tests
|
||||
//
|
||||
|
||||
#[test]
|
||||
fn target_direct_d() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b000, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectDReg(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_direct_a() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b001, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectAReg(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let expected_addr = INIT_ADDR;
|
||||
let expected = 0x12345678;
|
||||
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b010, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectAReg(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_inc() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let expected_addr = INIT_ADDR;
|
||||
let expected = 0x12345678;
|
||||
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b011, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegInc(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_dec() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let expected_addr = INIT_ADDR + 4;
|
||||
let expected = 0x12345678;
|
||||
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b100, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegDec(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_offset() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, (offset as i16) as u16).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b101, 0b100, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegOffset(4, offset));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_extension_word() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, brief_extension).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, (offset as i16) as u16).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b110, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegXRegOffset(2, RegisterType::Data, 3, offset, size));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_immediate_word() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, expected as u16).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b000, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_immediate_long() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x12345678;
|
||||
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_pc_offset() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, (offset as i16) as u16).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectPCOffset(offset));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_pc_extension_word() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, brief_extension).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, (offset as i16) as u16).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b011, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectPCXRegOffset(RegisterType::Data, 3, offset, size));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_immediate() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, expected as u16).unwrap();
|
||||
|
||||
let memory = get_decode_memory(&mut cpu, &system);
|
||||
let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b100, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::Immediate(expected));
|
||||
}
|
||||
|
||||
//
|
||||
// Instruction Decode Tests
|
||||
//
|
||||
|
||||
#[test]
|
||||
fn instruction_nop() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x4e71).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
||||
cpu.execute_current(&system).unwrap();
|
||||
// TODO you need a way to easily check the entire state (you maybe need to make a special struct for the state)
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn instruction_ori() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x0008).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0x00FF).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte));
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.a_reg[0], 0x000000FF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_equal() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap();
|
||||
@ -69,13 +244,11 @@ mod tests {
|
||||
cpu.step(&system).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte));
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr & 0x0F, 0x04);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_greater() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap();
|
||||
@ -83,13 +256,11 @@ mod tests {
|
||||
cpu.step(&system).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte));
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr & 0x0F, 0x009);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_less() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap();
|
||||
@ -97,43 +268,206 @@ mod tests {
|
||||
cpu.step(&system).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_andi_sr() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x027C).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0xF8FF).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_muls() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xC1FC).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0x0276).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::MUL(Target::Immediate(0x276), Target::DirectDReg(0), Size::Word, Sign::Signed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_asli() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE300).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_asri() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE200).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_roli() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE318).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_rori() {
|
||||
let (mut cpu, system) = init_decode_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE218).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod execute_tests {
|
||||
use crate::system::System;
|
||||
use crate::devices::{Steppable, wrap_addressable};
|
||||
use crate::memory::{Address, Addressable, MemoryBlock};
|
||||
|
||||
use crate::cpus::m68k::{M68k, M68kType};
|
||||
use crate::cpus::m68k::decode::{Instruction, Target, Size, Sign, ShiftDirection};
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
|
||||
fn init_test() -> (M68k, System) {
|
||||
let mut system = System::new();
|
||||
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap();
|
||||
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
|
||||
|
||||
let mut cpu = M68k::new(M68kType::MC68010);
|
||||
cpu.step(&system).unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.msp, INIT_STACK as u32);
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
||||
(cpu, system)
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn instruction_nop() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.decoder.instruction = Instruction::NOP;
|
||||
|
||||
let previous = cpu.state.clone();
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state, previous);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn instruction_ori() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.decoder.instruction = Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.a_reg[0], 0x000000FF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_equal() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let value = 0x20;
|
||||
cpu.state.d_reg[0] = value;
|
||||
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(value), Target::DirectDReg(0), Size::Byte);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr & 0x0F, 0x04);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_greater() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.d_reg[0] = 0x20;
|
||||
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr & 0x0F, 0x09);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_less() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.d_reg[0] = 0x20;
|
||||
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_andi_sr() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0x027C).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0xF8FF).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF));
|
||||
//cpu.execute_current(&system).unwrap();
|
||||
//assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
||||
cpu.state.sr = 0x87AA;
|
||||
cpu.decoder.instruction = Instruction::ANDtoSR(0xF8FF);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr, 0x80AA);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_ori_sr() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.sr = 0x8755;
|
||||
cpu.decoder.instruction = Instruction::ORtoSR(0x00AA);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.sr, 0x87FF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_muls() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xC1FC).unwrap();
|
||||
system.get_bus().write_beu16(INIT_ADDR + 2, 0x0276).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::MUL(Target::Immediate(0x276), Target::DirectDReg(0), Size::Word, Sign::Signed));
|
||||
//cpu.execute_current(&system).unwrap();
|
||||
//assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
||||
let value = 0x0276;
|
||||
cpu.state.d_reg[0] = 0x0200;
|
||||
cpu.decoder.instruction = Instruction::MUL(Target::Immediate(value), Target::DirectDReg(0), Size::Word, Sign::Signed);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.d_reg[0], 0x4ec00);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_divu() {
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let value = 0x0245;
|
||||
cpu.state.d_reg[0] = 0x40000;
|
||||
cpu.decoder.instruction = Instruction::DIV(Target::Immediate(value), Target::DirectDReg(0), Size::Word, Sign::Unsigned);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.d_reg[0], 0x007101C3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_asli() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE300).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.d_reg[0] = 0x01;
|
||||
cpu.decoder.instruction = Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.d_reg[0], 0x00000002);
|
||||
assert_eq!(cpu.state.sr & 0x1F, 0x00);
|
||||
@ -141,13 +475,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn instruction_asri() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE200).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.d_reg[0] = 0x81;
|
||||
cpu.decoder.instruction = Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.d_reg[0], 0x000000C0);
|
||||
assert_eq!(cpu.state.sr & 0x1F, 0x19);
|
||||
@ -155,13 +487,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn instruction_roli() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE318).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.d_reg[0] = 0x80;
|
||||
cpu.decoder.instruction = Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.d_reg[0], 0x00000001);
|
||||
assert_eq!(cpu.state.sr & 0x1F, 0x01);
|
||||
@ -169,13 +499,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn instruction_rori() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
|
||||
system.get_bus().write_beu16(INIT_ADDR, 0xE218).unwrap();
|
||||
cpu.decode_next(&system).unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
cpu.state.d_reg[0] = 0x01;
|
||||
cpu.decoder.instruction = Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right);
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state.d_reg[0], 0x00000080);
|
||||
assert_eq!(cpu.state.sr & 0x1F, 0x09);
|
||||
@ -183,17 +511,13 @@ mod tests {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#[test]
|
||||
fn target_value_direct_d() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
let target = cpu.decoder.get_mode_as_target(&system, 0b000, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectDReg(1));
|
||||
let target = Target::DirectDReg(1);
|
||||
|
||||
cpu.state.d_reg[1] = expected;
|
||||
let result = cpu.get_target_value(&system, target, size).unwrap();
|
||||
@ -202,13 +526,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn target_value_direct_a() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
let target = cpu.decoder.get_mode_as_target(&system, 0b001, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectAReg(2));
|
||||
let target = Target::DirectAReg(2);
|
||||
|
||||
cpu.state.a_reg[2] = expected;
|
||||
let result = cpu.get_target_value(&system, target, size).unwrap();
|
||||
@ -217,15 +539,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn target_value_indirect_a() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let expected_addr = INIT_ADDR;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let target = Target::IndirectAReg(2);
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
let target = cpu.decoder.get_mode_as_target(&system, 0b010, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectAReg(2));
|
||||
|
||||
cpu.state.a_reg[2] = INIT_ADDR as u32;
|
||||
let result = cpu.get_target_value(&system, target, size).unwrap();
|
||||
@ -234,15 +554,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn target_value_indirect_a_inc() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let expected_addr = INIT_ADDR;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let target = Target::IndirectARegInc(2);
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
let target = cpu.decoder.get_mode_as_target(&system, 0b011, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegInc(2));
|
||||
|
||||
cpu.state.a_reg[2] = INIT_ADDR as u32;
|
||||
let result = cpu.get_target_value(&system, target, size).unwrap();
|
||||
@ -252,15 +570,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn target_value_indirect_a_dec() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let size = Size::Long;
|
||||
let expected_addr = INIT_ADDR + 4;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let target = Target::IndirectARegDec(2);
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
let target = cpu.decoder.get_mode_as_target(&system, 0b100, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegDec(2));
|
||||
|
||||
cpu.state.a_reg[2] = (INIT_ADDR as u32) + 4;
|
||||
let result = cpu.get_target_value(&system, target, size).unwrap();
|
||||
@ -271,17 +587,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn target_value_immediate() {
|
||||
let (mut cpu, mut system) = init_test();
|
||||
let (mut cpu, system) = init_test();
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
system.get_bus().write_beu16(cpu.decoder.end as Address, expected as u16).unwrap();
|
||||
let target = cpu.decoder.get_mode_as_target(&system, 0b111, 0b100, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::Immediate(expected));
|
||||
let target = Target::Immediate(expected);
|
||||
|
||||
let result = cpu.get_target_value(&system, target, size).unwrap();
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,27 +9,33 @@ use crate::memory::{Addressable};
|
||||
|
||||
pub type Clock = u64;
|
||||
|
||||
|
||||
/// A device that can change state over time. The `step()` method will be called
|
||||
/// by the containing `System` when the system clock advances. If an error occurs
|
||||
/// with any device, the `on_error()` method will be called to display any state
|
||||
/// information that might be helpful for debugging.
|
||||
pub trait Steppable {
|
||||
fn step(&mut self, system: &System) -> Result<Clock, Error>;
|
||||
fn on_error(&mut self, _system: &System) { }
|
||||
}
|
||||
|
||||
/// A device that can receive an interrupt. The `interrupt_state_change()` method
|
||||
/// will be called whenever an interrupt signal changes goes high or low.
|
||||
pub trait Interruptable {
|
||||
fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
|
||||
pub trait AddressableDevice: Addressable + Steppable { }
|
||||
pub trait InterruptableDevice: Interruptable + Steppable { }
|
||||
|
||||
impl<T: Addressable + Steppable> AddressableDevice for T { }
|
||||
impl<T: Interruptable + Steppable> InterruptableDevice for T { }
|
||||
|
||||
pub type AddressableDeviceBox = Rc<RefCell<Box<dyn AddressableDevice>>>;
|
||||
pub type InterruptableDeviceBox = Rc<RefCell<Box<dyn InterruptableDevice>>>;
|
||||
|
||||
pub type AddressableDeviceRefMut<'a> = RefMut<'a, Box<dyn AddressableDevice>>;
|
||||
|
||||
impl<T: Addressable + Steppable> AddressableDevice for T { }
|
||||
impl<T: Interruptable + Steppable> InterruptableDevice for T { }
|
||||
|
||||
pub fn wrap_addressable<T: AddressableDevice + 'static>(value: T) -> AddressableDeviceBox {
|
||||
Rc::new(RefCell::new(Box::new(value)))
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
pub enum ErrorType {
|
||||
Emulator,
|
||||
Processor,
|
||||
Internal,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
16
src/main.rs
16
src/main.rs
@ -58,21 +58,6 @@ fn main() {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO I need to add a way to decode and dump the assembly for a section of code, in debugger
|
||||
cpu.enable_tracing();
|
||||
cpu.state.pc = 0x0010781a;
|
||||
while cpu.is_running() {
|
||||
match cpu.decode_next(&system) {
|
||||
Ok(()) => { },
|
||||
Err(err) => {
|
||||
cpu.dump_state(&system);
|
||||
panic!("{:?}", err);
|
||||
},
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn launch_terminal_emulator(name: String) {
|
||||
@ -84,7 +69,6 @@ pub fn launch_terminal_emulator(name: String) {
|
||||
}
|
||||
|
||||
pub fn launch_slip_connection(name: String) {
|
||||
use nix::unistd::sleep;
|
||||
use std::process::Command;
|
||||
|
||||
Command::new("sudo").args(["slattach", "-s", "38400", "-p", "slip", &name]).spawn().unwrap();
|
||||
|
@ -8,6 +8,7 @@ use crate::devices::{Clock, Steppable, AddressableDeviceBox};
|
||||
|
||||
pub type Address = u64;
|
||||
|
||||
/// A device that can be addressed to read data from or write data to the device.
|
||||
pub trait Addressable {
|
||||
fn len(&self) -> usize;
|
||||
fn read(&mut self, addr: Address, count: usize) -> Result<Vec<u8>, Error>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user