Added ROd instruction and fixed bug with MOVEM

This commit is contained in:
transistor 2021-10-05 16:22:21 -07:00
parent f5283730c2
commit f2a23a21cb
7 changed files with 314 additions and 50 deletions

View File

@ -30,7 +30,7 @@ pub struct M68kDebugger {
pub breakpoints: Vec<u32>,
pub use_tracing: bool,
pub use_debugger: bool,
pub step_until_return: bool,
pub step_until_return: Option<usize>,
pub stack_tracer: StackTracer,
}
@ -40,7 +40,7 @@ impl M68kDebugger {
breakpoints: vec!(),
use_tracing: false,
use_debugger: false,
step_until_return: false,
step_until_return: None,
stack_tracer: StackTracer::new(),
}
}
@ -69,15 +69,10 @@ impl MC68010 {
pub fn run_debugger(&mut self, space: &mut AddressSpace) {
self.dump_state(space);
if self.debugger.step_until_return {
match self.decoder.instruction {
Instruction::RTS | Instruction::RTE | Instruction::RTR => {
self.debugger.step_until_return = false;
}
_ => {
return;
},
}
match self.debugger.step_until_return {
Some(level) if level == self.debugger.stack_tracer.calls.len() => { self.debugger.step_until_return = None; },
Some(_) => { return; },
None => { },
}
loop {
@ -125,7 +120,7 @@ impl MC68010 {
}
},
"so" | "stepout" => {
self.debugger.step_until_return = true;
self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1);
return Ok(true);
},
"c" | "continue" => {

View File

@ -1,4 +1,6 @@
use std::fmt;
use crate::error::Error;
use crate::memory::{Address, AddressSpace};
@ -639,7 +641,7 @@ impl M68kDecoder {
(rtype, xreg, data, size)
}
fn get_mode_as_target(&mut self, space: &mut AddressSpace, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
pub fn get_mode_as_target(&mut self, space: &mut AddressSpace, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
let value = match mode {
0b000 => Target::DirectDReg(reg),
0b001 => Target::DirectAReg(reg),
@ -773,3 +775,21 @@ pub fn sign_extend_to_long(value: u32, from: Size) -> i32 {
}
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Target::Immediate(value) => write!(f, "#{:08x}", value),
Target::DirectDReg(reg) => write!(f, "%d{}", reg),
Target::DirectAReg(reg) => write!(f, "%a{}", reg),
Target::IndirectAReg(reg) => write!(f, "(%a{})", reg),
Target::IndirectARegInc(reg) => write!(f, "(%a{})+", reg),
Target::IndirectARegDec(reg) => write!(f, "-(%a{})", reg),
Target::IndirectARegOffset(reg, offset) => write!(f, "(%a{} + #{})", reg, offset),
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, _) => write!(f, "(%a{} + %{}{} + #{})", reg, if *rtype == RegisterType::Data { 'd' } else { 'a' }, xreg, offset),
Target::IndirectMemory(value) => write!(f, "(#{:08x})", value),
Target::IndirectPCOffset(offset) => write!(f, "(%pc + #{})", offset),
Target::IndirectPCXRegOffset(rtype, xreg, offset, _) => write!(f, "(%pc + %{}{} + #{})", if *rtype == RegisterType::Data { 'd' } else { 'a' }, xreg, offset),
}
}
}

View File

@ -142,9 +142,9 @@ impl MC68010 {
self.execute_current(space)?;
self.timer.cycle.end(timer);
if (self.timer.cycle.events % 500) == 0 {
println!("{}", self.timer);
}
//if (self.timer.cycle.events % 500) == 0 {
// println!("{}", self.timer);
//}
Ok(())
},
@ -191,8 +191,9 @@ impl MC68010 {
Instruction::AND(src, dest, size) => {
let value = self.get_target_value(space, src, size)?;
let existing = self.get_target_value(space, dest, size)?;
self.set_target_value(space, dest, existing & value, size)?;
self.set_logic_flags(value, size);
let result = get_value_sized(existing & value, size);
self.set_target_value(space, dest, result, size)?;
self.set_logic_flags(result, size);
},
Instruction::ANDtoCCR(value) => {
self.state.sr = self.state.sr | value as u16;
@ -300,8 +301,9 @@ impl MC68010 {
Instruction::EOR(src, dest, size) => {
let value = self.get_target_value(space, src, size)?;
let existing = self.get_target_value(space, dest, size)?;
self.set_target_value(space, dest, existing ^ value, size)?;
self.set_logic_flags(value, size);
let result = get_value_sized(existing ^ value, size);
self.set_target_value(space, dest, result, size)?;
self.set_logic_flags(result, size);
},
Instruction::EORtoCCR(value) => {
self.state.sr = self.state.sr ^ value as u16;
@ -402,18 +404,21 @@ impl MC68010 {
// TODO moving words requires a sign extension to 32 bits
if size != Size::Long { return Err(Error::new("Unsupported size in MOVEM instruction")); }
let mut addr = self.get_target_address(target)?;
if dir == Direction::ToTarget {
let mut mask = mask;
for i in (0..8).rev() {
if (mask & 0x01) != 0 {
let value = *self.get_a_reg_mut(i);
self.set_target_value(space, target, value, size)?;
addr -= size.in_bytes();
set_address_sized(space, addr as Address, value, size);
}
mask >>= 1;
}
for i in (0..8).rev() {
if (mask & 0x01) != 0 {
self.set_target_value(space, target, self.state.d_reg[i], size)?;
addr -= size.in_bytes();
set_address_sized(space, addr as Address, self.state.d_reg[i], size);
}
mask >>= 1;
}
@ -421,19 +426,28 @@ impl MC68010 {
let mut mask = mask;
for i in 0..8 {
if (mask & 0x01) != 0 {
self.state.d_reg[i] = self.get_target_value(space, target, size)?;
self.state.d_reg[i] = get_address_sized(space, addr as Address, size)?;
addr += size.in_bytes();
}
mask >>= 1;
}
for i in 0..8 {
if (mask & 0x01) != 0 {
let value = self.get_target_value(space, target, size)?;
let addr = self.get_a_reg_mut(i);
*addr = value;
*self.get_a_reg_mut(i) = get_address_sized(space, addr as Address, size)?;
addr += size.in_bytes();
}
mask >>= 1;
}
}
// If it was Post-Inc/Pre-Dec target, then update the value
match target {
Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => {
let a_reg_mut = self.get_a_reg_mut(reg);
*a_reg_mut = addr;
}
_ => { },
}
},
Instruction::MOVEQ(data, reg) => {
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
@ -473,8 +487,9 @@ impl MC68010 {
Instruction::OR(src, dest, size) => {
let value = self.get_target_value(space, src, size)?;
let existing = self.get_target_value(space, dest, size)?;
self.set_target_value(space, dest, existing | value, size)?;
self.set_logic_flags(value, size);
let result = get_value_sized(existing | value, size);
self.set_target_value(space, dest, result, size)?;
self.set_logic_flags(result, size);
},
Instruction::ORtoCCR(value) => {
self.state.sr = self.state.sr | value as u16;
@ -488,8 +503,18 @@ impl MC68010 {
},
//Instruction::RESET => {
//},
//Instruction::ROd(Target, Target, Size, ShiftDirection) => {
//},
Instruction::ROd(count, target, size, shift_dir) => {
let count = self.get_target_value(space, count, size)? % 64;
let mut pair = (self.get_target_value(space, target, size)?, false);
for _ in 0..count {
pair = rotate_operation(pair.0, size, shift_dir);
}
self.set_logic_flags(pair.0, size);
if pair.1 {
self.state.sr |= FLAGS_CARRY;
}
self.set_target_value(space, target, pair.0, size)?;
},
//Instruction::ROXd(Target, Target, Size, ShiftDirection) => {
//},
//Instruction::RTE => {
@ -563,7 +588,7 @@ impl MC68010 {
Ok(value)
}
fn get_target_value(&mut self, space: &mut AddressSpace, target: Target, size: Size) -> Result<u32, Error> {
pub fn get_target_value(&mut self, space: &mut AddressSpace, target: Target, size: Size) -> Result<u32, Error> {
match target {
Target::Immediate(value) => Ok(value),
Target::DirectDReg(reg) => Ok(get_value_sized(self.state.d_reg[reg as usize], size)),
@ -602,7 +627,7 @@ impl MC68010 {
}
}
fn set_target_value(&mut self, space: &mut AddressSpace, target: Target, value: u32, size: Size) -> Result<(), Error> {
pub fn set_target_value(&mut self, space: &mut AddressSpace, target: Target, value: u32, size: Size) -> Result<(), Error> {
match target {
Target::DirectDReg(reg) => {
set_value_sized(&mut self.state.d_reg[reg as usize], value, size);
@ -640,9 +665,9 @@ impl MC68010 {
Ok(())
}
fn get_target_address(&mut self, target: Target) -> Result<u32, Error> {
pub fn get_target_address(&mut self, target: Target) -> Result<u32, Error> {
let addr = match target {
Target::IndirectAReg(reg) => *self.get_a_reg_mut(reg),
Target::IndirectAReg(reg) | Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => *self.get_a_reg_mut(reg),
Target::IndirectARegOffset(reg, offset) => {
let addr = self.get_a_reg_mut(reg);
(*addr).wrapping_add(offset as u32)
@ -706,6 +731,10 @@ impl MC68010 {
}
}
fn set_flag(&mut self, flag: u16, value: bool) {
self.state.sr = (self.state.sr & !flag) | (if value { flag } else { 0 });
}
fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool, overflow: bool) {
let value = sign_extend_to_long(value, size);
@ -803,10 +832,11 @@ fn overflowing_sub_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool
fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) {
match dir {
ShiftDirection::Left => {
let bit = get_msb(value, size);
match size {
Size::Byte => (((value as u8) << 1) as u32, get_msb(value, size)),
Size::Word => (((value as u16) << 1) as u32, get_msb(value, size)),
Size::Long => ((value << 1) as u32, get_msb(value, size)),
Size::Byte => (((value as u8) << 1) as u32, bit),
Size::Word => (((value as u16) << 1) as u32, bit),
Size::Long => ((value << 1) as u32, bit),
}
},
ShiftDirection::Right => {
@ -816,6 +846,25 @@ fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool
}
}
fn rotate_operation(value: u32, size: Size, dir: ShiftDirection) -> (u32, bool) {
match dir {
ShiftDirection::Left => {
let bit = get_msb(value, size);
let mask = if bit { 0x01 } else { 0x00 };
match size {
Size::Byte => (mask | ((value as u8) << 1) as u32, bit),
Size::Word => (mask | ((value as u16) << 1) as u32, bit),
Size::Long => (mask | (value << 1) as u32, bit),
}
},
ShiftDirection::Right => {
let bit = if (value & 0x01) != 0 { true } else { false };
let mask = if bit { get_msb_mask(0xffffffff, size) } else { 0x0 };
((value >> 1) | mask, bit)
},
}
}
fn get_value_sized(value: u32, size: Size) -> u32 {
match size {

View File

@ -2,7 +2,7 @@
use crate::memory::{Address, AddressSpace, MemoryBlock};
use super::execute::MC68010;
use super::decode::{Instruction, Target, Size, Sign};
use super::decode::{Instruction, Target, Size, Sign, ShiftDirection};
const INIT_STACK: Address = 0x00002000;
const INIT_ADDR: Address = 0x00000010;
@ -27,8 +27,9 @@ fn init_test() -> (MC68010, AddressSpace) {
#[cfg(test)]
mod tests {
use crate::memory::Address;
use super::{init_test, INIT_ADDR};
use super::{Instruction, Target, Size, Sign};
use super::{Instruction, Target, Size, Sign, ShiftDirection};
#[test]
fn instruction_nop() {
@ -79,7 +80,7 @@ mod tests {
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte));
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.sr & 0x0F, 0x00B);
assert_eq!(cpu.state.sr & 0x0F, 0x009);
}
#[test]
@ -119,5 +120,164 @@ mod tests {
//cpu.execute_current(&mut space).unwrap();
//assert_eq!(cpu.state.sr & 0x0F, 0x00);
}
#[test]
fn instruction_asli() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0xE300).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
cpu.state.d_reg[0] = 0x01;
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.d_reg[0], 0x00000002);
assert_eq!(cpu.state.sr & 0x1F, 0x00);
}
#[test]
fn instruction_asri() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0xE200).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
cpu.state.d_reg[0] = 0x81;
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.d_reg[0], 0x000000C0);
assert_eq!(cpu.state.sr & 0x1F, 0x19);
}
#[test]
fn instruction_roli() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0xE318).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
cpu.state.d_reg[0] = 0x80;
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.d_reg[0], 0x00000001);
assert_eq!(cpu.state.sr & 0x1F, 0x01);
}
#[test]
fn instruction_rori() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0xE218).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
cpu.state.d_reg[0] = 0x01;
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.d_reg[0], 0x00000080);
assert_eq!(cpu.state.sr & 0x1F, 0x09);
}
#[test]
fn target_value_direct_d() {
let (mut cpu, mut space) = init_test();
let size = Size::Word;
let expected = 0x1234;
let target = cpu.decoder.get_mode_as_target(&mut space, 0b000, 0b001, Some(size)).unwrap();
assert_eq!(target, Target::DirectDReg(1));
cpu.state.d_reg[1] = expected;
let result = cpu.get_target_value(&mut space, target, size).unwrap();
assert_eq!(result, expected);
}
#[test]
fn target_value_direct_a() {
let (mut cpu, mut space) = init_test();
let size = Size::Word;
let expected = 0x1234;
let target = cpu.decoder.get_mode_as_target(&mut space, 0b001, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::DirectAReg(2));
cpu.state.a_reg[2] = expected;
let result = cpu.get_target_value(&mut space, target, size).unwrap();
assert_eq!(result, expected);
}
#[test]
fn target_value_indirect_a() {
let (mut cpu, mut space) = init_test();
let size = Size::Long;
let expected_addr = INIT_ADDR;
let expected = 0x12345678;
space.write_beu32(INIT_ADDR, expected).unwrap();
let target = cpu.decoder.get_mode_as_target(&mut space, 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(&mut space, target, size).unwrap();
assert_eq!(result, expected);
}
#[test]
fn target_value_indirect_a_inc() {
let (mut cpu, mut space) = init_test();
let size = Size::Long;
let expected_addr = INIT_ADDR;
let expected = 0x12345678;
space.write_beu32(INIT_ADDR, expected).unwrap();
let target = cpu.decoder.get_mode_as_target(&mut space, 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(&mut space, target, size).unwrap();
assert_eq!(result, expected);
assert_eq!(cpu.state.a_reg[2], (INIT_ADDR as u32) + 4);
}
#[test]
fn target_value_indirect_a_dec() {
let (mut cpu, mut space) = init_test();
let size = Size::Long;
let expected_addr = INIT_ADDR + 4;
let expected = 0x12345678;
space.write_beu32(INIT_ADDR, expected).unwrap();
let target = cpu.decoder.get_mode_as_target(&mut space, 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(&mut space, target, size).unwrap();
assert_eq!(result, expected);
assert_eq!(cpu.state.a_reg[2], INIT_ADDR as u32);
}
#[test]
fn target_value_immediate() {
let (mut cpu, mut space) = init_test();
let size = Size::Word;
let expected = 0x1234;
space.write_beu16(cpu.decoder.end as Address, expected as u16).unwrap();
let target = cpu.decoder.get_mode_as_target(&mut space, 0b111, 0b100, Some(size)).unwrap();
assert_eq!(target, Target::Immediate(expected));
let result = cpu.get_target_value(&mut space, target, size).unwrap();
assert_eq!(result, expected);
}
}

View File

@ -7,7 +7,7 @@ use crate::memory::{Address, Addressable};
const ATA_REG_DEV_CONTROL: Address = 0x1D;
const ATA_REG_DEV_ADDRESS: Address = 0x1F;
const ATA_REG_DATA: Address = 0x20;
const ATA_REG_DATA_WORD: Address = 0x20;
const ATA_REG_DATA_BYTE: Address = 0x21;
const ATA_REG_FEATURE: Address = 0x23;
const ATA_REG_ERROR: Address = 0x23;
@ -24,12 +24,17 @@ const ATA_CMD_WRITE_SECTORS: u8 = 0x30;
const ATA_CMD_IDENTIFY: u8 = 0xEC;
const ATA_CMD_SET_FEATURE: u8 = 0xEF;
const ATA_ST_BUSY: u8 = 0x80;
const ATA_ST_DATA_READY: u8 = 0x08;
const ATA_ST_ERROR: u8 = 0x01;
const ATA_SECTOR_SIZE: u32 = 512;
const DEV_NAME: &'static str = "ata";
pub struct AtaDevice {
pub read_addr: u32,
pub read_count: u32,
pub selected_sector: u32,
pub selected_count: u32,
pub contents: Vec<u8>,
}
@ -37,8 +42,8 @@ pub struct AtaDevice {
impl AtaDevice {
pub fn new() -> Self {
AtaDevice {
read_addr: 0,
read_count: 0,
selected_sector: 0,
selected_count: 0,
contents: vec![],
}
}
@ -63,8 +68,21 @@ impl Addressable for AtaDevice {
let mut data = vec![0; count];
match addr {
ATA_REG_COMMAND => {
//data[0] = self.input;
ATA_REG_DATA_WORD => {
self.selected_count -= 2;
let offset = ((self.selected_sector * ATA_SECTOR_SIZE) + (ATA_SECTOR_SIZE -1 - self.selected_count)) as usize;
data[0] = self.contents[offset];
data[1] = self.contents[offset + 1];
println!(">> {:x}{:x}", data[0], data[1]);
},
ATA_REG_DATA_BYTE => {
self.selected_count -= 1;
let offset = ((self.selected_sector * ATA_SECTOR_SIZE) + (ATA_SECTOR_SIZE - 1 - self.selected_count)) as usize;
data[0] = self.contents[offset];
println!(">> {:x}", data[0]);
},
ATA_REG_STATUS => {
data[0] = ATA_ST_DATA_READY;
},
_ => { println!("{}: reading from {:0x}", DEV_NAME, addr); },
}
@ -73,7 +91,28 @@ impl Addressable for AtaDevice {
}
fn write(&mut self, mut addr: Address, data: &[u8]) {
println!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
match addr {
ATA_REG_DRIVE_HEAD => { self.selected_sector |= ((data[0] & 0x1F) as u32) << 24; },
ATA_REG_CYL_HIGH => { self.selected_sector |= (data[0] as u32) << 16; },
ATA_REG_CYL_LOW => { self.selected_sector |= (data[0] as u32) << 8; },
ATA_REG_SECTOR_NUM => { self.selected_sector |= data[0] as u32; },
ATA_REG_SECTOR_COUNT => { self.selected_count = (data[0] as u32) * ATA_SECTOR_SIZE; },
ATA_REG_COMMAND => {
match data[0] {
ATA_CMD_READ_SECTORS => { println!("{}: reading sector {:x}", DEV_NAME, self.selected_sector); },
ATA_CMD_WRITE_SECTORS => { println!("{}: writing sector {:x}", DEV_NAME, self.selected_sector); },
ATA_CMD_IDENTIFY => { },
ATA_CMD_SET_FEATURE => { },
_ => { println!("{}: unrecognized command {:x}", DEV_NAME, data[0]); },
}
},
ATA_REG_FEATURE => {
// TODO implement features
},
ATA_REG_DATA => {
// TODO implement writing
},
_ => { println!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); },
}
}

View File

@ -24,7 +24,7 @@ fn main() {
space.insert(0x00100000, Box::new(ram));
let mut ata = AtaDevice::new();
ata.load("binaries/compactflash.img").unwrap();
ata.load("binaries/disk-with-partition-table.img").unwrap();
space.insert(0x00600000, Box::new(ata));
let mut serial = MC68681::new();
@ -32,11 +32,12 @@ fn main() {
space.insert(0x00700000, Box::new(serial));
let mut cpu = MC68010::new();
//cpu.enable_tracing();
cpu.enable_tracing();
//cpu.add_breakpoint(0x0c94);
//cpu.add_breakpoint(0x103234);
//cpu.add_breakpoint(0x106e6a);
cpu.add_breakpoint(0x224);
cpu.add_breakpoint(0x10407e);
while cpu.is_running() {
match cpu.step(&mut space) {