Abort instruction processing on misaligned address trap
This commit is contained in:
parent
f5df45499a
commit
2110bfbab8
110
src/m68k.rs
110
src/m68k.rs
@ -9,7 +9,7 @@ use crate::{
|
|||||||
disas::{self, DisassemblyError},
|
disas::{self, DisassemblyError},
|
||||||
instruction::{
|
instruction::{
|
||||||
ArithType, BitInsType, EffectiveAddress, Instruction, MoveDirection, ShiftDirection,
|
ArithType, BitInsType, EffectiveAddress, Instruction, MoveDirection, ShiftDirection,
|
||||||
ShiftType, Size, ControlRegister,
|
ShiftType, Size, ControlRegister, Rotation,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -122,6 +122,31 @@ impl MemCycleInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum InsExecError {
|
||||||
|
BusError(DetailedBusError),
|
||||||
|
AbnormalTrap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InsExecError {
|
||||||
|
pub fn try_into_bus_error(self) -> Result<DetailedBusError, Self> {
|
||||||
|
if let Self::BusError(v) = self {
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DetailedBusError> for InsExecError {
|
||||||
|
fn from(v: DetailedBusError) -> Self {
|
||||||
|
Self::BusError(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct M68K {
|
pub struct M68K {
|
||||||
dregs: [u32; 8],
|
dregs: [u32; 8],
|
||||||
@ -222,15 +247,26 @@ impl M68K {
|
|||||||
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| DetailedBusError {
|
||||||
cause: BusErrorCause::ReadingInstruction,
|
cause: BusErrorCause::ReadingInstruction,
|
||||||
..err
|
..err.try_into_bus_error().unwrap()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self) {
|
pub fn step(&mut self) {
|
||||||
let Err(bus_error) = self.step_ret_berr() else {
|
let bus_error = match self.step_ret_berr() {
|
||||||
self.stored_mem_cycles.clear();
|
Ok(_) => {
|
||||||
return;
|
self.stored_mem_cycles.clear();
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
match e {
|
||||||
|
InsExecError::BusError(e) => e,
|
||||||
|
InsExecError::AbnormalTrap => {
|
||||||
|
self.stored_mem_cycles.clear();
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if self.handling_bus_error {
|
if self.handling_bus_error {
|
||||||
println!("{} while handling bus error, halting", bus_error);
|
println!("{} while handling bus error, halting", bus_error);
|
||||||
@ -261,7 +297,7 @@ impl M68K {
|
|||||||
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", snd_bus_error, 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.stopped = true;
|
||||||
self.stored_mem_cycles.clear();
|
self.stored_mem_cycles.clear();
|
||||||
self.use_stored_mem_cycles = false;
|
self.use_stored_mem_cycles = false;
|
||||||
@ -271,7 +307,7 @@ impl M68K {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_ret_berr(&mut self) -> Result<(), DetailedBusError> {
|
fn step_ret_berr(&mut self) -> Result<(), InsExecError> {
|
||||||
if self.stopped {
|
if self.stopped {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -281,7 +317,7 @@ 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) => panic!("Invalid instruction"),
|
||||||
Err(DisassemblyError::ReadError(e)) => return Err(e),
|
Err(DisassemblyError::ReadError(e)) => return Err(e.into()),
|
||||||
};
|
};
|
||||||
self.pc = new_pc;
|
self.pc = new_pc;
|
||||||
match ins {
|
match ins {
|
||||||
@ -961,8 +997,8 @@ impl M68K {
|
|||||||
Instruction::Shift(typ, size, dir, rot, dst) => {
|
Instruction::Shift(typ, size, dir, rot, dst) => {
|
||||||
let dst_val = self.read_effective(dst, size)?;
|
let dst_val = self.read_effective(dst, size)?;
|
||||||
let rotation = match rot {
|
let rotation = match rot {
|
||||||
crate::instruction::Rotation::Immediate(rot) => rot,
|
Rotation::Immediate(rot) => rot,
|
||||||
crate::instruction::Rotation::Register(dreg) => {
|
Rotation::Register(dreg) => {
|
||||||
self.read_effective(EffectiveAddress::DataReg(dreg), Size::Byte)? as u8
|
self.read_effective(EffectiveAddress::DataReg(dreg), Size::Byte)? as u8
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1053,7 +1089,7 @@ impl M68K {
|
|||||||
src: EffectiveAddress,
|
src: EffectiveAddress,
|
||||||
mut size: Size,
|
mut size: Size,
|
||||||
typ: ArithType,
|
typ: ArithType,
|
||||||
) -> Result<(), DetailedBusError> {
|
) -> Result<(), InsExecError> {
|
||||||
let ext = match typ {
|
let ext = match typ {
|
||||||
ArithType::Ext => (self.sr & 0x0010) > 0,
|
ArithType::Ext => (self.sr & 0x0010) > 0,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1129,7 +1165,7 @@ impl M68K {
|
|||||||
src: EffectiveAddress,
|
src: EffectiveAddress,
|
||||||
mut size: Size,
|
mut size: Size,
|
||||||
typ: ArithType,
|
typ: ArithType,
|
||||||
) -> Result<(), DetailedBusError> {
|
) -> Result<(), InsExecError> {
|
||||||
let ext = match typ {
|
let ext = match typ {
|
||||||
ArithType::Ext => (self.sr & 0x0010) > 0,
|
ArithType::Ext => (self.sr & 0x0010) > 0,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1204,7 +1240,7 @@ impl M68K {
|
|||||||
dst: EffectiveAddress,
|
dst: EffectiveAddress,
|
||||||
src: EffectiveAddress,
|
src: EffectiveAddress,
|
||||||
size: Size,
|
size: Size,
|
||||||
) -> Result<(), DetailedBusError> {
|
) -> Result<(), InsExecError> {
|
||||||
let src_val = self.read_effective(src, size)?;
|
let src_val = self.read_effective(src, size)?;
|
||||||
let dst_val = self.read_effective(dst, size)?;
|
let dst_val = self.read_effective(dst, size)?;
|
||||||
let res;
|
let res;
|
||||||
@ -1253,7 +1289,7 @@ impl M68K {
|
|||||||
&mut self,
|
&mut self,
|
||||||
effective_address: EffectiveAddress,
|
effective_address: EffectiveAddress,
|
||||||
size: Size,
|
size: Size,
|
||||||
) -> Result<u32, DetailedBusError> {
|
) -> Result<u32, InsExecError> {
|
||||||
match effective_address {
|
match effective_address {
|
||||||
EffectiveAddress::Immediate(x) => Ok(x),
|
EffectiveAddress::Immediate(x) => Ok(x),
|
||||||
EffectiveAddress::DataReg(x) => Ok(Self::trim_excess(self.dregs[x as usize], size)),
|
EffectiveAddress::DataReg(x) => Ok(Self::trim_excess(self.dregs[x as usize], size)),
|
||||||
@ -1276,10 +1312,10 @@ impl M68K {
|
|||||||
EffectiveAddress::AddressPostinc(x) => {
|
EffectiveAddress::AddressPostinc(x) => {
|
||||||
let mut address =
|
let mut address =
|
||||||
self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?;
|
self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?;
|
||||||
let val = self.read_address(address, size);
|
let val = self.read_address(address, size)?;
|
||||||
address = address.wrapping_add(u32::from(size.byte_size()));
|
address = address.wrapping_add(u32::from(size.byte_size()));
|
||||||
self.write_effective(EffectiveAddress::AddressReg(x), address, Size::Long)?;
|
self.write_effective(EffectiveAddress::AddressReg(x), address, Size::Long)?;
|
||||||
val
|
Ok(val)
|
||||||
}
|
}
|
||||||
EffectiveAddress::AddressPredec(x) => {
|
EffectiveAddress::AddressPredec(x) => {
|
||||||
let address = self
|
let address = self
|
||||||
@ -1330,7 +1366,7 @@ impl M68K {
|
|||||||
effective_address: EffectiveAddress,
|
effective_address: EffectiveAddress,
|
||||||
data: u32,
|
data: u32,
|
||||||
size: Size,
|
size: Size,
|
||||||
) -> Result<(), DetailedBusError> {
|
) -> Result<(), InsExecError> {
|
||||||
match effective_address {
|
match effective_address {
|
||||||
EffectiveAddress::DataReg(x) => {
|
EffectiveAddress::DataReg(x) => {
|
||||||
self.dregs[x as usize] = Self::set_with_size(self.dregs[x as usize], data, size);
|
self.dregs[x as usize] = Self::set_with_size(self.dregs[x as usize], data, size);
|
||||||
@ -1408,7 +1444,7 @@ impl M68K {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_address(&mut self, address: u32, size: Size) -> Result<u32, DetailedBusError> {
|
fn read_address(&mut self, address: u32, size: Size) -> Result<u32, InsExecError> {
|
||||||
// println!("READ {:x}, {:?}", address, size);
|
// println!("READ {:x}, {:?}", address, size);
|
||||||
let address = address & 0xFF_FFFF;
|
let address = address & 0xFF_FFFF;
|
||||||
match size {
|
match size {
|
||||||
@ -1426,7 +1462,7 @@ impl M68K {
|
|||||||
address: u32,
|
address: u32,
|
||||||
data: u32,
|
data: u32,
|
||||||
size: Size,
|
size: Size,
|
||||||
) -> Result<(), DetailedBusError> {
|
) -> Result<(), InsExecError> {
|
||||||
// println!("WRITE {:x}, {:?}, data {:x}", address, size, data);
|
// 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)?,
|
||||||
@ -1439,7 +1475,7 @@ impl M68K {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_byte(&mut self, address: u32) -> Result<u8, DetailedBusError> {
|
fn read_byte(&mut self, address: u32) -> Result<u8, InsExecError> {
|
||||||
let address = address & 0xFF_FFFF;
|
let address = address & 0xFF_FFFF;
|
||||||
if self.use_stored_mem_cycles {
|
if self.use_stored_mem_cycles {
|
||||||
let cycle = self.stored_mem_cycles.remove(0);
|
let cycle = self.stored_mem_cycles.remove(0);
|
||||||
@ -1449,7 +1485,7 @@ impl M68K {
|
|||||||
} = cycle
|
} = cycle
|
||||||
{
|
{
|
||||||
if stored_address == address {
|
if stored_address == address {
|
||||||
return result;
|
return Ok(result?);
|
||||||
} else {
|
} else {
|
||||||
panic!("Stored bus cycle has wrong address when reading byte (reading {:#x}, stored {:#x})", address, stored_address);
|
panic!("Stored bus cycle has wrong address when reading byte (reading {:#x}, stored {:#x})", address, stored_address);
|
||||||
}
|
}
|
||||||
@ -1468,10 +1504,10 @@ impl M68K {
|
|||||||
result: result.clone(),
|
result: result.clone(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
result
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_byte(&mut self, address: u32, data: u8) -> Result<(), DetailedBusError> {
|
fn write_byte(&mut self, address: u32, data: u8) -> Result<(), InsExecError> {
|
||||||
let address = address & 0xFF_FFFF;
|
let address = address & 0xFF_FFFF;
|
||||||
if self.use_stored_mem_cycles {
|
if self.use_stored_mem_cycles {
|
||||||
let cycle = self.stored_mem_cycles.remove(0);
|
let cycle = self.stored_mem_cycles.remove(0);
|
||||||
@ -1482,7 +1518,7 @@ impl M68K {
|
|||||||
} = cycle
|
} = cycle
|
||||||
{
|
{
|
||||||
if stored_address == address && stored_data == data {
|
if stored_address == address && stored_data == data {
|
||||||
return 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 {:#x}, stored {:#x})", address, stored_address);
|
||||||
} else if stored_data != data {
|
} else if stored_data != data {
|
||||||
@ -1507,13 +1543,14 @@ impl M68K {
|
|||||||
result: result.clone(),
|
result: result.clone(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
result
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_word(&mut self, address: u32) -> Result<u16, DetailedBusError> {
|
fn read_word(&mut self, address: u32) -> Result<u16, InsExecError> {
|
||||||
let address = address & 0xFF_FFFF;
|
let address = address & 0xFF_FFFF;
|
||||||
if address & 0x1 != 0 {
|
if address & 0x1 != 0 {
|
||||||
self.trap(3)?;
|
self.trap(3)?;
|
||||||
|
return Err(InsExecError::AbnormalTrap);
|
||||||
}
|
}
|
||||||
if self.use_stored_mem_cycles {
|
if self.use_stored_mem_cycles {
|
||||||
let cycle = self.stored_mem_cycles.remove(0);
|
let cycle = self.stored_mem_cycles.remove(0);
|
||||||
@ -1523,7 +1560,7 @@ impl M68K {
|
|||||||
} = cycle
|
} = cycle
|
||||||
{
|
{
|
||||||
if stored_address == address {
|
if stored_address == address {
|
||||||
return result;
|
return Ok(result?);
|
||||||
} else {
|
} else {
|
||||||
panic!("Stored bus cycle has wrong address when reading word (reading {:#x}, stored {:#x})", address, stored_address);
|
panic!("Stored bus cycle has wrong address when reading word (reading {:#x}, stored {:#x})", address, stored_address);
|
||||||
}
|
}
|
||||||
@ -1542,13 +1579,14 @@ impl M68K {
|
|||||||
result: result.clone(),
|
result: result.clone(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
result
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_word(&mut self, address: u32, data: u16) -> Result<(), DetailedBusError> {
|
fn write_word(&mut self, address: u32, data: u16) -> Result<(), InsExecError> {
|
||||||
let address = address & 0xFF_FFFF;
|
let address = address & 0xFF_FFFF;
|
||||||
if address & 0x1 != 0 {
|
if address & 0x1 != 0 {
|
||||||
self.trap(3)?;
|
self.trap(3)?;
|
||||||
|
return Err(InsExecError::AbnormalTrap);
|
||||||
}
|
}
|
||||||
if self.use_stored_mem_cycles {
|
if self.use_stored_mem_cycles {
|
||||||
let cycle = self.stored_mem_cycles.remove(0);
|
let cycle = self.stored_mem_cycles.remove(0);
|
||||||
@ -1559,7 +1597,7 @@ impl M68K {
|
|||||||
} = cycle
|
} = cycle
|
||||||
{
|
{
|
||||||
if stored_address == address && stored_data == data {
|
if stored_address == address && stored_data == data {
|
||||||
return 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 {:#x}, stored {:#x})", address, stored_address);
|
||||||
} else if stored_data != data {
|
} else if stored_data != data {
|
||||||
@ -1584,7 +1622,7 @@ impl M68K {
|
|||||||
result: result.clone(),
|
result: result.clone(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
result
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trim_excess(num: u32, size: Size) -> u32 {
|
fn trim_excess(num: u32, size: Size) -> u32 {
|
||||||
@ -1603,7 +1641,7 @@ impl M68K {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn effective_address(&mut self, ea: EffectiveAddress) -> Result<u32, DetailedBusError> {
|
fn effective_address(&mut self, ea: EffectiveAddress) -> Result<u32, InsExecError> {
|
||||||
match ea {
|
match ea {
|
||||||
EffectiveAddress::Address(x) => {
|
EffectiveAddress::Address(x) => {
|
||||||
Ok(self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?)
|
Ok(self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?)
|
||||||
@ -1642,11 +1680,11 @@ impl M68K {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, data: u32, size: Size) -> Result<(), DetailedBusError> {
|
fn push(&mut self, data: u32, size: Size) -> Result<(), InsExecError> {
|
||||||
self.write_effective(EffectiveAddress::AddressPredec(7), data, size)
|
self.write_effective(EffectiveAddress::AddressPredec(7), data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self, size: Size) -> Result<u32, DetailedBusError> {
|
fn pop(&mut self, size: Size) -> Result<u32, InsExecError> {
|
||||||
self.read_effective(EffectiveAddress::AddressPostinc(7), size)
|
self.read_effective(EffectiveAddress::AddressPostinc(7), size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1654,7 +1692,7 @@ impl M68K {
|
|||||||
(self.sr & 0x2000) > 0
|
(self.sr & 0x2000) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trap(&mut self, vector: u8) -> Result<(), DetailedBusError> {
|
fn trap(&mut self, vector: u8) -> Result<(), InsExecError> {
|
||||||
let new_pc = self.read_address((u32::from(vector) * 4) + self.vbr, Size::Long)?;
|
let new_pc = self.read_address((u32::from(vector) * 4) + self.vbr, Size::Long)?;
|
||||||
self.push(u32::from(vector), Size::Word)?;
|
self.push(u32::from(vector), Size::Word)?;
|
||||||
self.push(self.pc, Size::Long)?;
|
self.push(self.pc, Size::Long)?;
|
||||||
@ -1671,7 +1709,7 @@ impl M68K {
|
|||||||
byte_access: bool,
|
byte_access: bool,
|
||||||
fault_addr: u32,
|
fault_addr: u32,
|
||||||
write_data: u16,
|
write_data: u16,
|
||||||
) -> Result<(), DetailedBusError> {
|
) -> Result<(), InsExecError> {
|
||||||
let new_pc = self.read_address(2 * 4 + self.vbr, Size::Long)?;
|
let new_pc = self.read_address(2 * 4 + self.vbr, Size::Long)?;
|
||||||
// Version & internal information
|
// Version & internal information
|
||||||
self.push(0, Size::Long)?;
|
self.push(0, Size::Long)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user