Merge branch 'master' of pterpstra.com:m68k-backplane-computer/emu
This commit is contained in:
commit
f3cec9c9a3
@ -95,7 +95,7 @@ impl Backplane {
|
||||
}
|
||||
let cards: Vec<_> = card_configs
|
||||
.into_iter()
|
||||
.map(|cfg| cfg.into_card())
|
||||
.map(card::Config::into_card)
|
||||
.try_collect()?;
|
||||
|
||||
let mmu = cards
|
||||
@ -328,7 +328,7 @@ impl Backplane {
|
||||
fn read_byte_io(&self, address: u8) -> NullableResult<u8, BusError> {
|
||||
#[allow(clippy::single_match)]
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
11
src/disas.rs
11
src/disas.rs
@ -3,8 +3,8 @@ use std::fmt::Display;
|
||||
use bitvec::prelude::*;
|
||||
|
||||
use crate::instruction::{
|
||||
BitInsType, Condition, EffectiveAddress, Instruction, MoveDirection, RegisterEffective,
|
||||
Rotation, ShiftDirection, ShiftType, Size, ControlRegister,
|
||||
BitInsType, Condition, ControlRegister, EffectiveAddress, Instruction, MoveDirection,
|
||||
RegisterEffective, Rotation, ShiftDirection, ShiftType, Size,
|
||||
};
|
||||
|
||||
use derive_try_from_primitive::TryFromPrimitive;
|
||||
@ -502,7 +502,8 @@ impl<T> Disasm<'_, T> {
|
||||
} else {
|
||||
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))
|
||||
} else if ins_word[4..10].load_be::<u8>() == 0b11_1010 {
|
||||
let dst_mode =
|
||||
@ -616,9 +617,9 @@ impl<T> Disasm<'_, T> {
|
||||
Size::Long => unreachable!(),
|
||||
};
|
||||
let new_pc = if displacement >= 0 {
|
||||
pc.wrapping_add(displacement as u16 as u32)
|
||||
pc.wrapping_add(u32::from(displacement as u16))
|
||||
} else {
|
||||
pc.wrapping_sub(-displacement as u16 as u32)
|
||||
pc.wrapping_sub(u32::from(-displacement as u16))
|
||||
};
|
||||
if condition == Condition::False {
|
||||
Ok(Instruction::Bsr(size, displacement, new_pc))
|
||||
|
@ -265,23 +265,22 @@ impl Display for ShiftDirection {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, TryFromPrimitive)]
|
||||
#[repr(u16)]
|
||||
pub enum ControlRegister {
|
||||
SFC = 0x0,
|
||||
DFC = 0x1,
|
||||
USP = 0x800,
|
||||
VBR = 0x801,
|
||||
Sfc = 0x0,
|
||||
Dfc = 0x1,
|
||||
Usp = 0x800,
|
||||
Vbr = 0x801,
|
||||
}
|
||||
|
||||
impl Display for ControlRegister {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::SFC => f.write_str("SFC"),
|
||||
Self::DFC => f.write_str("DFC"),
|
||||
Self::USP => f.write_str("USP"),
|
||||
Self::VBR => f.write_str("VBR"),
|
||||
Self::Sfc => f.write_str("SFC"),
|
||||
Self::Dfc => f.write_str("DFC"),
|
||||
Self::Usp => f.write_str("USP"),
|
||||
Self::Vbr => f.write_str("VBR"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -488,12 +487,10 @@ impl Display for Instruction {
|
||||
Self::Rts => write!(f, "RTS"),
|
||||
Self::Trapv => write!(f, "TRAPV"),
|
||||
Self::Rtr => write!(f, "RTR"),
|
||||
Self::Movec(dir, ea, ctrl) => {
|
||||
match dir {
|
||||
Self::Movec(dir, ea, ctrl) => match dir {
|
||||
MoveDirection::MemToReg => write!(f, "MOVEC {ctrl}, {ea}"),
|
||||
MoveDirection::RegToMem => write!(f, "MOVEC {ea}, {ctrl}"),
|
||||
}
|
||||
}
|
||||
},
|
||||
Self::Jsr(ea) => write!(f, "JSR {ea}"),
|
||||
Self::Jmp(ea) => write!(f, "JMP {ea}"),
|
||||
Self::Movem(dir, size, dst, regs) => {
|
||||
|
235
src/m68k.rs
235
src/m68k.rs
@ -8,8 +8,8 @@ use crate::{
|
||||
backplane::Backplane,
|
||||
disas::{self, DisassemblyError},
|
||||
instruction::{
|
||||
ArithType, BitInsType, EffectiveAddress, Instruction, MoveDirection, ShiftDirection,
|
||||
ShiftType, Size, ControlRegister, Rotation,
|
||||
ArithType, BitInsType, ControlRegister, EffectiveAddress, Instruction, MoveDirection,
|
||||
Rotation, ShiftDirection, ShiftType, Size,
|
||||
},
|
||||
};
|
||||
|
||||
@ -87,37 +87,37 @@ enum MemCycleInfo {
|
||||
impl MemCycleInfo {
|
||||
fn is_err(&self) -> bool {
|
||||
match self {
|
||||
MemCycleInfo::ReadByte { result, .. } => result.is_err(),
|
||||
MemCycleInfo::ReadWord { result, .. } => result.is_err(),
|
||||
MemCycleInfo::WriteByte { result, .. } => result.is_err(),
|
||||
MemCycleInfo::WriteWord { result, .. } => result.is_err(),
|
||||
Self::ReadByte { result, .. } => result.is_err(),
|
||||
Self::ReadWord { result, .. } => result.is_err(),
|
||||
Self::WriteByte { result, .. } => result.is_err(),
|
||||
Self::WriteWord { result, .. } => result.is_err(),
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_err(&self) -> DetailedBusError {
|
||||
match self {
|
||||
MemCycleInfo::ReadByte { result, .. } => result.unwrap_err(),
|
||||
MemCycleInfo::ReadWord { result, .. } => result.unwrap_err(),
|
||||
MemCycleInfo::WriteByte { result, .. } => result.unwrap_err(),
|
||||
MemCycleInfo::WriteWord { result, .. } => result.unwrap_err(),
|
||||
Self::ReadByte { result, .. } => result.unwrap_err(),
|
||||
Self::ReadWord { result, .. } => result.unwrap_err(),
|
||||
Self::WriteByte { result, .. } => result.unwrap_err(),
|
||||
Self::WriteWord { result, .. } => result.unwrap_err(),
|
||||
}
|
||||
}
|
||||
|
||||
fn address(&self) -> u32 {
|
||||
*(match self {
|
||||
MemCycleInfo::ReadByte { address, .. } => address,
|
||||
MemCycleInfo::ReadWord { address, .. } => address,
|
||||
MemCycleInfo::WriteByte { address, .. } => address,
|
||||
MemCycleInfo::WriteWord { address, .. } => address,
|
||||
Self::ReadByte { address, .. } => address,
|
||||
Self::ReadWord { address, .. } => address,
|
||||
Self::WriteByte { address, .. } => address,
|
||||
Self::WriteWord { address, .. } => address,
|
||||
})
|
||||
}
|
||||
|
||||
fn try_get_write_data(&self) -> Option<u16> {
|
||||
match self {
|
||||
MemCycleInfo::ReadByte { .. } => None,
|
||||
MemCycleInfo::ReadWord { .. } => None,
|
||||
MemCycleInfo::WriteByte { data, .. } => Some(*data as u16),
|
||||
MemCycleInfo::WriteWord { data, .. } => Some(*data),
|
||||
Self::ReadByte { .. } => None,
|
||||
Self::ReadWord { .. } => None,
|
||||
Self::WriteByte { data, .. } => Some(u16::from(*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)]
|
||||
pub struct M68K {
|
||||
@ -225,7 +231,7 @@ impl M68K {
|
||||
self.read_word(4),
|
||||
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.pc = (u32::from(pc_high) << 16) | u32::from(pc_low);
|
||||
self.sr = 0x2700 | self.sr & 0xFF;
|
||||
@ -243,33 +249,34 @@ impl M68K {
|
||||
pub fn disassemble(
|
||||
&mut self,
|
||||
loc: u32,
|
||||
) -> Result<(Instruction, u32), DisassemblyError<DetailedBusError>> {
|
||||
) -> Result<(Instruction, u32), DisassemblyError<InsExecError>> {
|
||||
disas::disasm(loc, &mut |addr| {
|
||||
self.read_word(addr).map_err(|err| DetailedBusError {
|
||||
self.read_word(addr).map_err(|err| match err {
|
||||
InsExecError::AbnormalTrap => InsExecError::AbnormalTrap,
|
||||
InsExecError::BusError(err) => InsExecError::BusError(DetailedBusError {
|
||||
cause: BusErrorCause::ReadingInstruction,
|
||||
..err.try_into_bus_error().unwrap()
|
||||
..err
|
||||
}),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn step(&mut self) {
|
||||
let bus_error = match self.step_ret_berr() {
|
||||
Ok(_) => {
|
||||
Ok(()) => {
|
||||
self.stored_mem_cycles.clear();
|
||||
return;
|
||||
},
|
||||
Err(e) => {
|
||||
match e {
|
||||
}
|
||||
Err(e) => match e {
|
||||
InsExecError::BusError(e) => e,
|
||||
InsExecError::AbnormalTrap => {
|
||||
self.stored_mem_cycles.clear();
|
||||
return;
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
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.stored_mem_cycles.clear();
|
||||
self.use_stored_mem_cycles = false;
|
||||
@ -288,22 +295,23 @@ impl M68K {
|
||||
};
|
||||
let stored_mem_cycles_len = self.stored_mem_cycles.len();
|
||||
let last_cycle = &self.stored_mem_cycles[stored_mem_cycles_len - 1];
|
||||
if let Err(snd_bus_error) = self
|
||||
.berr_trap(
|
||||
if let Err(snd_bus_error) = self.berr_trap(
|
||||
write,
|
||||
ins,
|
||||
byte_access,
|
||||
bus_error.address,
|
||||
last_cycle.try_get_write_data().unwrap_or(0),
|
||||
)
|
||||
{
|
||||
println!("{} while trapping to bus error handler for {}, halting", snd_bus_error.try_into_bus_error().unwrap(), bus_error);
|
||||
) {
|
||||
println!(
|
||||
"{} while trapping to bus error handler for {}, halting",
|
||||
snd_bus_error.try_into_bus_error().unwrap(),
|
||||
bus_error
|
||||
);
|
||||
self.stopped = true;
|
||||
self.stored_mem_cycles.clear();
|
||||
self.use_stored_mem_cycles = false;
|
||||
self.handling_bus_error = false;
|
||||
self.store_mem_cycles = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,13 +324,16 @@ impl M68K {
|
||||
}
|
||||
let (ins, new_pc) = match self.disassemble(self.pc) {
|
||||
Ok(ins) => ins,
|
||||
Err(DisassemblyError::InvalidInstruction) => panic!("Invalid instruction"),
|
||||
Err(DisassemblyError::ReadError(e)) => return Err(e.into()),
|
||||
Err(DisassemblyError::InvalidInstruction) => {
|
||||
self.trap(4)?;
|
||||
return self.step_ret_berr();
|
||||
}
|
||||
Err(DisassemblyError::ReadError(e)) => return Err(e),
|
||||
};
|
||||
self.pc = new_pc;
|
||||
match ins {
|
||||
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::Ori(size, dst, val) => {
|
||||
@ -340,7 +351,7 @@ impl M68K {
|
||||
self.sr = (self.sr & 0xFFE0) | new_flags;
|
||||
}
|
||||
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::Andi(size, dst, val) => {
|
||||
@ -364,7 +375,7 @@ impl M68K {
|
||||
self.add(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg)?;
|
||||
}
|
||||
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::Eori(size, dst, val) => {
|
||||
@ -423,7 +434,7 @@ impl M68K {
|
||||
)? as u8;
|
||||
self.write_effective(
|
||||
EffectiveAddress::DataReg(dreg),
|
||||
((high as u32) << 8) | (low as u32),
|
||||
(u32::from(high) << 8) | u32::from(low),
|
||||
Size::Word,
|
||||
)?;
|
||||
}
|
||||
@ -446,10 +457,10 @@ impl M68K {
|
||||
)? as u8;
|
||||
self.write_effective(
|
||||
EffectiveAddress::DataReg(dreg),
|
||||
((high as u32) << 24)
|
||||
| ((mid_high as u32) << 16)
|
||||
| ((mid_low as u32) << 8)
|
||||
| (low as u32),
|
||||
(u32::from(high) << 24)
|
||||
| (u32::from(mid_high) << 16)
|
||||
| (u32::from(mid_low) << 8)
|
||||
| u32::from(low),
|
||||
Size::Word,
|
||||
)?;
|
||||
}
|
||||
@ -600,11 +611,7 @@ impl M68K {
|
||||
} else {
|
||||
sp.wrapping_sub(-displacement as u32)
|
||||
};
|
||||
self.write_effective(
|
||||
EffectiveAddress::AddressReg(7),
|
||||
new_sp,
|
||||
Size::Long,
|
||||
)?;
|
||||
self.write_effective(EffectiveAddress::AddressReg(7), new_sp, Size::Long)?;
|
||||
}
|
||||
Instruction::Unlk(areg) => {
|
||||
let dst = EffectiveAddress::AddressReg(areg);
|
||||
@ -657,14 +664,11 @@ impl M68K {
|
||||
let ssw_rerrun = (special_status_word >> 15) > 1;
|
||||
let stored_mem_cycles_len = self.stored_mem_cycles.len();
|
||||
let last_cycle = &mut self.stored_mem_cycles[stored_mem_cycles_len - 1];
|
||||
if !ssw_rerrun {
|
||||
if last_cycle.is_err() {
|
||||
self.stored_mem_cycles.pop();
|
||||
}
|
||||
} else {
|
||||
if fault_address != last_cycle.address() {
|
||||
panic!("Recorded fault address did not match cycle address");
|
||||
};
|
||||
if ssw_rerrun {
|
||||
assert!(
|
||||
fault_address == last_cycle.address(),
|
||||
"Recorded fault address did not match cycle address"
|
||||
);
|
||||
let (expected_write, expected_ins, expected_byte_access) =
|
||||
match last_cycle.unwrap_err().cause {
|
||||
BusErrorCause::ReadingByte => (false, false, true),
|
||||
@ -673,15 +677,9 @@ impl M68K {
|
||||
BusErrorCause::WritingWord => (true, false, false),
|
||||
BusErrorCause::ReadingInstruction => (false, true, false),
|
||||
};
|
||||
if ssw_write != 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);
|
||||
};
|
||||
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);
|
||||
};
|
||||
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})");
|
||||
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})");
|
||||
let input_buf = if ssw_ins {
|
||||
instruction_input_buf
|
||||
} else {
|
||||
@ -705,6 +703,8 @@ impl M68K {
|
||||
*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.pc = self.pop(Size::Long)?;
|
||||
}
|
||||
Instruction::Movec(dir, ea, ctrl) => {
|
||||
match dir {
|
||||
MoveDirection::MemToReg => {
|
||||
match ctrl {
|
||||
ControlRegister::SFC => todo!(),
|
||||
ControlRegister::DFC => todo!(),
|
||||
ControlRegister::USP => {
|
||||
Instruction::Movec(dir, ea, ctrl) => match dir {
|
||||
MoveDirection::MemToReg => match ctrl {
|
||||
ControlRegister::Sfc => todo!(),
|
||||
ControlRegister::Dfc => todo!(),
|
||||
ControlRegister::Usp => {
|
||||
self.write_effective(ea, self.usp, Size::Long)?;
|
||||
},
|
||||
ControlRegister::VBR => {
|
||||
}
|
||||
ControlRegister::Vbr => {
|
||||
self.write_effective(ea, self.vbr, Size::Long)?;
|
||||
},
|
||||
}
|
||||
},
|
||||
MoveDirection::RegToMem => {
|
||||
match ctrl {
|
||||
ControlRegister::SFC => todo!(),
|
||||
ControlRegister::DFC => todo!(),
|
||||
ControlRegister::USP => {
|
||||
MoveDirection::RegToMem => match ctrl {
|
||||
ControlRegister::Sfc => todo!(),
|
||||
ControlRegister::Dfc => todo!(),
|
||||
ControlRegister::Usp => {
|
||||
self.usp = self.read_effective(ea, Size::Long)?;
|
||||
},
|
||||
ControlRegister::VBR => {
|
||||
}
|
||||
ControlRegister::Vbr => {
|
||||
self.vbr = self.read_effective(ea, Size::Long)? & !(0x3FF);
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Instruction::Jsr(ea) => {
|
||||
self.push(self.pc, Size::Long)?;
|
||||
self.pc = self.effective_address(ea)?;
|
||||
@ -780,7 +774,7 @@ impl M68K {
|
||||
}
|
||||
Instruction::Addq(size, val, dst) => self.add(
|
||||
dst,
|
||||
EffectiveAddress::Immediate(val as i32 as u32),
|
||||
EffectiveAddress::Immediate(i32::from(val) as u32),
|
||||
size,
|
||||
if matches!(dst, EffectiveAddress::AddressReg(_)) {
|
||||
ArithType::Addr
|
||||
@ -790,7 +784,7 @@ impl M68K {
|
||||
)?,
|
||||
Instruction::Subq(size, val, dst) => self.sub(
|
||||
dst,
|
||||
EffectiveAddress::Immediate(val as i32 as u32),
|
||||
EffectiveAddress::Immediate(i32::from(val) as u32),
|
||||
size,
|
||||
if matches!(dst, EffectiveAddress::AddressReg(_)) {
|
||||
ArithType::Addr
|
||||
@ -827,7 +821,7 @@ impl M68K {
|
||||
}
|
||||
}
|
||||
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 zero = imm == 0;
|
||||
let old_flags = self.sr & 0xFFE0;
|
||||
@ -1361,7 +1355,7 @@ impl M68K {
|
||||
.wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_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),
|
||||
}
|
||||
}
|
||||
@ -1440,7 +1434,7 @@ impl M68K {
|
||||
.wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_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::PcDisplacement(..)
|
||||
| EffectiveAddress::PcIndex(..)
|
||||
@ -1450,7 +1444,6 @@ impl M68K {
|
||||
}
|
||||
|
||||
fn read_address(&mut self, address: u32, size: Size) -> Result<u32, InsExecError> {
|
||||
// println!("READ {:x}, {:?}", address, size);
|
||||
let address = address & 0xFF_FFFF;
|
||||
match size {
|
||||
Size::Byte => Ok(u32::from(self.read_byte(address)?)),
|
||||
@ -1462,13 +1455,7 @@ impl M68K {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_address(
|
||||
&mut self,
|
||||
address: u32,
|
||||
data: u32,
|
||||
size: Size,
|
||||
) -> Result<(), InsExecError> {
|
||||
// println!("WRITE {:x}, {:?}, data {:x}", address, size, data);
|
||||
fn write_address(&mut self, address: u32, data: u32, size: Size) -> Result<(), InsExecError> {
|
||||
match size {
|
||||
Size::Byte => self.write_byte(address, data as u8)?,
|
||||
Size::Word => self.write_word(address, data as u16)?,
|
||||
@ -1489,11 +1476,8 @@ impl M68K {
|
||||
result,
|
||||
} = 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?);
|
||||
} 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() {
|
||||
self.store_mem_cycles = true;
|
||||
@ -1504,10 +1488,8 @@ impl M68K {
|
||||
cause: BusErrorCause::ReadingByte,
|
||||
});
|
||||
if self.store_mem_cycles {
|
||||
self.stored_mem_cycles.push(MemCycleInfo::ReadByte {
|
||||
address,
|
||||
result: result.clone(),
|
||||
});
|
||||
self.stored_mem_cycles
|
||||
.push(MemCycleInfo::ReadByte { address, result });
|
||||
};
|
||||
Ok(result?)
|
||||
}
|
||||
@ -1525,9 +1507,9 @@ impl M68K {
|
||||
if stored_address == address && stored_data == data {
|
||||
return Ok(result?);
|
||||
} 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 {
|
||||
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() {
|
||||
@ -1545,7 +1527,7 @@ impl M68K {
|
||||
self.stored_mem_cycles.push(MemCycleInfo::WriteByte {
|
||||
address,
|
||||
data,
|
||||
result: result.clone(),
|
||||
result,
|
||||
});
|
||||
};
|
||||
Ok(result?)
|
||||
@ -1564,11 +1546,8 @@ impl M68K {
|
||||
result,
|
||||
} = 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?);
|
||||
} 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() {
|
||||
self.store_mem_cycles = true;
|
||||
@ -1579,10 +1558,8 @@ impl M68K {
|
||||
cause: BusErrorCause::ReadingWord,
|
||||
});
|
||||
if self.store_mem_cycles {
|
||||
self.stored_mem_cycles.push(MemCycleInfo::ReadWord {
|
||||
address,
|
||||
result: result.clone(),
|
||||
});
|
||||
self.stored_mem_cycles
|
||||
.push(MemCycleInfo::ReadWord { address, result });
|
||||
};
|
||||
Ok(result?)
|
||||
}
|
||||
@ -1604,9 +1581,9 @@ impl M68K {
|
||||
if stored_address == address && stored_data == data {
|
||||
return Ok(result?);
|
||||
} 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 {
|
||||
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() {
|
||||
@ -1624,7 +1601,7 @@ impl M68K {
|
||||
self.stored_mem_cycles.push(MemCycleInfo::WriteWord {
|
||||
address,
|
||||
data,
|
||||
result: result.clone(),
|
||||
result,
|
||||
});
|
||||
};
|
||||
Ok(result?)
|
||||
@ -1663,7 +1640,7 @@ impl M68K {
|
||||
}
|
||||
}
|
||||
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::DataReg(_)
|
||||
| EffectiveAddress::AddressReg(_)
|
||||
@ -1735,17 +1712,17 @@ impl M68K {
|
||||
// Unused
|
||||
self.push(0, Size::Word)?;
|
||||
// Data output buffer
|
||||
self.push(write_data as u32, Size::Word)?;
|
||||
self.push(u32::from(write_data), Size::Word)?;
|
||||
// Unused
|
||||
self.push(0, Size::Word)?;
|
||||
// Fault address
|
||||
self.push(fault_addr, Size::Long)?;
|
||||
// Special status word
|
||||
let special_status_word = ((write as u16) << 8)
|
||||
| ((byte_access as u16) << 9)
|
||||
let special_status_word = (u16::from(write) << 8)
|
||||
| (u16::from(byte_access) << 9)
|
||||
| (((fault_addr & 0x1) as u16) << 10)
|
||||
| (!ins as u16)
|
||||
| (ins as u16);
|
||||
| u16::from(!ins)
|
||||
| u16::from(ins);
|
||||
self.push(u32::from(special_status_word), Size::Word)?;
|
||||
// Format & vector
|
||||
self.push(0x8002, Size::Word)?;
|
||||
|
25
src/main.rs
25
src/main.rs
@ -15,16 +15,13 @@ mod symbol;
|
||||
mod symbol_table;
|
||||
mod symbol_tables;
|
||||
mod term;
|
||||
use crate::{
|
||||
backplane::Backplane,
|
||||
location::Location,
|
||||
m68k::{DetailedBusError, M68K},
|
||||
};
|
||||
use crate::{backplane::Backplane, location::Location, m68k::M68K};
|
||||
use anyhow::anyhow;
|
||||
use clap::Parser;
|
||||
use disas::DisassemblyError;
|
||||
use indexmap::IndexSet;
|
||||
use itertools::Itertools;
|
||||
use m68k::InsExecError;
|
||||
use parse_int::parse;
|
||||
use reedline_repl_rs::{
|
||||
clap::{builder::BoolishValueParser, Arg, ArgAction, Command},
|
||||
@ -286,22 +283,22 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
if args.get_flag("phys") {
|
||||
for i in 0..count {
|
||||
match size {
|
||||
peek::Size::Byte => data.push(bus.read_byte_phys(addr + i)? as u32),
|
||||
peek::Size::Word => data.push(bus.read_word_phys(addr + (i * 2))? as u32),
|
||||
peek::Size::Byte => data.push(u32::from(bus.read_byte_phys(addr + i)?)),
|
||||
peek::Size::Word => data.push(u32::from(bus.read_word_phys(addr + (i * 2))?)),
|
||||
peek::Size::LongWord => data.push(
|
||||
(bus.read_word_phys(addr + (i * 4))? as u32) << 16
|
||||
| (bus.read_word_phys(addr + (i * 4) + 2)? as u32),
|
||||
u32::from(bus.read_word_phys(addr + (i * 4))?) << 16
|
||||
| u32::from(bus.read_word_phys(addr + (i * 4) + 2)?),
|
||||
),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..count {
|
||||
match size {
|
||||
peek::Size::Byte => data.push(bus.read_byte(addr + i)? as u32),
|
||||
peek::Size::Word => data.push(bus.read_word(addr + (i * 2))? as u32),
|
||||
peek::Size::Byte => data.push(u32::from(bus.read_byte(addr + i)?)),
|
||||
peek::Size::Word => data.push(u32::from(bus.read_word(addr + (i * 2))?)),
|
||||
peek::Size::LongWord => data.push(
|
||||
(bus.read_word(addr + (i * 4))? as u32) << 16
|
||||
| (bus.read_word(addr + (i * 4) + 2)? as u32),
|
||||
u32::from(bus.read_word(addr + (i * 4))?) << 16
|
||||
| u32::from(bus.read_word(addr + (i * 4) + 2)?),
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -527,7 +524,7 @@ fn disas_fmt(
|
||||
cpu: &mut M68K,
|
||||
addr: u32,
|
||||
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) {
|
||||
format!("{table}:{symbol} + {offset} (0x{addr:x})")
|
||||
} else {
|
||||
|
13
src/mmu.rs
13
src/mmu.rs
@ -49,7 +49,7 @@ impl Card for MmuCard {
|
||||
let offset = address % 4;
|
||||
match 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!(),
|
||||
}
|
||||
}
|
||||
@ -86,18 +86,19 @@ impl Card for MmuCard {
|
||||
match offset {
|
||||
0 => (),
|
||||
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 => {
|
||||
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 => {
|
||||
if self.print_debug {
|
||||
println!(
|
||||
"Clearing TLB entry {:#x} ( page start {:#x} )",
|
||||
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;
|
||||
@ -164,7 +165,7 @@ impl Mmu for MmuCard {
|
||||
let print_debug = self.print_debug;
|
||||
if self.enabled {
|
||||
if print_debug {
|
||||
println!("Translating {:#x}", address);
|
||||
println!("Translating {address:#x}");
|
||||
}
|
||||
let page = address >> 12;
|
||||
let offset = address & 0xFFF;
|
||||
@ -192,7 +193,7 @@ impl Mmu for MmuCard {
|
||||
let mapping_hi = backplane.read_word_phys(mapping_address)?;
|
||||
let mapping_lo = backplane.read_word_phys(mapping_address + 2)?;
|
||||
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;
|
||||
mapping
|
||||
};
|
||||
|
@ -16,8 +16,8 @@ impl Format {
|
||||
Self::Hex => format!("0x{:0>width$x}", num, width = size.byte_count() * 2),
|
||||
Self::Decimal => {
|
||||
let num = match size {
|
||||
Size::Byte => num as u8 as i8 as i32,
|
||||
Size::Word => num as u16 as i16 as i32,
|
||||
Size::Byte => i32::from(num as u8 as i8),
|
||||
Size::Word => i32::from(num as u16 as i16),
|
||||
Size::LongWord => num as i32,
|
||||
};
|
||||
format!("{num}")
|
||||
|
@ -77,7 +77,7 @@ impl Card for Rom {
|
||||
match address {
|
||||
(0..=0xEF) => NullableResult::Ok(self.ram[address as usize]),
|
||||
(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)),
|
||||
_ => NullableResult::Null,
|
||||
}
|
||||
@ -144,7 +144,7 @@ impl Display for Rom {
|
||||
if self.enabled {
|
||||
f.write_fmt(format_args!(
|
||||
", enabled at base address {:#x}",
|
||||
(self.start as u32) << 16
|
||||
u32::from(self.start) << 16
|
||||
))?;
|
||||
};
|
||||
Ok(())
|
||||
|
@ -102,14 +102,13 @@ impl Card for Storage {
|
||||
0x9 => match data {
|
||||
0x0 => {
|
||||
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();
|
||||
let mut buf = Vec::new();
|
||||
buf.resize(self.count as usize * SECTOR_SIZE as usize, 0);
|
||||
let mut buf = vec![0; self.count as usize * SECTOR_SIZE as usize];
|
||||
match file.read_exact(&mut buf) {
|
||||
Ok(_) => (),
|
||||
Ok(()) => (),
|
||||
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (),
|
||||
Err(e) => Err(e).unwrap(),
|
||||
Err(e) => panic!("{e:?}"),
|
||||
}
|
||||
self.read_data.extend(buf);
|
||||
self.status.set(Status::DATA_READY, true);
|
||||
@ -117,14 +116,13 @@ impl Card for Storage {
|
||||
}
|
||||
0x1 => {
|
||||
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();
|
||||
let mut buf = Vec::new();
|
||||
buf.resize(self.count as usize * SECTOR_SIZE as usize, 0);
|
||||
let mut buf = vec![0; self.count as usize * SECTOR_SIZE as usize];
|
||||
match file.read_exact(&mut buf) {
|
||||
Ok(_) => (),
|
||||
Ok(()) => (),
|
||||
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (),
|
||||
Err(e) => Err(e).unwrap(),
|
||||
Err(e) => panic!("{e:?}"),
|
||||
}
|
||||
self.read_data.extend(buf);
|
||||
self.status.set(Status::BUSY, true);
|
||||
|
@ -84,8 +84,8 @@ impl SymbolTable {
|
||||
self.breakpoints = self
|
||||
.breakpoints
|
||||
.iter()
|
||||
.filter(|&sym| table.symbols.contains_key(sym))
|
||||
.cloned()
|
||||
.filter(|sym| table.symbols.contains_key(sym))
|
||||
.collect::<IndexSet<_>>();
|
||||
self.symbols = table.symbols;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user