Merge branch 'master' of pterpstra.com:m68k-backplane-computer/emu

This commit is contained in:
pjht 2023-12-20 13:11:29 -06:00
commit f3cec9c9a3
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
10 changed files with 178 additions and 207 deletions

View File

@ -95,7 +95,7 @@ impl Backplane {
} }
let cards: Vec<_> = card_configs let cards: Vec<_> = card_configs
.into_iter() .into_iter()
.map(|cfg| cfg.into_card()) .map(card::Config::into_card)
.try_collect()?; .try_collect()?;
let mmu = cards let mmu = cards
@ -328,7 +328,7 @@ impl Backplane {
fn read_byte_io(&self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&self, address: u8) -> NullableResult<u8, BusError> {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match address { match address {
0x1 => NullableResult::Ok(self.io_at_top_16mb.load(Ordering::Relaxed) as u8), 0x1 => NullableResult::Ok(u8::from(self.io_at_top_16mb.load(Ordering::Relaxed))),
_ => NullableResult::Ok(0), _ => NullableResult::Ok(0),
} }
} }

View File

@ -3,8 +3,8 @@ use std::fmt::Display;
use bitvec::prelude::*; use bitvec::prelude::*;
use crate::instruction::{ use crate::instruction::{
BitInsType, Condition, EffectiveAddress, Instruction, MoveDirection, RegisterEffective, BitInsType, Condition, ControlRegister, EffectiveAddress, Instruction, MoveDirection,
Rotation, ShiftDirection, ShiftType, Size, ControlRegister, RegisterEffective, Rotation, ShiftDirection, ShiftType, Size,
}; };
use derive_try_from_primitive::TryFromPrimitive; use derive_try_from_primitive::TryFromPrimitive;
@ -461,7 +461,7 @@ impl<T> Disasm<'_, T> {
} else if ins_word[4..13].load_be::<u16>() == 0b1_1100_1010 { } else if ins_word[4..13].load_be::<u16>() == 0b1_1100_1010 {
let areg = ins_word[13..16].load_be::<u8>(); let areg = ins_word[13..16].load_be::<u8>();
let displacement = self.read_immediate(Size::Word)? as i16; let displacement = self.read_immediate(Size::Word)? as i16;
Ok(Instruction::Link {areg, displacement}) Ok(Instruction::Link { areg, displacement })
} else if ins_word[4..13].load_be::<u16>() == 0b1_1100_1011 { } else if ins_word[4..13].load_be::<u16>() == 0b1_1100_1011 {
let dst = ins_word[13..16].load_be::<u8>(); let dst = ins_word[13..16].load_be::<u8>();
Ok(Instruction::Unlk(dst)) Ok(Instruction::Unlk(dst))
@ -502,7 +502,8 @@ impl<T> Disasm<'_, T> {
} else { } else {
EffectiveAddress::DataReg(reg_num) EffectiveAddress::DataReg(reg_num)
}; };
let ctrl = ControlRegister::try_from(word2[4..16].load_be::<u16>()).map_err(|_| DisassemblyError::InvalidInstruction)?; let ctrl = ControlRegister::try_from(word2[4..16].load_be::<u16>())
.map_err(|_| DisassemblyError::InvalidInstruction)?;
Ok(Instruction::Movec(dir, ea, ctrl)) Ok(Instruction::Movec(dir, ea, ctrl))
} else if ins_word[4..10].load_be::<u8>() == 0b11_1010 { } else if ins_word[4..10].load_be::<u8>() == 0b11_1010 {
let dst_mode = let dst_mode =
@ -616,9 +617,9 @@ impl<T> Disasm<'_, T> {
Size::Long => unreachable!(), Size::Long => unreachable!(),
}; };
let new_pc = if displacement >= 0 { let new_pc = if displacement >= 0 {
pc.wrapping_add(displacement as u16 as u32) pc.wrapping_add(u32::from(displacement as u16))
} else { } else {
pc.wrapping_sub(-displacement as u16 as u32) pc.wrapping_sub(u32::from(-displacement as u16))
}; };
if condition == Condition::False { if condition == Condition::False {
Ok(Instruction::Bsr(size, displacement, new_pc)) Ok(Instruction::Bsr(size, displacement, new_pc))

View File

@ -265,23 +265,22 @@ impl Display for ShiftDirection {
} }
} }
#[derive(Debug, Clone, TryFromPrimitive)] #[derive(Debug, Clone, TryFromPrimitive)]
#[repr(u16)] #[repr(u16)]
pub enum ControlRegister { pub enum ControlRegister {
SFC = 0x0, Sfc = 0x0,
DFC = 0x1, Dfc = 0x1,
USP = 0x800, Usp = 0x800,
VBR = 0x801, Vbr = 0x801,
} }
impl Display for ControlRegister { impl Display for ControlRegister {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::SFC => f.write_str("SFC"), Self::Sfc => f.write_str("SFC"),
Self::DFC => f.write_str("DFC"), Self::Dfc => f.write_str("DFC"),
Self::USP => f.write_str("USP"), Self::Usp => f.write_str("USP"),
Self::VBR => f.write_str("VBR"), Self::Vbr => f.write_str("VBR"),
} }
} }
} }
@ -488,12 +487,10 @@ impl Display for Instruction {
Self::Rts => write!(f, "RTS"), Self::Rts => write!(f, "RTS"),
Self::Trapv => write!(f, "TRAPV"), Self::Trapv => write!(f, "TRAPV"),
Self::Rtr => write!(f, "RTR"), Self::Rtr => write!(f, "RTR"),
Self::Movec(dir, ea, ctrl) => { Self::Movec(dir, ea, ctrl) => match dir {
match dir { MoveDirection::MemToReg => write!(f, "MOVEC {ctrl}, {ea}"),
MoveDirection::MemToReg => write!(f, "MOVEC {ctrl}, {ea}"), MoveDirection::RegToMem => write!(f, "MOVEC {ea}, {ctrl}"),
MoveDirection::RegToMem => write!(f, "MOVEC {ea}, {ctrl}"), },
}
}
Self::Jsr(ea) => write!(f, "JSR {ea}"), Self::Jsr(ea) => write!(f, "JSR {ea}"),
Self::Jmp(ea) => write!(f, "JMP {ea}"), Self::Jmp(ea) => write!(f, "JMP {ea}"),
Self::Movem(dir, size, dst, regs) => { Self::Movem(dir, size, dst, regs) => {

View File

@ -8,8 +8,8 @@ use crate::{
backplane::Backplane, backplane::Backplane,
disas::{self, DisassemblyError}, disas::{self, DisassemblyError},
instruction::{ instruction::{
ArithType, BitInsType, EffectiveAddress, Instruction, MoveDirection, ShiftDirection, ArithType, BitInsType, ControlRegister, EffectiveAddress, Instruction, MoveDirection,
ShiftType, Size, ControlRegister, Rotation, Rotation, ShiftDirection, ShiftType, Size,
}, },
}; };
@ -87,37 +87,37 @@ enum MemCycleInfo {
impl MemCycleInfo { impl MemCycleInfo {
fn is_err(&self) -> bool { fn is_err(&self) -> bool {
match self { match self {
MemCycleInfo::ReadByte { result, .. } => result.is_err(), Self::ReadByte { result, .. } => result.is_err(),
MemCycleInfo::ReadWord { result, .. } => result.is_err(), Self::ReadWord { result, .. } => result.is_err(),
MemCycleInfo::WriteByte { result, .. } => result.is_err(), Self::WriteByte { result, .. } => result.is_err(),
MemCycleInfo::WriteWord { result, .. } => result.is_err(), Self::WriteWord { result, .. } => result.is_err(),
} }
} }
fn unwrap_err(&self) -> DetailedBusError { fn unwrap_err(&self) -> DetailedBusError {
match self { match self {
MemCycleInfo::ReadByte { result, .. } => result.unwrap_err(), Self::ReadByte { result, .. } => result.unwrap_err(),
MemCycleInfo::ReadWord { result, .. } => result.unwrap_err(), Self::ReadWord { result, .. } => result.unwrap_err(),
MemCycleInfo::WriteByte { result, .. } => result.unwrap_err(), Self::WriteByte { result, .. } => result.unwrap_err(),
MemCycleInfo::WriteWord { result, .. } => result.unwrap_err(), Self::WriteWord { result, .. } => result.unwrap_err(),
} }
} }
fn address(&self) -> u32 { fn address(&self) -> u32 {
*(match self { *(match self {
MemCycleInfo::ReadByte { address, .. } => address, Self::ReadByte { address, .. } => address,
MemCycleInfo::ReadWord { address, .. } => address, Self::ReadWord { address, .. } => address,
MemCycleInfo::WriteByte { address, .. } => address, Self::WriteByte { address, .. } => address,
MemCycleInfo::WriteWord { address, .. } => address, Self::WriteWord { address, .. } => address,
}) })
} }
fn try_get_write_data(&self) -> Option<u16> { fn try_get_write_data(&self) -> Option<u16> {
match self { match self {
MemCycleInfo::ReadByte { .. } => None, Self::ReadByte { .. } => None,
MemCycleInfo::ReadWord { .. } => None, Self::ReadWord { .. } => None,
MemCycleInfo::WriteByte { data, .. } => Some(*data as u16), Self::WriteByte { data, .. } => Some(u16::from(*data)),
MemCycleInfo::WriteWord { data, .. } => Some(*data), Self::WriteWord { data, .. } => Some(*data),
} }
} }
} }
@ -144,8 +144,14 @@ impl From<DetailedBusError> for InsExecError {
} }
} }
impl Display for InsExecError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BusError(err) => f.write_fmt(format_args!("{err}")),
Self::AbnormalTrap => f.write_str("Abnormal trap"),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct M68K { pub struct M68K {
@ -225,7 +231,7 @@ impl M68K {
self.read_word(4), self.read_word(4),
self.read_word(6), self.read_word(6),
) { ) {
self.ssp = ((ssp_high as u32) << 16) | (ssp_low as u32); self.ssp = (u32::from(ssp_high) << 16) | u32::from(ssp_low);
self.vbr = 0; self.vbr = 0;
self.pc = (u32::from(pc_high) << 16) | u32::from(pc_low); self.pc = (u32::from(pc_high) << 16) | u32::from(pc_low);
self.sr = 0x2700 | self.sr & 0xFF; self.sr = 0x2700 | self.sr & 0xFF;
@ -243,33 +249,34 @@ impl M68K {
pub fn disassemble( pub fn disassemble(
&mut self, &mut self,
loc: u32, loc: u32,
) -> Result<(Instruction, u32), DisassemblyError<DetailedBusError>> { ) -> Result<(Instruction, u32), DisassemblyError<InsExecError>> {
disas::disasm(loc, &mut |addr| { disas::disasm(loc, &mut |addr| {
self.read_word(addr).map_err(|err| DetailedBusError { self.read_word(addr).map_err(|err| match err {
cause: BusErrorCause::ReadingInstruction, InsExecError::AbnormalTrap => InsExecError::AbnormalTrap,
..err.try_into_bus_error().unwrap() InsExecError::BusError(err) => InsExecError::BusError(DetailedBusError {
cause: BusErrorCause::ReadingInstruction,
..err
}),
}) })
}) })
} }
pub fn step(&mut self) { pub fn step(&mut self) {
let bus_error = match self.step_ret_berr() { let bus_error = match self.step_ret_berr() {
Ok(_) => { Ok(()) => {
self.stored_mem_cycles.clear(); self.stored_mem_cycles.clear();
return; return;
}, }
Err(e) => { Err(e) => match e {
match e { InsExecError::BusError(e) => e,
InsExecError::BusError(e) => e, InsExecError::AbnormalTrap => {
InsExecError::AbnormalTrap => { self.stored_mem_cycles.clear();
self.stored_mem_cycles.clear(); return;
return;
},
} }
}, },
}; };
if self.handling_bus_error { if self.handling_bus_error {
println!("{} while handling bus error, halting", bus_error); println!("{bus_error} while handling bus error, halting");
self.stopped = true; self.stopped = true;
self.stored_mem_cycles.clear(); self.stored_mem_cycles.clear();
self.use_stored_mem_cycles = false; self.use_stored_mem_cycles = false;
@ -288,22 +295,23 @@ impl M68K {
}; };
let stored_mem_cycles_len = self.stored_mem_cycles.len(); let stored_mem_cycles_len = self.stored_mem_cycles.len();
let last_cycle = &self.stored_mem_cycles[stored_mem_cycles_len - 1]; let last_cycle = &self.stored_mem_cycles[stored_mem_cycles_len - 1];
if let Err(snd_bus_error) = self if let Err(snd_bus_error) = self.berr_trap(
.berr_trap( write,
write, ins,
ins, byte_access,
byte_access, bus_error.address,
bus_error.address, last_cycle.try_get_write_data().unwrap_or(0),
last_cycle.try_get_write_data().unwrap_or(0), ) {
) println!(
{ "{} while trapping to bus error handler for {}, halting",
println!("{} while trapping to bus error handler for {}, halting", snd_bus_error.try_into_bus_error().unwrap(), bus_error); snd_bus_error.try_into_bus_error().unwrap(),
bus_error
);
self.stopped = true; self.stopped = true;
self.stored_mem_cycles.clear(); self.stored_mem_cycles.clear();
self.use_stored_mem_cycles = false; self.use_stored_mem_cycles = false;
self.handling_bus_error = false; self.handling_bus_error = false;
self.store_mem_cycles = true; self.store_mem_cycles = true;
return;
} }
} }
@ -316,13 +324,16 @@ impl M68K {
} }
let (ins, new_pc) = match self.disassemble(self.pc) { let (ins, new_pc) = match self.disassemble(self.pc) {
Ok(ins) => ins, Ok(ins) => ins,
Err(DisassemblyError::InvalidInstruction) => panic!("Invalid instruction"), Err(DisassemblyError::InvalidInstruction) => {
Err(DisassemblyError::ReadError(e)) => return Err(e.into()), self.trap(4)?;
return self.step_ret_berr();
}
Err(DisassemblyError::ReadError(e)) => return Err(e),
}; };
self.pc = new_pc; self.pc = new_pc;
match ins { match ins {
Instruction::OriCcr(val) => { Instruction::OriCcr(val) => {
self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) | val as u16); self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) | u16::from(val));
} }
Instruction::OriSr(val) => self.sr |= val, Instruction::OriSr(val) => self.sr |= val,
Instruction::Ori(size, dst, val) => { Instruction::Ori(size, dst, val) => {
@ -340,7 +351,7 @@ impl M68K {
self.sr = (self.sr & 0xFFE0) | new_flags; self.sr = (self.sr & 0xFFE0) | new_flags;
} }
Instruction::AndiCcr(val) => { Instruction::AndiCcr(val) => {
self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) & val as u16); self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) & u16::from(val));
} }
Instruction::AndiSr(val) => self.sr &= val, Instruction::AndiSr(val) => self.sr &= val,
Instruction::Andi(size, dst, val) => { Instruction::Andi(size, dst, val) => {
@ -364,7 +375,7 @@ impl M68K {
self.add(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg)?; self.add(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg)?;
} }
Instruction::EoriCcr(val) => { Instruction::EoriCcr(val) => {
self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) ^ val as u16); self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) ^ u16::from(val));
} }
Instruction::EoriSr(val) => self.sr ^= val, Instruction::EoriSr(val) => self.sr ^= val,
Instruction::Eori(size, dst, val) => { Instruction::Eori(size, dst, val) => {
@ -423,7 +434,7 @@ impl M68K {
)? as u8; )? as u8;
self.write_effective( self.write_effective(
EffectiveAddress::DataReg(dreg), EffectiveAddress::DataReg(dreg),
((high as u32) << 8) | (low as u32), (u32::from(high) << 8) | u32::from(low),
Size::Word, Size::Word,
)?; )?;
} }
@ -446,10 +457,10 @@ impl M68K {
)? as u8; )? as u8;
self.write_effective( self.write_effective(
EffectiveAddress::DataReg(dreg), EffectiveAddress::DataReg(dreg),
((high as u32) << 24) (u32::from(high) << 24)
| ((mid_high as u32) << 16) | (u32::from(mid_high) << 16)
| ((mid_low as u32) << 8) | (u32::from(mid_low) << 8)
| (low as u32), | u32::from(low),
Size::Word, Size::Word,
)?; )?;
} }
@ -600,11 +611,7 @@ impl M68K {
} else { } else {
sp.wrapping_sub(-displacement as u32) sp.wrapping_sub(-displacement as u32)
}; };
self.write_effective( self.write_effective(EffectiveAddress::AddressReg(7), new_sp, Size::Long)?;
EffectiveAddress::AddressReg(7),
new_sp,
Size::Long,
)?;
} }
Instruction::Unlk(areg) => { Instruction::Unlk(areg) => {
let dst = EffectiveAddress::AddressReg(areg); let dst = EffectiveAddress::AddressReg(areg);
@ -657,14 +664,11 @@ impl M68K {
let ssw_rerrun = (special_status_word >> 15) > 1; let ssw_rerrun = (special_status_word >> 15) > 1;
let stored_mem_cycles_len = self.stored_mem_cycles.len(); let stored_mem_cycles_len = self.stored_mem_cycles.len();
let last_cycle = &mut self.stored_mem_cycles[stored_mem_cycles_len - 1]; let last_cycle = &mut self.stored_mem_cycles[stored_mem_cycles_len - 1];
if !ssw_rerrun { if ssw_rerrun {
if last_cycle.is_err() { assert!(
self.stored_mem_cycles.pop(); fault_address == last_cycle.address(),
} "Recorded fault address did not match cycle address"
} else { );
if fault_address != last_cycle.address() {
panic!("Recorded fault address did not match cycle address");
};
let (expected_write, expected_ins, expected_byte_access) = let (expected_write, expected_ins, expected_byte_access) =
match last_cycle.unwrap_err().cause { match last_cycle.unwrap_err().cause {
BusErrorCause::ReadingByte => (false, false, true), BusErrorCause::ReadingByte => (false, false, true),
@ -673,15 +677,9 @@ impl M68K {
BusErrorCause::WritingWord => (true, false, false), BusErrorCause::WritingWord => (true, false, false),
BusErrorCause::ReadingInstruction => (false, true, false), BusErrorCause::ReadingInstruction => (false, true, false),
}; };
if ssw_write != expected_write { assert!(ssw_write == expected_write, "Write flag in the SSW did not match kind of cycle when returning from handling bus error (got {ssw_write}, expected {expected_write})");
panic!("Write flag in the SSW did not match kind of cycle when returning from handling bus error (got {}, expected {})", ssw_write, expected_write); assert!(ssw_ins == expected_ins, "Instruction flag in the SSW did not match kind of cycle when returning from handling bus error (got {ssw_ins}, expected {expected_ins})");
}; assert!(ssw_byte_access == expected_byte_access, "Byte access flag in the SSW did not match kind of cycle when returning from handling bus error (got {ssw_byte_access}, expected {expected_byte_access})");
if ssw_ins != expected_ins {
panic!("Instruction flag in the SSW did not match kind of cycle when returning from handling bus error (got {}, expected {})", ssw_ins, expected_ins);
};
if ssw_byte_access != expected_byte_access {
panic!("Byte access flag in the SSW did not match kind of cycle when returning from handling bus error (got {}, expected {})", ssw_byte_access, expected_byte_access);
};
let input_buf = if ssw_ins { let input_buf = if ssw_ins {
instruction_input_buf instruction_input_buf
} else { } else {
@ -705,6 +703,8 @@ impl M68K {
*result = Ok(()); *result = Ok(());
} }
} }
} else if last_cycle.is_err() {
self.stored_mem_cycles.pop();
} }
} }
} }
@ -719,34 +719,28 @@ impl M68K {
self.sr = (self.sr & 0xFF00) | u16::from(self.pop(Size::Word)? as u8); self.sr = (self.sr & 0xFF00) | u16::from(self.pop(Size::Word)? as u8);
self.pc = self.pop(Size::Long)?; self.pc = self.pop(Size::Long)?;
} }
Instruction::Movec(dir, ea, ctrl) => { Instruction::Movec(dir, ea, ctrl) => match dir {
match dir { MoveDirection::MemToReg => match ctrl {
MoveDirection::MemToReg => { ControlRegister::Sfc => todo!(),
match ctrl { ControlRegister::Dfc => todo!(),
ControlRegister::SFC => todo!(), ControlRegister::Usp => {
ControlRegister::DFC => todo!(), self.write_effective(ea, self.usp, Size::Long)?;
ControlRegister::USP => { }
self.write_effective(ea, self.usp, Size::Long)?; ControlRegister::Vbr => {
}, self.write_effective(ea, self.vbr, Size::Long)?;
ControlRegister::VBR => { }
self.write_effective(ea, self.vbr, Size::Long)?; },
}, MoveDirection::RegToMem => match ctrl {
} ControlRegister::Sfc => todo!(),
}, ControlRegister::Dfc => todo!(),
MoveDirection::RegToMem => { ControlRegister::Usp => {
match ctrl { self.usp = self.read_effective(ea, Size::Long)?;
ControlRegister::SFC => todo!(), }
ControlRegister::DFC => todo!(), ControlRegister::Vbr => {
ControlRegister::USP => { self.vbr = self.read_effective(ea, Size::Long)? & !(0x3FF);
self.usp = self.read_effective(ea, Size::Long)?; }
}, },
ControlRegister::VBR => { },
self.vbr = self.read_effective(ea, Size::Long)? &!(0x3FF);
},
}
},
}
}
Instruction::Jsr(ea) => { Instruction::Jsr(ea) => {
self.push(self.pc, Size::Long)?; self.push(self.pc, Size::Long)?;
self.pc = self.effective_address(ea)?; self.pc = self.effective_address(ea)?;
@ -780,7 +774,7 @@ impl M68K {
} }
Instruction::Addq(size, val, dst) => self.add( Instruction::Addq(size, val, dst) => self.add(
dst, dst,
EffectiveAddress::Immediate(val as i32 as u32), EffectiveAddress::Immediate(i32::from(val) as u32),
size, size,
if matches!(dst, EffectiveAddress::AddressReg(_)) { if matches!(dst, EffectiveAddress::AddressReg(_)) {
ArithType::Addr ArithType::Addr
@ -790,7 +784,7 @@ impl M68K {
)?, )?,
Instruction::Subq(size, val, dst) => self.sub( Instruction::Subq(size, val, dst) => self.sub(
dst, dst,
EffectiveAddress::Immediate(val as i32 as u32), EffectiveAddress::Immediate(i32::from(val) as u32),
size, size,
if matches!(dst, EffectiveAddress::AddressReg(_)) { if matches!(dst, EffectiveAddress::AddressReg(_)) {
ArithType::Addr ArithType::Addr
@ -827,7 +821,7 @@ impl M68K {
} }
} }
Instruction::Moveq { dreg, imm } => { Instruction::Moveq { dreg, imm } => {
let imm = imm as i32 as u32; let imm = i32::from(imm) as u32;
let neg = (imm & 0x8000_0000) > 0; let neg = (imm & 0x8000_0000) > 0;
let zero = imm == 0; let zero = imm == 0;
let old_flags = self.sr & 0xFFE0; let old_flags = self.sr & 0xFFE0;
@ -1361,7 +1355,7 @@ impl M68K {
.wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)?); .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)?);
self.read_address(address, size) self.read_address(address, size)
} }
EffectiveAddress::AbsoluteShort(x) => self.read_address(x as u32, size), EffectiveAddress::AbsoluteShort(x) => self.read_address(u32::from(x), size),
EffectiveAddress::AbsoluteLong(x) => self.read_address(x, size), EffectiveAddress::AbsoluteLong(x) => self.read_address(x, size),
} }
} }
@ -1440,7 +1434,7 @@ impl M68K {
.wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)?); .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)?);
self.write_address(address, data, size)?; self.write_address(address, data, size)?;
} }
EffectiveAddress::AbsoluteShort(x) => self.write_address(x as u32, data, size)?, EffectiveAddress::AbsoluteShort(x) => self.write_address(u32::from(x), data, size)?,
EffectiveAddress::AbsoluteLong(x) => self.write_address(x, data, size)?, EffectiveAddress::AbsoluteLong(x) => self.write_address(x, data, size)?,
EffectiveAddress::PcDisplacement(..) EffectiveAddress::PcDisplacement(..)
| EffectiveAddress::PcIndex(..) | EffectiveAddress::PcIndex(..)
@ -1450,7 +1444,6 @@ impl M68K {
} }
fn read_address(&mut self, address: u32, size: Size) -> Result<u32, InsExecError> { fn read_address(&mut self, address: u32, size: Size) -> Result<u32, InsExecError> {
// println!("READ {:x}, {:?}", address, size);
let address = address & 0xFF_FFFF; let address = address & 0xFF_FFFF;
match size { match size {
Size::Byte => Ok(u32::from(self.read_byte(address)?)), Size::Byte => Ok(u32::from(self.read_byte(address)?)),
@ -1462,13 +1455,7 @@ impl M68K {
} }
} }
fn write_address( fn write_address(&mut self, address: u32, data: u32, size: Size) -> Result<(), InsExecError> {
&mut self,
address: u32,
data: u32,
size: Size,
) -> Result<(), InsExecError> {
// println!("WRITE {:x}, {:?}, data {:x}", address, size, data);
match size { match size {
Size::Byte => self.write_byte(address, data as u8)?, Size::Byte => self.write_byte(address, data as u8)?,
Size::Word => self.write_word(address, data as u16)?, Size::Word => self.write_word(address, data as u16)?,
@ -1489,11 +1476,8 @@ impl M68K {
result, result,
} = cycle } = cycle
{ {
if stored_address == address { assert!(stored_address == address, "Stored bus cycle has wrong address when reading byte (reading {address:#x}, stored {stored_address:#x})");
return Ok(result?); return Ok(result?);
} else {
panic!("Stored bus cycle has wrong address when reading byte (reading {:#x}, stored {:#x})", address, stored_address);
}
} }
if self.stored_mem_cycles.is_empty() { if self.stored_mem_cycles.is_empty() {
self.store_mem_cycles = true; self.store_mem_cycles = true;
@ -1504,10 +1488,8 @@ impl M68K {
cause: BusErrorCause::ReadingByte, cause: BusErrorCause::ReadingByte,
}); });
if self.store_mem_cycles { if self.store_mem_cycles {
self.stored_mem_cycles.push(MemCycleInfo::ReadByte { self.stored_mem_cycles
address, .push(MemCycleInfo::ReadByte { address, result });
result: result.clone(),
});
}; };
Ok(result?) Ok(result?)
} }
@ -1525,9 +1507,9 @@ impl M68K {
if stored_address == address && stored_data == data { if stored_address == address && stored_data == data {
return Ok(result?); return Ok(result?);
} else if stored_address != address { } else if stored_address != address {
panic!("Stored bus cycle has wrong address when writing byte (reading {:#x}, stored {:#x})", address, stored_address); panic!("Stored bus cycle has wrong address when writing byte (reading {address:#x}, stored {stored_address:#x})");
} else if stored_data != data { } else if stored_data != data {
panic!("Stored bus cycle has wrong data when writing byte (writing {:#x}, stored {:#x})", data, stored_data); panic!("Stored bus cycle has wrong data when writing byte (writing {data:#x}, stored {stored_data:#x})");
} }
} }
if self.stored_mem_cycles.is_empty() { if self.stored_mem_cycles.is_empty() {
@ -1545,7 +1527,7 @@ impl M68K {
self.stored_mem_cycles.push(MemCycleInfo::WriteByte { self.stored_mem_cycles.push(MemCycleInfo::WriteByte {
address, address,
data, data,
result: result.clone(), result,
}); });
}; };
Ok(result?) Ok(result?)
@ -1564,11 +1546,8 @@ impl M68K {
result, result,
} = cycle } = cycle
{ {
if stored_address == address { assert!(stored_address == address, "Stored bus cycle has wrong address when reading word (reading {address:#x}, stored {stored_address:#x})");
return Ok(result?); return Ok(result?);
} else {
panic!("Stored bus cycle has wrong address when reading word (reading {:#x}, stored {:#x})", address, stored_address);
}
} }
if self.stored_mem_cycles.is_empty() { if self.stored_mem_cycles.is_empty() {
self.store_mem_cycles = true; self.store_mem_cycles = true;
@ -1579,10 +1558,8 @@ impl M68K {
cause: BusErrorCause::ReadingWord, cause: BusErrorCause::ReadingWord,
}); });
if self.store_mem_cycles { if self.store_mem_cycles {
self.stored_mem_cycles.push(MemCycleInfo::ReadWord { self.stored_mem_cycles
address, .push(MemCycleInfo::ReadWord { address, result });
result: result.clone(),
});
}; };
Ok(result?) Ok(result?)
} }
@ -1604,9 +1581,9 @@ impl M68K {
if stored_address == address && stored_data == data { if stored_address == address && stored_data == data {
return Ok(result?); return Ok(result?);
} else if stored_address != address { } else if stored_address != address {
panic!("Stored bus cycle has wrong address when writing word (reading {:#x}, stored {:#x})", address, stored_address); panic!("Stored bus cycle has wrong address when writing word (reading {address:#x}, stored {stored_address:#x})");
} else if stored_data != data { } else if stored_data != data {
panic!("Stored bus cycle has wrong data when writing word (writing {:#x}, stored {:#x})", data, stored_data); panic!("Stored bus cycle has wrong data when writing word (writing {data:#x}, stored {stored_data:#x})");
} }
} }
if self.stored_mem_cycles.is_empty() { if self.stored_mem_cycles.is_empty() {
@ -1624,7 +1601,7 @@ impl M68K {
self.stored_mem_cycles.push(MemCycleInfo::WriteWord { self.stored_mem_cycles.push(MemCycleInfo::WriteWord {
address, address,
data, data,
result: result.clone(), result,
}); });
}; };
Ok(result?) Ok(result?)
@ -1663,7 +1640,7 @@ impl M68K {
} }
} }
EffectiveAddress::PcDisplacement(pc, d) => Ok(pc.wrapping_add(d.into())), EffectiveAddress::PcDisplacement(pc, d) => Ok(pc.wrapping_add(d.into())),
EffectiveAddress::AbsoluteShort(x) => Ok(x as u32), EffectiveAddress::AbsoluteShort(x) => Ok(u32::from(x)),
EffectiveAddress::AbsoluteLong(x) => Ok(x), EffectiveAddress::AbsoluteLong(x) => Ok(x),
EffectiveAddress::DataReg(_) EffectiveAddress::DataReg(_)
| EffectiveAddress::AddressReg(_) | EffectiveAddress::AddressReg(_)
@ -1735,17 +1712,17 @@ impl M68K {
// Unused // Unused
self.push(0, Size::Word)?; self.push(0, Size::Word)?;
// Data output buffer // Data output buffer
self.push(write_data as u32, Size::Word)?; self.push(u32::from(write_data), Size::Word)?;
// Unused // Unused
self.push(0, Size::Word)?; self.push(0, Size::Word)?;
// Fault address // Fault address
self.push(fault_addr, Size::Long)?; self.push(fault_addr, Size::Long)?;
// Special status word // Special status word
let special_status_word = ((write as u16) << 8) let special_status_word = (u16::from(write) << 8)
| ((byte_access as u16) << 9) | (u16::from(byte_access) << 9)
| (((fault_addr & 0x1) as u16) << 10) | (((fault_addr & 0x1) as u16) << 10)
| (!ins as u16) | u16::from(!ins)
| (ins as u16); | u16::from(ins);
self.push(u32::from(special_status_word), Size::Word)?; self.push(u32::from(special_status_word), Size::Word)?;
// Format & vector // Format & vector
self.push(0x8002, Size::Word)?; self.push(0x8002, Size::Word)?;

View File

@ -15,16 +15,13 @@ mod symbol;
mod symbol_table; mod symbol_table;
mod symbol_tables; mod symbol_tables;
mod term; mod term;
use crate::{ use crate::{backplane::Backplane, location::Location, m68k::M68K};
backplane::Backplane,
location::Location,
m68k::{DetailedBusError, M68K},
};
use anyhow::anyhow; use anyhow::anyhow;
use clap::Parser; use clap::Parser;
use disas::DisassemblyError; use disas::DisassemblyError;
use indexmap::IndexSet; use indexmap::IndexSet;
use itertools::Itertools; use itertools::Itertools;
use m68k::InsExecError;
use parse_int::parse; use parse_int::parse;
use reedline_repl_rs::{ use reedline_repl_rs::{
clap::{builder::BoolishValueParser, Arg, ArgAction, Command}, clap::{builder::BoolishValueParser, Arg, ArgAction, Command},
@ -286,22 +283,22 @@ fn main() -> Result<(), anyhow::Error> {
if args.get_flag("phys") { if args.get_flag("phys") {
for i in 0..count { for i in 0..count {
match size { match size {
peek::Size::Byte => data.push(bus.read_byte_phys(addr + i)? as u32), peek::Size::Byte => data.push(u32::from(bus.read_byte_phys(addr + i)?)),
peek::Size::Word => data.push(bus.read_word_phys(addr + (i * 2))? as u32), peek::Size::Word => data.push(u32::from(bus.read_word_phys(addr + (i * 2))?)),
peek::Size::LongWord => data.push( peek::Size::LongWord => data.push(
(bus.read_word_phys(addr + (i * 4))? as u32) << 16 u32::from(bus.read_word_phys(addr + (i * 4))?) << 16
| (bus.read_word_phys(addr + (i * 4) + 2)? as u32), | u32::from(bus.read_word_phys(addr + (i * 4) + 2)?),
), ),
} }
} }
} else { } else {
for i in 0..count { for i in 0..count {
match size { match size {
peek::Size::Byte => data.push(bus.read_byte(addr + i)? as u32), peek::Size::Byte => data.push(u32::from(bus.read_byte(addr + i)?)),
peek::Size::Word => data.push(bus.read_word(addr + (i * 2))? as u32), peek::Size::Word => data.push(u32::from(bus.read_word(addr + (i * 2))?)),
peek::Size::LongWord => data.push( peek::Size::LongWord => data.push(
(bus.read_word(addr + (i * 4))? as u32) << 16 u32::from(bus.read_word(addr + (i * 4))?) << 16
| (bus.read_word(addr + (i * 4) + 2)? as u32), | u32::from(bus.read_word(addr + (i * 4) + 2)?),
), ),
} }
} }
@ -527,7 +524,7 @@ fn disas_fmt(
cpu: &mut M68K, cpu: &mut M68K,
addr: u32, addr: u32,
symbol_tables: &SymbolTables, symbol_tables: &SymbolTables,
) -> (String, Result<u32, DisassemblyError<DetailedBusError>>) { ) -> (String, Result<u32, DisassemblyError<InsExecError>>) {
let addr_fmt = if let Some((table, symbol, offset)) = symbol_tables.address_to_symbol(addr) { let addr_fmt = if let Some((table, symbol, offset)) = symbol_tables.address_to_symbol(addr) {
format!("{table}:{symbol} + {offset} (0x{addr:x})") format!("{table}:{symbol} + {offset} (0x{addr:x})")
} else { } else {

View File

@ -49,7 +49,7 @@ impl Card for MmuCard {
let offset = address % 4; let offset = address % 4;
match offset { match offset {
(0..=2) => NullableResult::Ok(u32_get_be_byte(self.map_frames[map_no], offset)), (0..=2) => NullableResult::Ok(u32_get_be_byte(self.map_frames[map_no], offset)),
3 => NullableResult::Ok(self.map_frames_enabled[map_no] as u8), 3 => NullableResult::Ok(u8::from(self.map_frames_enabled[map_no])),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -86,18 +86,19 @@ impl Card for MmuCard {
match offset { match offset {
0 => (), 0 => (),
1 => { 1 => {
self.tlb_clear_entry = (self.tlb_clear_entry & 0xF) | ((data as u16) << 4); self.tlb_clear_entry =
(self.tlb_clear_entry & 0xF) | (u16::from(data) << 4);
} }
2 => { 2 => {
self.tlb_clear_entry = self.tlb_clear_entry =
(self.tlb_clear_entry & 0xFF0) | (((data as u16) & 0xF0) >> 4); (self.tlb_clear_entry & 0xFF0) | ((u16::from(data) & 0xF0) >> 4);
} }
3 => { 3 => {
if self.print_debug { if self.print_debug {
println!( println!(
"Clearing TLB entry {:#x} ( page start {:#x} )", "Clearing TLB entry {:#x} ( page start {:#x} )",
self.tlb_clear_entry, self.tlb_clear_entry,
(self.tlb_clear_entry as u32) << 12 u32::from(self.tlb_clear_entry) << 12
); );
} }
self.tlb[self.tlb_clear_entry as usize] = 0x0; self.tlb[self.tlb_clear_entry as usize] = 0x0;
@ -164,7 +165,7 @@ impl Mmu for MmuCard {
let print_debug = self.print_debug; let print_debug = self.print_debug;
if self.enabled { if self.enabled {
if print_debug { if print_debug {
println!("Translating {:#x}", address); println!("Translating {address:#x}");
} }
let page = address >> 12; let page = address >> 12;
let offset = address & 0xFFF; let offset = address & 0xFFF;
@ -192,7 +193,7 @@ impl Mmu for MmuCard {
let mapping_hi = backplane.read_word_phys(mapping_address)?; let mapping_hi = backplane.read_word_phys(mapping_address)?;
let mapping_lo = backplane.read_word_phys(mapping_address + 2)?; let mapping_lo = backplane.read_word_phys(mapping_address + 2)?;
let mapping = let mapping =
((mapping_hi as u32) << 16 | mapping_lo as u32) | TLB_MAPPING_FLAG_VALID; (u32::from(mapping_hi) << 16 | u32::from(mapping_lo)) | TLB_MAPPING_FLAG_VALID;
self.tlb[page as usize] = mapping; self.tlb[page as usize] = mapping;
mapping mapping
}; };

View File

@ -16,8 +16,8 @@ impl Format {
Self::Hex => format!("0x{:0>width$x}", num, width = size.byte_count() * 2), Self::Hex => format!("0x{:0>width$x}", num, width = size.byte_count() * 2),
Self::Decimal => { Self::Decimal => {
let num = match size { let num = match size {
Size::Byte => num as u8 as i8 as i32, Size::Byte => i32::from(num as u8 as i8),
Size::Word => num as u16 as i16 as i32, Size::Word => i32::from(num as u16 as i16),
Size::LongWord => num as i32, Size::LongWord => num as i32,
}; };
format!("{num}") format!("{num}")

View File

@ -77,7 +77,7 @@ impl Card for Rom {
match address { match address {
(0..=0xEF) => NullableResult::Ok(self.ram[address as usize]), (0..=0xEF) => NullableResult::Ok(self.ram[address as usize]),
(0xF0..=0xF1) => NullableResult::Ok(u16_get_be_byte(self.start, address - 0xF0)), (0xF0..=0xF1) => NullableResult::Ok(u16_get_be_byte(self.start, address - 0xF0)),
0xF3 => NullableResult::Ok(self.enabled as u8), 0xF3 => NullableResult::Ok(u8::from(self.enabled)),
(0xFE..=0xFF) => NullableResult::Ok(u16_get_be_byte(ID, address - 0xFE)), (0xFE..=0xFF) => NullableResult::Ok(u16_get_be_byte(ID, address - 0xFE)),
_ => NullableResult::Null, _ => NullableResult::Null,
} }
@ -144,7 +144,7 @@ impl Display for Rom {
if self.enabled { if self.enabled {
f.write_fmt(format_args!( f.write_fmt(format_args!(
", enabled at base address {:#x}", ", enabled at base address {:#x}",
(self.start as u32) << 16 u32::from(self.start) << 16
))?; ))?;
}; };
Ok(()) Ok(())

View File

@ -102,14 +102,13 @@ impl Card for Storage {
0x9 => match data { 0x9 => match data {
0x0 => { 0x0 => {
if let Some((file, _)) = &mut self.file { if let Some((file, _)) = &mut self.file {
file.seek(SeekFrom::Start(self.sector as u64 * SECTOR_SIZE)) file.seek(SeekFrom::Start(u64::from(self.sector) * SECTOR_SIZE))
.unwrap(); .unwrap();
let mut buf = Vec::new(); let mut buf = vec![0; self.count as usize * SECTOR_SIZE as usize];
buf.resize(self.count as usize * SECTOR_SIZE as usize, 0);
match file.read_exact(&mut buf) { match file.read_exact(&mut buf) {
Ok(_) => (), Ok(()) => (),
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (), Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (),
Err(e) => Err(e).unwrap(), Err(e) => panic!("{e:?}"),
} }
self.read_data.extend(buf); self.read_data.extend(buf);
self.status.set(Status::DATA_READY, true); self.status.set(Status::DATA_READY, true);
@ -117,14 +116,13 @@ impl Card for Storage {
} }
0x1 => { 0x1 => {
if let Some((file, _)) = &mut self.file { if let Some((file, _)) = &mut self.file {
file.seek(SeekFrom::Start(self.sector as u64 * SECTOR_SIZE)) file.seek(SeekFrom::Start(u64::from(self.sector) * SECTOR_SIZE))
.unwrap(); .unwrap();
let mut buf = Vec::new(); let mut buf = vec![0; self.count as usize * SECTOR_SIZE as usize];
buf.resize(self.count as usize * SECTOR_SIZE as usize, 0);
match file.read_exact(&mut buf) { match file.read_exact(&mut buf) {
Ok(_) => (), Ok(()) => (),
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (), Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (),
Err(e) => Err(e).unwrap(), Err(e) => panic!("{e:?}"),
} }
self.read_data.extend(buf); self.read_data.extend(buf);
self.status.set(Status::BUSY, true); self.status.set(Status::BUSY, true);

View File

@ -84,8 +84,8 @@ impl SymbolTable {
self.breakpoints = self self.breakpoints = self
.breakpoints .breakpoints
.iter() .iter()
.filter(|&sym| table.symbols.contains_key(sym))
.cloned() .cloned()
.filter(|sym| table.symbols.contains_key(sym))
.collect::<IndexSet<_>>(); .collect::<IndexSet<_>>();
self.symbols = table.symbols; self.symbols = table.symbols;
} }