mirror of
https://github.com/transistorfet/moa.git
synced 2025-02-17 18:30:33 +00:00
Added ROd instruction and fixed bug with MOVEM
This commit is contained in:
parent
f5283730c2
commit
f2a23a21cb
Binary file not shown.
@ -30,7 +30,7 @@ pub struct M68kDebugger {
|
|||||||
pub breakpoints: Vec<u32>,
|
pub breakpoints: Vec<u32>,
|
||||||
pub use_tracing: bool,
|
pub use_tracing: bool,
|
||||||
pub use_debugger: bool,
|
pub use_debugger: bool,
|
||||||
pub step_until_return: bool,
|
pub step_until_return: Option<usize>,
|
||||||
pub stack_tracer: StackTracer,
|
pub stack_tracer: StackTracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ impl M68kDebugger {
|
|||||||
breakpoints: vec!(),
|
breakpoints: vec!(),
|
||||||
use_tracing: false,
|
use_tracing: false,
|
||||||
use_debugger: false,
|
use_debugger: false,
|
||||||
step_until_return: false,
|
step_until_return: None,
|
||||||
stack_tracer: StackTracer::new(),
|
stack_tracer: StackTracer::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,15 +69,10 @@ impl MC68010 {
|
|||||||
pub fn run_debugger(&mut self, space: &mut AddressSpace) {
|
pub fn run_debugger(&mut self, space: &mut AddressSpace) {
|
||||||
self.dump_state(space);
|
self.dump_state(space);
|
||||||
|
|
||||||
if self.debugger.step_until_return {
|
match self.debugger.step_until_return {
|
||||||
match self.decoder.instruction {
|
Some(level) if level == self.debugger.stack_tracer.calls.len() => { self.debugger.step_until_return = None; },
|
||||||
Instruction::RTS | Instruction::RTE | Instruction::RTR => {
|
Some(_) => { return; },
|
||||||
self.debugger.step_until_return = false;
|
None => { },
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -125,7 +120,7 @@ impl MC68010 {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"so" | "stepout" => {
|
"so" | "stepout" => {
|
||||||
self.debugger.step_until_return = true;
|
self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
},
|
},
|
||||||
"c" | "continue" => {
|
"c" | "continue" => {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::memory::{Address, AddressSpace};
|
use crate::memory::{Address, AddressSpace};
|
||||||
|
|
||||||
@ -639,7 +641,7 @@ impl M68kDecoder {
|
|||||||
(rtype, xreg, data, size)
|
(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 {
|
let value = match mode {
|
||||||
0b000 => Target::DirectDReg(reg),
|
0b000 => Target::DirectDReg(reg),
|
||||||
0b001 => Target::DirectAReg(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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -142,9 +142,9 @@ impl MC68010 {
|
|||||||
self.execute_current(space)?;
|
self.execute_current(space)?;
|
||||||
self.timer.cycle.end(timer);
|
self.timer.cycle.end(timer);
|
||||||
|
|
||||||
if (self.timer.cycle.events % 500) == 0 {
|
//if (self.timer.cycle.events % 500) == 0 {
|
||||||
println!("{}", self.timer);
|
// println!("{}", self.timer);
|
||||||
}
|
//}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@ -191,8 +191,9 @@ impl MC68010 {
|
|||||||
Instruction::AND(src, dest, size) => {
|
Instruction::AND(src, dest, size) => {
|
||||||
let value = self.get_target_value(space, src, size)?;
|
let value = self.get_target_value(space, src, size)?;
|
||||||
let existing = self.get_target_value(space, dest, size)?;
|
let existing = self.get_target_value(space, dest, size)?;
|
||||||
self.set_target_value(space, dest, existing & value, size)?;
|
let result = get_value_sized(existing & value, size);
|
||||||
self.set_logic_flags(value, size);
|
self.set_target_value(space, dest, result, size)?;
|
||||||
|
self.set_logic_flags(result, size);
|
||||||
},
|
},
|
||||||
Instruction::ANDtoCCR(value) => {
|
Instruction::ANDtoCCR(value) => {
|
||||||
self.state.sr = self.state.sr | value as u16;
|
self.state.sr = self.state.sr | value as u16;
|
||||||
@ -300,8 +301,9 @@ impl MC68010 {
|
|||||||
Instruction::EOR(src, dest, size) => {
|
Instruction::EOR(src, dest, size) => {
|
||||||
let value = self.get_target_value(space, src, size)?;
|
let value = self.get_target_value(space, src, size)?;
|
||||||
let existing = self.get_target_value(space, dest, size)?;
|
let existing = self.get_target_value(space, dest, size)?;
|
||||||
self.set_target_value(space, dest, existing ^ value, size)?;
|
let result = get_value_sized(existing ^ value, size);
|
||||||
self.set_logic_flags(value, size);
|
self.set_target_value(space, dest, result, size)?;
|
||||||
|
self.set_logic_flags(result, size);
|
||||||
},
|
},
|
||||||
Instruction::EORtoCCR(value) => {
|
Instruction::EORtoCCR(value) => {
|
||||||
self.state.sr = self.state.sr ^ value as u16;
|
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
|
// TODO moving words requires a sign extension to 32 bits
|
||||||
if size != Size::Long { return Err(Error::new("Unsupported size in MOVEM instruction")); }
|
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 {
|
if dir == Direction::ToTarget {
|
||||||
let mut mask = mask;
|
let mut mask = mask;
|
||||||
for i in (0..8).rev() {
|
for i in (0..8).rev() {
|
||||||
if (mask & 0x01) != 0 {
|
if (mask & 0x01) != 0 {
|
||||||
let value = *self.get_a_reg_mut(i);
|
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;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
for i in (0..8).rev() {
|
for i in (0..8).rev() {
|
||||||
if (mask & 0x01) != 0 {
|
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;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
@ -421,19 +426,28 @@ impl MC68010 {
|
|||||||
let mut mask = mask;
|
let mut mask = mask;
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
if (mask & 0x01) != 0 {
|
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;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
if (mask & 0x01) != 0 {
|
if (mask & 0x01) != 0 {
|
||||||
let value = self.get_target_value(space, target, size)?;
|
*self.get_a_reg_mut(i) = get_address_sized(space, addr as Address, size)?;
|
||||||
let addr = self.get_a_reg_mut(i);
|
addr += size.in_bytes();
|
||||||
*addr = value;
|
|
||||||
}
|
}
|
||||||
mask >>= 1;
|
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) => {
|
Instruction::MOVEQ(data, reg) => {
|
||||||
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
|
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
|
||||||
@ -473,8 +487,9 @@ impl MC68010 {
|
|||||||
Instruction::OR(src, dest, size) => {
|
Instruction::OR(src, dest, size) => {
|
||||||
let value = self.get_target_value(space, src, size)?;
|
let value = self.get_target_value(space, src, size)?;
|
||||||
let existing = self.get_target_value(space, dest, size)?;
|
let existing = self.get_target_value(space, dest, size)?;
|
||||||
self.set_target_value(space, dest, existing | value, size)?;
|
let result = get_value_sized(existing | value, size);
|
||||||
self.set_logic_flags(value, size);
|
self.set_target_value(space, dest, result, size)?;
|
||||||
|
self.set_logic_flags(result, size);
|
||||||
},
|
},
|
||||||
Instruction::ORtoCCR(value) => {
|
Instruction::ORtoCCR(value) => {
|
||||||
self.state.sr = self.state.sr | value as u16;
|
self.state.sr = self.state.sr | value as u16;
|
||||||
@ -488,8 +503,18 @@ impl MC68010 {
|
|||||||
},
|
},
|
||||||
//Instruction::RESET => {
|
//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::ROXd(Target, Target, Size, ShiftDirection) => {
|
||||||
//},
|
//},
|
||||||
//Instruction::RTE => {
|
//Instruction::RTE => {
|
||||||
@ -563,7 +588,7 @@ impl MC68010 {
|
|||||||
Ok(value)
|
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 {
|
match target {
|
||||||
Target::Immediate(value) => Ok(value),
|
Target::Immediate(value) => Ok(value),
|
||||||
Target::DirectDReg(reg) => Ok(get_value_sized(self.state.d_reg[reg as usize], size)),
|
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 {
|
match target {
|
||||||
Target::DirectDReg(reg) => {
|
Target::DirectDReg(reg) => {
|
||||||
set_value_sized(&mut self.state.d_reg[reg as usize], value, size);
|
set_value_sized(&mut self.state.d_reg[reg as usize], value, size);
|
||||||
@ -640,9 +665,9 @@ impl MC68010 {
|
|||||||
Ok(())
|
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 {
|
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) => {
|
Target::IndirectARegOffset(reg, offset) => {
|
||||||
let addr = self.get_a_reg_mut(reg);
|
let addr = self.get_a_reg_mut(reg);
|
||||||
(*addr).wrapping_add(offset as u32)
|
(*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) {
|
fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool, overflow: bool) {
|
||||||
let value = sign_extend_to_long(value, size);
|
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) {
|
fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) {
|
||||||
match dir {
|
match dir {
|
||||||
ShiftDirection::Left => {
|
ShiftDirection::Left => {
|
||||||
|
let bit = get_msb(value, size);
|
||||||
match size {
|
match size {
|
||||||
Size::Byte => (((value as u8) << 1) as u32, get_msb(value, size)),
|
Size::Byte => (((value as u8) << 1) as u32, bit),
|
||||||
Size::Word => (((value as u16) << 1) as u32, get_msb(value, size)),
|
Size::Word => (((value as u16) << 1) as u32, bit),
|
||||||
Size::Long => ((value << 1) as u32, get_msb(value, size)),
|
Size::Long => ((value << 1) as u32, bit),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ShiftDirection::Right => {
|
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 {
|
fn get_value_sized(value: u32, size: Size) -> u32 {
|
||||||
match size {
|
match size {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use crate::memory::{Address, AddressSpace, MemoryBlock};
|
use crate::memory::{Address, AddressSpace, MemoryBlock};
|
||||||
|
|
||||||
use super::execute::MC68010;
|
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_STACK: Address = 0x00002000;
|
||||||
const INIT_ADDR: Address = 0x00000010;
|
const INIT_ADDR: Address = 0x00000010;
|
||||||
@ -27,8 +27,9 @@ fn init_test() -> (MC68010, AddressSpace) {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::memory::Address;
|
||||||
use super::{init_test, INIT_ADDR};
|
use super::{init_test, INIT_ADDR};
|
||||||
use super::{Instruction, Target, Size, Sign};
|
use super::{Instruction, Target, Size, Sign, ShiftDirection};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instruction_nop() {
|
fn instruction_nop() {
|
||||||
@ -79,7 +80,7 @@ mod tests {
|
|||||||
cpu.decode_next(&mut space).unwrap();
|
cpu.decode_next(&mut space).unwrap();
|
||||||
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte));
|
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte));
|
||||||
cpu.execute_current(&mut space).unwrap();
|
cpu.execute_current(&mut space).unwrap();
|
||||||
assert_eq!(cpu.state.sr & 0x0F, 0x00B);
|
assert_eq!(cpu.state.sr & 0x0F, 0x009);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -119,5 +120,164 @@ mod tests {
|
|||||||
//cpu.execute_current(&mut space).unwrap();
|
//cpu.execute_current(&mut space).unwrap();
|
||||||
//assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
//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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use crate::memory::{Address, Addressable};
|
|||||||
|
|
||||||
const ATA_REG_DEV_CONTROL: Address = 0x1D;
|
const ATA_REG_DEV_CONTROL: Address = 0x1D;
|
||||||
const ATA_REG_DEV_ADDRESS: Address = 0x1F;
|
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_DATA_BYTE: Address = 0x21;
|
||||||
const ATA_REG_FEATURE: Address = 0x23;
|
const ATA_REG_FEATURE: Address = 0x23;
|
||||||
const ATA_REG_ERROR: 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_IDENTIFY: u8 = 0xEC;
|
||||||
const ATA_CMD_SET_FEATURE: u8 = 0xEF;
|
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";
|
const DEV_NAME: &'static str = "ata";
|
||||||
|
|
||||||
pub struct AtaDevice {
|
pub struct AtaDevice {
|
||||||
pub read_addr: u32,
|
pub selected_sector: u32,
|
||||||
pub read_count: u32,
|
pub selected_count: u32,
|
||||||
pub contents: Vec<u8>,
|
pub contents: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +42,8 @@ pub struct AtaDevice {
|
|||||||
impl AtaDevice {
|
impl AtaDevice {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
AtaDevice {
|
AtaDevice {
|
||||||
read_addr: 0,
|
selected_sector: 0,
|
||||||
read_count: 0,
|
selected_count: 0,
|
||||||
contents: vec![],
|
contents: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,8 +68,21 @@ impl Addressable for AtaDevice {
|
|||||||
let mut data = vec![0; count];
|
let mut data = vec![0; count];
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
ATA_REG_COMMAND => {
|
ATA_REG_DATA_WORD => {
|
||||||
//data[0] = self.input;
|
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); },
|
_ => { println!("{}: reading from {:0x}", DEV_NAME, addr); },
|
||||||
}
|
}
|
||||||
@ -73,7 +91,28 @@ impl Addressable for AtaDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, mut addr: Address, data: &[u8]) {
|
fn write(&mut self, mut addr: Address, data: &[u8]) {
|
||||||
|
println!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
||||||
match addr {
|
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); },
|
_ => { println!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ fn main() {
|
|||||||
space.insert(0x00100000, Box::new(ram));
|
space.insert(0x00100000, Box::new(ram));
|
||||||
|
|
||||||
let mut ata = AtaDevice::new();
|
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));
|
space.insert(0x00600000, Box::new(ata));
|
||||||
|
|
||||||
let mut serial = MC68681::new();
|
let mut serial = MC68681::new();
|
||||||
@ -32,11 +32,12 @@ fn main() {
|
|||||||
space.insert(0x00700000, Box::new(serial));
|
space.insert(0x00700000, Box::new(serial));
|
||||||
|
|
||||||
let mut cpu = MC68010::new();
|
let mut cpu = MC68010::new();
|
||||||
//cpu.enable_tracing();
|
cpu.enable_tracing();
|
||||||
|
|
||||||
//cpu.add_breakpoint(0x0c94);
|
//cpu.add_breakpoint(0x0c94);
|
||||||
//cpu.add_breakpoint(0x103234);
|
//cpu.add_breakpoint(0x103234);
|
||||||
//cpu.add_breakpoint(0x106e6a);
|
cpu.add_breakpoint(0x224);
|
||||||
|
cpu.add_breakpoint(0x10407e);
|
||||||
|
|
||||||
while cpu.is_running() {
|
while cpu.is_running() {
|
||||||
match cpu.step(&mut space) {
|
match cpu.step(&mut space) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user