From a52442493a7bdfccdabe1db824cbf5b2fad44263 Mon Sep 17 00:00:00 2001 From: pjht Date: Tue, 24 Jan 2023 10:23:46 -0600 Subject: [PATCH] Return bus errors from cpu.step() instead of panicking --- src/disas.rs | 10 +- src/m68k.rs | 550 +++++++++++++++++++++++++++++---------------------- src/main.rs | 12 +- 3 files changed, 331 insertions(+), 241 deletions(-) diff --git a/src/disas.rs b/src/disas.rs index 3758b56..23e3cd9 100644 --- a/src/disas.rs +++ b/src/disas.rs @@ -62,14 +62,14 @@ pub fn disasm( #[derive(Debug)] pub enum DisassemblyError { InvalidInstruction, - ReadError(u32, T), + ReadError(T), } impl Display for DisassemblyError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidInstruction => f.write_str("Invalid instruction"), - Self::ReadError(addr, e) => f.write_fmt(format_args!("Read error at {} ({})", addr, e)), + Self::ReadError(e) => f.write_fmt(format_args!("{}", e)), } } } @@ -926,11 +926,9 @@ impl Disasm<'_, T> { } fn read_prog_word(&mut self) -> Result> { - let word = ((self.byte_read)(self.pc) - .map_err(|e| DisassemblyError::ReadError(self.pc, e))? as u16) + let word = ((self.byte_read)(self.pc).map_err(|e| DisassemblyError::ReadError(e))? as u16) << 8 - | ((self.byte_read)(self.pc + 1) - .map_err(|e| DisassemblyError::ReadError(self.pc + 1, e))? as u16); + | ((self.byte_read)(self.pc + 1).map_err(|e| DisassemblyError::ReadError(e))? as u16); self.pc += 2; Ok(word) } diff --git a/src/m68k.rs b/src/m68k.rs index c74400e..5a980fe 100644 --- a/src/m68k.rs +++ b/src/m68k.rs @@ -24,6 +24,44 @@ impl Display for BusError { impl Error for BusError {} +#[derive(Debug)] +pub enum BusErrorCause { + ReadingByte, + ReadingWord, + WritingByte, + WritingWord, + ReadingInstruction, +} + +impl Display for BusErrorCause { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BusErrorCause::ReadingByte => f.write_str("reading byte from"), + BusErrorCause::ReadingWord => f.write_str("reading word from"), + BusErrorCause::WritingByte => f.write_str("writing byte to"), + BusErrorCause::WritingWord => f.write_str("writing word to"), + BusErrorCause::ReadingInstruction => f.write_str("reading instruction at"), + } + } +} + +#[derive(Debug)] +pub struct DetailedBusError { + address: u32, + cause: BusErrorCause, +} + +impl Display for DetailedBusError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "Bus error {} 0x{:0>8x}", + self.cause, self.address + )) + } +} + +impl Error for DetailedBusError {} + // pub trait Bus: Debug { // fn read_word(&mut self, address: u32) -> Result; // fn read_byte(&mut self, address: u32) -> Result; @@ -93,27 +131,37 @@ impl M68K { } pub fn reset(&mut self) { - let ssp_high = self.read_word(0); - let ssp_low = self.read_word(2); - self.ssp = ((ssp_high as u32) << 16) | (ssp_low as u32); - let pc_high = self.read_word(4); - let pc_low = self.read_word(6); - self.pc = (u32::from(pc_high) << 16) | u32::from(pc_low); - self.sr = 0x2700 | self.sr & 0xFF; - self.stopped = false; - self.initialized = true; + if let (Ok(ssp_high), Ok(ssp_low), Ok(pc_high), Ok(pc_low)) = ( + self.read_word(0), + self.read_word(2), + self.read_word(4), + self.read_word(6), + ) { + self.ssp = ((ssp_high as u32) << 16) | (ssp_low as u32); + self.pc = (u32::from(pc_high) << 16) | u32::from(pc_low); + self.sr = 0x2700 | self.sr & 0xFF; + self.stopped = false; + self.initialized = true; + } else { + self.stopped = true; + } } pub fn disassemble( &mut self, loc: u32, - ) -> Result<(Instruction, u32), DisassemblyError> { - disas::disasm(loc, &mut |addr| self.bus.read_byte(addr)) + ) -> Result<(Instruction, u32), DisassemblyError> { + disas::disasm(loc, &mut |addr| { + self.bus.read_byte(addr).map_err(|_| DetailedBusError { + address: addr, + cause: BusErrorCause::ReadingInstruction, + }) + }) } - pub fn step(&mut self) { + pub fn step(&mut self) -> Result<(), DetailedBusError> { if self.stopped { - return; + return Ok(()); } if !self.initialized { self.reset(); @@ -121,9 +169,7 @@ impl M68K { let (ins, new_pc) = match self.disassemble(self.pc) { Ok(ins) => ins, Err(DisassemblyError::InvalidInstruction) => panic!("Invalid instruction"), - Err(DisassemblyError::ReadError(addr, _e)) => { - panic!("Bus error while reading instruction at address {addr:#x}") - } + Err(DisassemblyError::ReadError(e)) => return Err(e), }; self.pc = new_pc; match ins { @@ -132,9 +178,9 @@ impl M68K { } Instruction::OriSr(val) => self.sr |= val as u16, Instruction::Ori(size, dst, val) => { - let dst_val = self.read_effective(dst, size); + let dst_val = self.read_effective(dst, size)?; let res = dst_val | val; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let zero = res == 0; let neg = match size { Size::Byte => (res & 0x80) > 0, @@ -150,9 +196,9 @@ impl M68K { } Instruction::AndiSr(val) => self.sr &= val as u16, Instruction::Andi(size, dst, val) => { - let dst_val = self.read_effective(dst, size); + let dst_val = self.read_effective(dst, size)?; let res = dst_val & val; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let zero = res == 0; let neg = match size { Size::Byte => (res & 0x80) > 0, @@ -164,19 +210,19 @@ impl M68K { self.sr = (self.sr & 0xFFE0) | new_flags; } Instruction::Subi(size, dst, val) => { - self.sub(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg); + self.sub(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg)?; } Instruction::Addi(size, dst, val) => { - self.add(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg); + self.add(dst, EffectiveAddress::Immediate(val), size, ArithType::Reg)?; } Instruction::EoriCcr(val) => { self.sr = (self.sr & 0xFF00) | ((self.sr & 0xFF) ^ val as u16); } Instruction::EoriSr(val) => self.sr ^= val as u16, Instruction::Eori(size, dst, val) => { - let dst_val = self.read_effective(dst, size); + let dst_val = self.read_effective(dst, size)?; let res = dst_val ^ val; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let zero = res == 0; let neg = match size { Size::Byte => (res & 0x80) > 0, @@ -188,7 +234,7 @@ impl M68K { self.sr = (self.sr & 0xFFE0) | new_flags; } Instruction::Cmpi(size, dst, val) => { - self.cmp(dst, EffectiveAddress::Immediate(val), size); + self.cmp(dst, EffectiveAddress::Immediate(val), size)?; } Instruction::Bit { typ, @@ -196,8 +242,8 @@ impl M68K { dst, size, } => { - let mut dst_val = self.read_effective(dst, size); - let idx = self.read_effective(idx, Size::Byte) as usize; + let mut dst_val = self.read_effective(dst, size)?; + let idx = self.read_effective(idx, Size::Byte)? as usize; let dst_bits = BitSlice::::from_element_mut(&mut dst_val); let dst_bit = dst_bits[idx]; self.sr = (self.sr & 0xFFFB) | (u16::from(dst_bit) << 2); @@ -207,7 +253,7 @@ impl M68K { BitInsType::Clear => dst_bits.set(idx, false), BitInsType::Set => dst_bits.set(idx, true), } - self.write_effective(dst, dst_val, size); + self.write_effective(dst, dst_val, size)?; } Instruction::Movep { dir, @@ -222,34 +268,34 @@ impl M68K { let high = self.read_effective( EffectiveAddress::AddressDisplacement(areg, start_offset), Size::Byte, - ) as u8; + )? as u8; let low = self.read_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 2), Size::Byte, - ) as u8; + )? as u8; self.write_effective( EffectiveAddress::DataReg(dreg), ((high as u32) << 8) | (low as u32), Size::Word, - ); + )?; } Size::Long => { let high = self.read_effective( EffectiveAddress::AddressDisplacement(areg, start_offset), Size::Byte, - ) as u8; + )? as u8; let mid_high = self.read_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 2), Size::Byte, - ) as u8; + )? as u8; let mid_low = self.read_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 4), Size::Byte, - ) as u8; + )? as u8; let low = self.read_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 6), Size::Byte, - ) as u8; + )? as u8; self.write_effective( EffectiveAddress::DataReg(dreg), ((high as u32) << 24) @@ -257,7 +303,7 @@ impl M68K { | ((mid_low as u32) << 8) | (low as u32), Size::Word, - ); + )?; } }, MoveDirection::RegToMem => match size { @@ -267,40 +313,40 @@ impl M68K { EffectiveAddress::AddressDisplacement(areg, start_offset), self.dregs[dreg as usize] & 0xFF, Size::Byte, - ); + )?; self.write_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 2), (self.dregs[dreg as usize] & 0xFF00) >> 8, Size::Byte, - ); + )?; } Size::Long => { self.write_effective( EffectiveAddress::AddressDisplacement(areg, start_offset), self.dregs[dreg as usize] & 0xFF, Size::Byte, - ); + )?; self.write_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 2), (self.dregs[dreg as usize] & 0xFF00) >> 8, Size::Byte, - ); + )?; self.write_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 4), (self.dregs[dreg as usize] & 0xFF_0000) >> 16, Size::Byte, - ); + )?; self.write_effective( EffectiveAddress::AddressDisplacement(areg, start_offset + 6), (self.dregs[dreg as usize] & 0xFF00_0000) >> 24, Size::Byte, - ); + )?; } }, }, Instruction::Move { src, dst, size } => { - let src_val = self.read_effective(src, size); - self.write_effective(dst, src_val, size); + let src_val = self.read_effective(src, size)?; + self.write_effective(dst, src_val, size)?; if !matches!(dst, EffectiveAddress::AddressReg(_)) { let zero = src_val == 0; let neg = match size { @@ -314,28 +360,28 @@ impl M68K { } } Instruction::MoveFromSr(dst) => { - self.write_effective(dst, u32::from(self.sr), Size::Word); + self.write_effective(dst, u32::from(self.sr), Size::Word)?; } Instruction::MoveToCcr(src) => { - let src_val = self.read_effective(src, Size::Byte); + let src_val = self.read_effective(src, Size::Byte)?; self.sr = (self.sr & 0xFF00) | src_val as u16; } Instruction::MoveToSr(src) => { - let src_val = self.read_effective(src, Size::Word); + let src_val = self.read_effective(src, Size::Word)?; self.sr = src_val as u16; } Instruction::Negx(size, dst) => { - self.sub(dst, EffectiveAddress::Immediate(0), size, ArithType::Ext); + self.sub(dst, EffectiveAddress::Immediate(0), size, ArithType::Ext)?; } Instruction::Clr(size, dst) => { - self.write_effective(dst, 0, size); + self.write_effective(dst, 0, size)?; self.sr = (self.sr & 0xFFF0) | 0b0100; } Instruction::Neg(size, dst) => { - self.sub(dst, EffectiveAddress::Immediate(0), size, ArithType::Reg); + self.sub(dst, EffectiveAddress::Immediate(0), size, ArithType::Reg)?; } Instruction::Not(size, dst) => { - let dst_val = self.read_effective(dst, size); + let dst_val = self.read_effective(dst, size)?; let res = Self::trim_excess(!dst_val, size); let zero = res == 0; let neg = match size { @@ -343,12 +389,12 @@ impl M68K { Size::Word => (res & 0x8000) > 0, Size::Long => (res & 0x8000_0000) > 0, }; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; self.sr = (self.sr & 0xFFF0) | u16::from(neg) << 3 | u16::from(zero) << 2; } Instruction::Ext(size, dreg) => { let dst = EffectiveAddress::DataReg(dreg); - let dst_val = self.read_effective(dst, Size::Byte); + let dst_val = self.read_effective(dst, Size::Byte)?; let res = i32::from(dst_val as u8 as i8) as u32; let zero = res == 0; let neg = match size { @@ -357,33 +403,33 @@ impl M68K { Size::Long => (res & 0x8000_0000) > 0, }; self.sr = (self.sr & 0xFFF0) | u16::from(neg) << 3 | u16::from(zero) << 2; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; } Instruction::Nbcd(_) => todo!(), Instruction::Swap(dreg) => { let dst = EffectiveAddress::DataReg(dreg); - let dst_val = self.read_effective(dst, Size::Long); + let dst_val = self.read_effective(dst, Size::Long)?; let res = (dst_val & 0xFFFF) << 16 | (dst_val & 0xFFFF_0000); let zero = res == 0; let neg = (res & 0x8000_0000) > 0; self.sr = (self.sr & 0xFFF0) | u16::from(neg) << 3 | u16::from(zero) << 2; - self.write_effective(dst, res, Size::Long); + self.write_effective(dst, res, Size::Long)?; } Instruction::Pea(ea) => { - let ea = self.effective_address(ea); - self.push(ea, Size::Long); + let ea = self.effective_address(ea)?; + self.push(ea, Size::Long)?; } Instruction::Tas(dst) => { - let dst_val = self.read_effective(dst, Size::Byte); + let dst_val = self.read_effective(dst, Size::Byte)?; let neg = (dst_val & 0x80) > 0; let zero = dst_val == 0; let old_flags = self.sr & 0xFFE0; let new_flags = (old_flags & 0x10) | u16::from(neg) << 3 | u16::from(zero) << 2; - self.write_effective(dst, dst_val | 0x80, Size::Byte); + self.write_effective(dst, dst_val | 0x80, Size::Byte)?; self.sr = (self.sr & 0xFFE0) | new_flags; } Instruction::Tst(size, src) => { - let dst_val = self.read_effective(src, Size::Byte); + let dst_val = self.read_effective(src, Size::Byte)?; let neg = match size { Size::Byte => (dst_val & 0x80) > 0, Size::Word => (dst_val & 0x8000) > 0, @@ -394,31 +440,31 @@ impl M68K { let new_flags = (old_flags & 0x10) | u16::from(neg) << 3 | u16::from(zero) << 2; self.sr = (self.sr & 0xFFE0) | new_flags; } - Instruction::Trap(vec) => self.trap(vec), + Instruction::Trap(vec) => self.trap(vec)?, Instruction::Link { areg, displacement } => { let dst = EffectiveAddress::AddressReg(areg); - let dst_val = self.read_effective(dst, Size::Long); - self.push(dst_val, Size::Long); - let sp = self.read_effective(EffectiveAddress::AddressReg(7), Size::Long); - self.write_effective(dst, sp, Size::Long); + let dst_val = self.read_effective(dst, Size::Long)?; + self.push(dst_val, Size::Long)?; + let sp = self.read_effective(EffectiveAddress::AddressReg(7), Size::Long)?; + self.write_effective(dst, sp, Size::Long)?; self.write_effective( EffectiveAddress::AddressReg(7), sp.wrapping_add(u32::from(displacement)), Size::Long, - ); + )?; } Instruction::Unlk(areg) => { let dst = EffectiveAddress::AddressReg(areg); - let dst_val = self.read_effective(dst, Size::Long); - self.write_effective(EffectiveAddress::AddressReg(7), dst_val, Size::Long); - let old_dst = self.pop(Size::Long); - self.write_effective(dst, old_dst, Size::Long); + let dst_val = self.read_effective(dst, Size::Long)?; + self.write_effective(EffectiveAddress::AddressReg(7), dst_val, Size::Long)?; + let old_dst = self.pop(Size::Long)?; + self.write_effective(dst, old_dst, Size::Long)?; } Instruction::MoveUsp(dir, areg) => { let areg = EffectiveAddress::AddressReg(areg); match dir { - MoveDirection::MemToReg => self.write_effective(areg, self.usp, Size::Long), - MoveDirection::RegToMem => self.usp = self.read_effective(areg, Size::Long), + MoveDirection::MemToReg => self.write_effective(areg, self.usp, Size::Long)?, + MoveDirection::RegToMem => self.usp = self.read_effective(areg, Size::Long)?, } } Instruction::Reset => { @@ -430,49 +476,49 @@ impl M68K { self.stopped = true; } Instruction::Rte => { - self.sr = self.pop(Size::Word) as u16; - self.pc = self.pop(Size::Long); - self.pop(Size::Long); //Discard format + vector offset + self.sr = self.pop(Size::Word)? as u16; + self.pc = self.pop(Size::Long)?; + self.pop(Size::Long)?; //Discard format + vector offset } - Instruction::Rts => self.pc = self.pop(Size::Long), + Instruction::Rts => self.pc = self.pop(Size::Long)?, Instruction::Trapv => { if self.sr & 0x2 > 0 { - self.trap(7); + self.trap(7)?; } } Instruction::Rtr => { - self.sr = (self.sr & 0xFF00) | u16::from(self.pop(Size::Word) as u8); - self.pc = self.pop(Size::Long); + self.sr = (self.sr & 0xFF00) | u16::from(self.pop(Size::Word)? as u8); + self.pc = self.pop(Size::Long)?; } Instruction::Jsr(ea) => { - self.push(self.pc, Size::Long); - self.pc = self.effective_address(ea); + self.push(self.pc, Size::Long)?; + self.pc = self.effective_address(ea)?; } - Instruction::Jmp(ea) => self.pc = self.effective_address(ea), + Instruction::Jmp(ea) => self.pc = self.effective_address(ea)?, Instruction::Movem(dir, size, dst, regs) => match dir { MoveDirection::MemToReg => { for ® in ®s { - let ea_val = self.read_effective(dst, size); - self.write_effective(reg, ea_val, size); + let ea_val = self.read_effective(dst, size)?; + self.write_effective(reg, ea_val, size)?; } } MoveDirection::RegToMem => { for ® in ®s { - let reg_val = self.read_effective(reg, size); - self.write_effective(dst, reg_val, size); + let reg_val = self.read_effective(reg, size)?; + self.write_effective(dst, reg_val, size)?; } } }, Instruction::Lea(areg, ea) => { - let ea = self.effective_address(ea); - self.write_effective(EffectiveAddress::AddressReg(areg), ea, Size::Long); + let ea = self.effective_address(ea)?; + self.write_effective(EffectiveAddress::AddressReg(areg), ea, Size::Long)?; } Instruction::Chk(src, bound) => { let src = EffectiveAddress::DataReg(src); - let upper_bound_val = self.read_effective(bound, Size::Word) as u16 as i16; - let dreg_val = self.read_effective(src, Size::Word) as u16 as i16; + let upper_bound_val = self.read_effective(bound, Size::Word)? as u16 as i16; + let dreg_val = self.read_effective(src, Size::Word)? as u16 as i16; if dreg_val < 0 || dreg_val > upper_bound_val { - self.trap(6); + self.trap(6)?; } } Instruction::Addq(size, val, dst) => self.add( @@ -484,7 +530,7 @@ impl M68K { } else { ArithType::Reg }, - ), + )?, Instruction::Subq(size, val, dst) => self.sub( dst, EffectiveAddress::Immediate(val as i32 as u32), @@ -494,28 +540,28 @@ impl M68K { } else { ArithType::Reg }, - ), + )?, Instruction::Scc(cond, dst) => self.write_effective( dst, if cond.matches(self.sr as u8) { 0xFF } else { 0 }, Size::Byte, - ), + )?, Instruction::Dbcc(cond, dreg, _disp, new_pc) => { let dst = EffectiveAddress::DataReg(dreg); if cond.matches(self.sr as u8) { - return; + return Ok(()); } - let dst_val = self.read_effective(dst, Size::Word); + let dst_val = self.read_effective(dst, Size::Word)?; let res = dst_val.wrapping_sub(1) as u16; - self.write_effective(dst, u32::from(res), Size::Word); + self.write_effective(dst, u32::from(res), Size::Word)?; if res == 0xFFFF { - return; + return Ok(()); } self.pc = new_pc; } Instruction::Bra(_size, _disp, new_pc) => self.pc = new_pc, Instruction::Bsr(_size, _disp, new_pc) => { - self.push(self.pc, Size::Long); + self.push(self.pc, Size::Long)?; self.pc = new_pc; } Instruction::Bcc(_size, cond, _disp, new_pc) => { @@ -530,14 +576,14 @@ impl M68K { let old_flags = self.sr & 0xFFE0; let new_flags = (old_flags & 0x10) | u16::from(neg) << 3 | u16::from(zero) << 2; self.sr = (self.sr & 0xFFE0) | new_flags; - self.write_effective(EffectiveAddress::DataReg(dreg), imm, Size::Long); + self.write_effective(EffectiveAddress::DataReg(dreg), imm, Size::Long)?; } Instruction::Divu(dst_dreg, src) => { let dst = EffectiveAddress::DataReg(dst_dreg); - let src_val = self.read_effective(src, Size::Word); - let dst_val = self.read_effective(dst, Size::Word); + let src_val = self.read_effective(src, Size::Word)?; + let dst_val = self.read_effective(dst, Size::Word)?; if src_val == 0 { - self.trap(5); + self.trap(5)?; } let dst_val = dst_val as i32; let src_val = i32::from(src_val as u16 as i16); @@ -547,7 +593,7 @@ impl M68K { dst, (rem as i16 as u32) << 16 | (quot as i16 as u32) & 0xFFFF, Size::Long, - ); + )?; if i16::try_from(quot).is_err() || i16::try_from(rem).is_err() { self.sr = (self.sr & 0xFFF0) | 0b0010; } else { @@ -558,14 +604,14 @@ impl M68K { } Instruction::Divs(dst_dreg, src) => { let dst = EffectiveAddress::DataReg(dst_dreg); - let src_val = self.read_effective(src, Size::Word); - let dst_val = self.read_effective(dst, Size::Word); + let src_val = self.read_effective(src, Size::Word)?; + let dst_val = self.read_effective(dst, Size::Word)?; if src_val == 0 { - self.trap(5); + self.trap(5)?; } let quot = dst_val / src_val; let rem = dst_val % src_val; - self.write_effective(dst, rem << 16 | quot & 0xFFFF, Size::Long); + self.write_effective(dst, rem << 16 | quot & 0xFFFF, Size::Long)?; if quot > u32::from(u16::MAX) || rem > u32::from(u16::MAX) { self.sr = (self.sr & 0xFFF0) | 0b0010; } else { @@ -575,10 +621,10 @@ impl M68K { } Instruction::Sbcd { .. } => todo!(), Instruction::Or { size, src, dst } => { - let src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + let src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let res = dst_val | src_val; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let zero = res == 0; let neg = match size { Size::Byte => (res & 0x80) > 0, @@ -589,19 +635,19 @@ impl M68K { let new_flags = (old_flags & 0x10) | u16::from(neg) << 3 | u16::from(zero) << 2; self.sr = (self.sr & 0xFFE0) | new_flags; } - Instruction::Sub { size, src, dst } => self.sub(dst, src, size, ArithType::Reg), - Instruction::Subx { src, dst, size } => self.sub(dst, src, size, ArithType::Ext), + Instruction::Sub { size, src, dst } => self.sub(dst, src, size, ArithType::Reg)?, + Instruction::Subx { src, dst, size } => self.sub(dst, src, size, ArithType::Ext)?, Instruction::Suba(dst_areg, size, src) => self.sub( EffectiveAddress::AddressReg(dst_areg), src, size, ArithType::Addr, - ), + )?, Instruction::Eor { size, src, dst } => { - let src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + let src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let res = dst_val ^ src_val; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let zero = res == 0; let neg = match size { Size::Byte => (res & 0x80) > 0, @@ -615,15 +661,15 @@ impl M68K { Instruction::Cmpm { size, src, dst } => { let src = EffectiveAddress::AddressPostinc(src); let dst = EffectiveAddress::AddressPostinc(dst); - self.cmp(dst, src, size); + self.cmp(dst, src, size)?; } Instruction::Cmp(dst_dreg, size, src) => { - self.cmp(EffectiveAddress::DataReg(dst_dreg), src, size); + self.cmp(EffectiveAddress::DataReg(dst_dreg), src, size)?; } Instruction::Cmpa(dst_areg, size, src) => { let dst = EffectiveAddress::AddressReg(dst_areg); - let src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + let src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let cmp_src = match size { Size::Word => i32::from(src_val as u16 as i16) as u32, Size::Long => src_val, @@ -638,15 +684,15 @@ impl M68K { EffectiveAddress::Immediate(cmp_dst), EffectiveAddress::Immediate(cmp_src), size, - ); + )?; } Instruction::Mulu(dst_dreg, src) => { let dst = EffectiveAddress::DataReg(dst_dreg); - let src_val = self.read_effective(src, Size::Word); - let dst_val = self.read_effective(dst, Size::Word); + let src_val = self.read_effective(src, Size::Word)?; + let dst_val = self.read_effective(dst, Size::Word)?; let res = src_val * dst_val; - self.write_effective(dst, res, Size::Long); + self.write_effective(dst, res, Size::Long)?; let neg = (res & 0x8000_0000) > 0; let zero = res == 0; let old_flags = self.sr & 0xFFE0; @@ -655,10 +701,10 @@ impl M68K { } Instruction::Muls(dst_dreg, src) => { let dst = EffectiveAddress::DataReg(dst_dreg); - let src_val = self.read_effective(src, Size::Word); - let dst_val = self.read_effective(dst, Size::Word); + let src_val = self.read_effective(src, Size::Word)?; + let dst_val = self.read_effective(dst, Size::Word)?; let res = (src_val as i32 * dst_val as i32) as u32; - self.write_effective(dst, res, Size::Long); + self.write_effective(dst, res, Size::Long)?; let neg = (res & 0x8000_0000) > 0; let zero = res == 0; let old_flags = self.sr & 0xFFE0; @@ -668,16 +714,16 @@ impl M68K { Instruction::Abcd { .. } => todo!(), Instruction::Exg { src, dst } => { - let src_val = self.read_effective(src, Size::Long); - let dst_val = self.read_effective(dst, Size::Long); - self.write_effective(src, dst_val, Size::Long); - self.write_effective(dst, src_val, Size::Long); + let src_val = self.read_effective(src, Size::Long)?; + let dst_val = self.read_effective(dst, Size::Long)?; + self.write_effective(src, dst_val, Size::Long)?; + self.write_effective(dst, src_val, Size::Long)?; } Instruction::And { size, src, dst } => { - let src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + let src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let res = dst_val & src_val; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let zero = res == 0; let neg = match size { Size::Byte => (res & 0x80) > 0, @@ -688,20 +734,20 @@ impl M68K { let new_flags = (old_flags & 0x10) | u16::from(neg) << 3 | u16::from(zero) << 2; self.sr = (self.sr & 0xFFE0) | new_flags; } - Instruction::Add { size, src, dst } => self.add(dst, src, size, ArithType::Reg), - Instruction::Addx { src, dst, size } => self.add(dst, src, size, ArithType::Ext), + Instruction::Add { size, src, dst } => self.add(dst, src, size, ArithType::Reg)?, + Instruction::Addx { src, dst, size } => self.add(dst, src, size, ArithType::Ext)?, Instruction::Adda(dst_areg, size, src) => self.add( EffectiveAddress::AddressReg(dst_areg), src, size, ArithType::Addr, - ), + )?, 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 { crate::instruction::Rotation::Immediate(rot) => rot, crate::instruction::Rotation::Register(dreg) => { - self.read_effective(EffectiveAddress::DataReg(dreg), Size::Byte) as u8 + self.read_effective(EffectiveAddress::DataReg(dreg), Size::Byte)? as u8 } }; let (carry, res): (bool, u32) = match (typ, dir) { @@ -774,14 +820,15 @@ impl M68K { Size::Word => (res & 0x8000) > 0, Size::Long => (res & 0x8000_0000) > 0, }; - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; let flags = u8::from(carry) << 4 | u8::from(neg) << 3 | u8::from(zero) << 2 | u8::from(carry); self.sr = self.sr & 0xFFE0 | u16::from(flags); } - } + }; + Ok(()) } fn add( @@ -790,13 +837,13 @@ impl M68K { src: EffectiveAddress, mut size: Size, typ: ArithType, - ) { + ) -> Result<(), DetailedBusError> { let ext = match typ { ArithType::Ext => (self.sr & 0x0010) > 0, _ => false, }; - let mut src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + let mut src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let res; let carry; let ovf; @@ -834,7 +881,7 @@ impl M68K { neg = res & 0x8000_0000 > 0; } } - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; match typ { ArithType::Reg => { let flags = u8::from(carry) << 4 @@ -857,6 +904,7 @@ impl M68K { self.sr = self.sr & 0xFFE0 | u16::from(flags); } } + Ok(()) } fn sub( @@ -865,13 +913,13 @@ impl M68K { src: EffectiveAddress, mut size: Size, typ: ArithType, - ) { + ) -> Result<(), DetailedBusError> { let ext = match typ { ArithType::Ext => (self.sr & 0x0010) > 0, _ => false, }; - let mut src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + let mut src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let res; let borrow; let ovf; @@ -909,7 +957,7 @@ impl M68K { neg = res & 0x8000_0000 > 0; } } - self.write_effective(dst, res, size); + self.write_effective(dst, res, size)?; match typ { ArithType::Reg => { let flags = u8::from(borrow) << 4 @@ -932,11 +980,17 @@ impl M68K { self.sr = (self.sr & 0xFFE0) | u16::from(flags); } } + Ok(()) } - fn cmp(&mut self, dst: EffectiveAddress, src: EffectiveAddress, size: Size) { - let src_val = self.read_effective(src, size); - let dst_val = self.read_effective(dst, size); + fn cmp( + &mut self, + dst: EffectiveAddress, + src: EffectiveAddress, + size: Size, + ) -> Result<(), DetailedBusError> { + let src_val = self.read_effective(src, size)?; + let dst_val = self.read_effective(dst, size)?; let res; let borrow; let ovf; @@ -976,48 +1030,54 @@ impl M68K { | u8::from(ovf) << 1 | u8::from(borrow); self.sr = (self.sr & 0xFFF0) | u16::from(flags); + Ok(()) } - fn read_effective(&mut self, effective_address: EffectiveAddress, size: Size) -> u32 { + fn read_effective( + &mut self, + effective_address: EffectiveAddress, + size: Size, + ) -> Result { match effective_address { - EffectiveAddress::Immediate(x) => x, - EffectiveAddress::DataReg(x) => Self::trim_excess(self.dregs[x as usize], size), + EffectiveAddress::Immediate(x) => Ok(x), + EffectiveAddress::DataReg(x) => Ok(Self::trim_excess(self.dregs[x as usize], size)), EffectiveAddress::AddressReg(x) => { assert!(size != Size::Byte); if x == 7 { if self.is_supervisor() { - Self::trim_excess(self.ssp, size) + Ok(Self::trim_excess(self.ssp, size)) } else { - Self::trim_excess(self.usp, size) + Ok(Self::trim_excess(self.usp, size)) } } else { - Self::trim_excess(self.aregs[x as usize], size) + Ok(Self::trim_excess(self.aregs[x as usize], size)) } } EffectiveAddress::Address(x) => { - let address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long); + let address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?; self.read_address(address, size) } EffectiveAddress::AddressPostinc(x) => { - let mut address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long); + let mut address = + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?; let val = self.read_address(address, 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 } EffectiveAddress::AddressPredec(x) => { let address = self - .read_effective(EffectiveAddress::AddressReg(x), Size::Long) + .read_effective(EffectiveAddress::AddressReg(x), Size::Long)? .wrapping_sub(u32::from(size.byte_size())); - self.write_effective(EffectiveAddress::AddressReg(x), address, Size::Long); + self.write_effective(EffectiveAddress::AddressReg(x), address, Size::Long)?; self.read_address(address, size) } EffectiveAddress::AddressDisplacement(x, d) => { let address = if d > 0 { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)? .wrapping_add((d as u16).into()) } else { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)? .wrapping_sub((-d as u16).into()) }; self.read_address(address, size) @@ -1029,9 +1089,9 @@ impl M68K { idx_size, } => { let address = self - .read_effective(EffectiveAddress::AddressReg(reg), Size::Long) + .read_effective(EffectiveAddress::AddressReg(reg), Size::Long)? .wrapping_add(displacement.into()) - .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) } EffectiveAddress::PcDisplacement(pc, d) => { @@ -1041,7 +1101,7 @@ impl M68K { EffectiveAddress::PcIndex(pc, displacement, idx, idx_size) => { let address = pc .wrapping_add(displacement.into()) - .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) } EffectiveAddress::AbsoluteShort(x) => self.read_address(x as u32, size), @@ -1049,7 +1109,12 @@ impl M68K { } } - fn write_effective(&mut self, effective_address: EffectiveAddress, data: u32, size: Size) { + fn write_effective( + &mut self, + effective_address: EffectiveAddress, + data: u32, + size: Size, + ) -> Result<(), DetailedBusError> { match effective_address { EffectiveAddress::DataReg(x) => { self.dregs[x as usize] = Self::set_with_size(self.dregs[x as usize], data, size); @@ -1071,38 +1136,40 @@ impl M68K { } } EffectiveAddress::Address(x) => { - let address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long); - self.write_address(address, data, size); + let address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?; + self.write_address(address, data, size)?; } EffectiveAddress::AddressPostinc(x) => { - let mut address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long); - self.write_address(address, data, size); + let mut address = + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?; + self.write_address(address, data, size)?; if x == 7 && size == Size::Byte { address = address.wrapping_add(2); } else { 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)?; } EffectiveAddress::AddressPredec(x) => { - let mut address = self.read_effective(EffectiveAddress::AddressReg(x), Size::Long); + let mut address = + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?; if x == 7 && size == Size::Byte { address = address.wrapping_sub(2); } else { address = address.wrapping_sub(u32::from(size.byte_size())); } - self.write_effective(EffectiveAddress::AddressReg(x), address, Size::Long); - self.write_address(address, data, size); + self.write_effective(EffectiveAddress::AddressReg(x), address, Size::Long)?; + self.write_address(address, data, size)?; } EffectiveAddress::AddressDisplacement(x, d) => { let address = if d > 0 { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)? .wrapping_add((d as u16).into()) } else { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) + self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)? .wrapping_sub((-d as u16).into()) }; - self.write_address(address, data, size); + self.write_address(address, data, size)?; } EffectiveAddress::AddressIndex { reg, @@ -1111,70 +1178,86 @@ impl M68K { idx_size, } => { let address = self - .read_effective(EffectiveAddress::AddressReg(reg), Size::Long) + .read_effective(EffectiveAddress::AddressReg(reg), Size::Long)? .wrapping_add(displacement.into()) - .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)); - self.write_address(address, data, size); + .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::AbsoluteLong(x) => self.write_address(x, data, size), + EffectiveAddress::AbsoluteShort(x) => self.write_address(x as u32, data, size)?, + EffectiveAddress::AbsoluteLong(x) => self.write_address(x, data, size)?, EffectiveAddress::PcDisplacement(..) | EffectiveAddress::PcIndex(..) | EffectiveAddress::Immediate(_) => panic!(), }; + Ok(()) } - fn read_address(&mut self, address: u32, size: Size) -> u32 { + fn read_address(&mut self, address: u32, size: Size) -> Result { // println!("READ {:x}, {:?}", address, size); match size { - Size::Byte => u32::from(self.read_byte(address)), - Size::Word => u32::from(self.read_word(address)), + Size::Byte => Ok(u32::from(self.read_byte(address)?)), + Size::Word => Ok(u32::from(self.read_word(address)?)), Size::Long => { - u32::from(self.read_word(address)) << 16 | u32::from(self.read_word(address + 2)) + Ok(u32::from(self.read_word(address)?) << 16 + | u32::from(self.read_word(address + 2)?)) } } } - fn write_address(&mut self, address: u32, data: u32, size: Size) { + fn write_address( + &mut self, + address: u32, + data: u32, + size: Size, + ) -> Result<(), DetailedBusError> { // println!("WRITE {:x}, {:?}, data {:x}", address, size, data); match size { - Size::Byte => self.write_byte(address, data as u8), - Size::Word => self.write_word(address, data as u16), + Size::Byte => self.write_byte(address, data as u8)?, + Size::Word => self.write_word(address, data as u16)?, Size::Long => { - self.write_word(address, (data >> 16) as u16); - self.write_word(address + 2, data as u16); + self.write_word(address, (data >> 16) as u16)?; + self.write_word(address + 2, data as u16)?; } } + Ok(()) } - fn read_byte(&mut self, address: u32) -> u8 { - self.bus - .read_byte(address) - .unwrap_or_else(|_| panic!("Could not read byte from 0x{:0>8x}", address)) + fn read_byte(&mut self, address: u32) -> Result { + self.bus.read_byte(address).map_err(|_| DetailedBusError { + address, + cause: BusErrorCause::ReadingByte, + }) } - fn write_byte(&mut self, address: u32, data: u8) { + fn write_byte(&mut self, address: u32, data: u8) -> Result<(), DetailedBusError> { self.bus .write_byte(address, data) - .unwrap_or_else(|_| panic!("Could not write byte to 0x{:0>8x}", address)); + .map_err(|_| DetailedBusError { + address, + cause: BusErrorCause::WritingByte, + }) } - fn read_word(&mut self, address: u32) -> u16 { + fn read_word(&mut self, address: u32) -> Result { if address & 0x1 != 0 { - self.trap(3); + self.trap(3)?; } - self.bus - .read_word(address) - .unwrap_or_else(|_| panic!("Could not read word from 0x{:0>8x}", address)) + self.bus.read_word(address).map_err(|_| DetailedBusError { + address, + cause: BusErrorCause::ReadingWord, + }) } - fn write_word(&mut self, address: u32, data: u16) { + fn write_word(&mut self, address: u32, data: u16) -> Result<(), DetailedBusError> { if address & 0x1 != 0 { - self.trap(3); + self.trap(3)?; } self.bus .write_word(address, data) - .unwrap_or_else(|_| panic!("Could not write word to 0x{:0>8x}", address)); + .map_err(|_| DetailedBusError { + address, + cause: BusErrorCause::WritingWord, + }) } fn trim_excess(num: u32, size: Size) -> u32 { @@ -1193,23 +1276,25 @@ impl M68K { } } - fn effective_address(&mut self, ea: EffectiveAddress) -> u32 { + fn effective_address(&mut self, ea: EffectiveAddress) -> Result { match ea { EffectiveAddress::Address(x) => { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) + Ok(self.read_effective(EffectiveAddress::AddressReg(x), Size::Long)?) } EffectiveAddress::AddressDisplacement(x, d) => { if d > 0 { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) - .wrapping_add((d as u16).into()) + Ok(self + .read_effective(EffectiveAddress::AddressReg(x), Size::Long)? + .wrapping_add((d as u16).into())) } else { - self.read_effective(EffectiveAddress::AddressReg(x), Size::Long) - .wrapping_sub((-d as u16).into()) + Ok(self + .read_effective(EffectiveAddress::AddressReg(x), Size::Long)? + .wrapping_sub((-d as u16).into())) } } - EffectiveAddress::PcDisplacement(pc, d) => pc.wrapping_add(d.into()), - EffectiveAddress::AbsoluteShort(x) => x as u32, - EffectiveAddress::AbsoluteLong(x) => x, + EffectiveAddress::PcDisplacement(pc, d) => Ok(pc.wrapping_add(d.into())), + EffectiveAddress::AbsoluteShort(x) => Ok(x as u32), + EffectiveAddress::AbsoluteLong(x) => Ok(x), EffectiveAddress::DataReg(_) | EffectiveAddress::AddressReg(_) | EffectiveAddress::AddressPredec(_) @@ -1220,21 +1305,21 @@ impl M68K { displacement, idx, idx_size, - } => self - .read_effective(EffectiveAddress::AddressReg(reg), Size::Long) + } => Ok(self + .read_effective(EffectiveAddress::AddressReg(reg), Size::Long)? .wrapping_add(displacement.into()) - .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)), - EffectiveAddress::PcIndex(pc, displacement, idx, idx_size) => pc + .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)?)), + EffectiveAddress::PcIndex(pc, displacement, idx, idx_size) => Ok(pc .wrapping_add(displacement.into()) - .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)), + .wrapping_add(self.read_effective(EffectiveAddress::from(idx), idx_size)?)), } } - fn push(&mut self, data: u32, size: Size) { - self.write_effective(EffectiveAddress::AddressPredec(7), data, size); + fn push(&mut self, data: u32, size: Size) -> Result<(), DetailedBusError> { + self.write_effective(EffectiveAddress::AddressPredec(7), data, size) } - fn pop(&mut self, size: Size) -> u32 { + fn pop(&mut self, size: Size) -> Result { self.read_effective(EffectiveAddress::AddressPostinc(7), size) } @@ -1242,13 +1327,14 @@ impl M68K { (self.sr & 0x2000) > 0 } - fn trap(&mut self, vector: u8) { - let new_pc = self.read_address(u32::from(vector) * 4, Size::Long); - self.push(u32::from(vector), Size::Word); - self.push(self.pc, Size::Long); - self.push(u32::from(self.sr), Size::Word); + fn trap(&mut self, vector: u8) -> Result<(), DetailedBusError> { + let new_pc = self.read_address(u32::from(vector) * 4, Size::Long)?; + self.push(u32::from(vector), Size::Word)?; + self.push(self.pc, Size::Long)?; + self.push(u32::from(self.sr), Size::Word)?; self.sr |= 0x2000; self.pc = new_pc; + Ok(()) } #[allow(dead_code)] diff --git a/src/main.rs b/src/main.rs index ef3f535..d306bf2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ mod term; use crate::{ backplane::Backplane, location::Location, - m68k::{BusError, M68K}, + m68k::{DetailedBusError, M68K}, }; use anyhow::anyhow; use clap::Parser; @@ -79,7 +79,13 @@ fn main() -> Result<(), anyhow::Error> { if args.run { let mut out = String::new(); while !state.cpu.stopped { - state.cpu.step(); + match state.cpu.step() { + Ok(()) => (), + Err(e) => { + println!("{}", e); + state.cpu.stopped = true; + } + } } out += &format!("{}\n", state.cpu); let pc = state.cpu.pc(); @@ -458,7 +464,7 @@ fn disas_fmt( cpu: &mut M68K, addr: u32, symbol_tables: &SymbolTables, -) -> (String, Result>) { +) -> (String, Result>) { let addr_fmt = if let Some((table, symbol, offset)) = symbol_tables.address_to_symbol(addr) { format!("{}:{} + {} (0x{:x})", table, symbol, offset, addr) } else {