mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-24 23:32:46 +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 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" => {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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); },
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user