Fixed some decoder bugs in m68k

This commit is contained in:
transistor 2021-12-14 16:06:34 -08:00
parent 148b4dcf2c
commit 1b6cbfa831
6 changed files with 112 additions and 40 deletions

View File

@ -74,7 +74,7 @@ impl M68kDecoder {
OPCG_BIT_OPS => {
let optype = (ins & 0x0F00) >> 8;
if (ins & 0x3F) == 0b111100 {
if (ins & 0x13F) == 0x03C {
match (ins & 0x00C0) >> 6 {
0b00 => {
let data = self.read_instruction_word(memory)?;
@ -171,11 +171,15 @@ impl M68kDecoder {
let ins_0f00 = ins & 0xF00;
let ins_00f0 = ins & 0x0F0;
if (ins & 0x180) == 0x180 && (ins & 0x038) != 0 {
if (ins & 0x180) == 0x180 {
if (ins & 0x040) == 0 {
let size = match get_size(ins) {
Some(Size::Word) => Size::Word,
Some(Size::Long) if self.cputype >= M68kType::MC68020 => Size::Long,
// TODO 2021-12-14: the docs for the 68000 show the size field, even though it says it only operates on words
// and according to some other sources, it seems they are parsed and executed on the 68000, so
// I'm removing the check that only allows this on the MC68020
//Some(Size::Long) if self.cputype >= M68kType::MC68020 => Size::Long,
Some(Size::Long) => Size::Long,
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
};
@ -698,11 +702,11 @@ impl M68kDecoder {
match reg {
0b000 => {
let value = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word) as u32;
Target::IndirectMemory(value)
Target::IndirectMemory(value, Size::Word)
},
0b001 => {
let value = self.read_instruction_long(memory)?;
Target::IndirectMemory(value)
Target::IndirectMemory(value, Size::Long)
},
0b010 => {
let displacement = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
@ -754,7 +758,7 @@ impl M68kDecoder {
(0..((self.end - self.start) / 2)).map(|offset|
Ok(format!("{:04x} ", memory.read_beu16((self.start + (offset * 2)) as Address).unwrap()))
).collect();
println!("{:#010x}: {}\n\t{:?}\n", self.start, ins_data.unwrap(), self.instruction);
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
}
}
@ -807,7 +811,6 @@ fn get_condition(ins: u16) -> Condition {
0b1101 => Condition::LessThan,
0b1110 => Condition::GreaterThan,
0b1111 => Condition::LessThanOrEqual,
_ => Condition::True,
}
}

View File

@ -29,7 +29,7 @@ use super::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority}
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
self.step_internal(system)?;
Ok((1_000_000_000 / self.frequency as u64) * 4)
Ok((1_000_000_000 / self.frequency as u64) * 4 as ClockElapsed)
}
fn on_error(&mut self, system: &System) {
@ -756,11 +756,11 @@ impl M68k {
let addr = self.get_a_reg_mut(reg);
*addr = new_value;
},
Instruction::UnimplementedA(ins) => {
Instruction::UnimplementedA(_) => {
self.state.pc -= 2;
self.exception(Exceptions::LineAEmulator as u8, false)?;
},
Instruction::UnimplementedF(ins) => {
Instruction::UnimplementedF(_) => {
self.state.pc -= 2;
self.exception(Exceptions::LineFEmulator as u8, false)?;
},
@ -771,8 +771,8 @@ impl M68k {
Ok(())
}
fn execute_movem(&mut self, target: Target, size: Size, dir: Direction, mut mask: u16) -> Result<(), Error> {
let mut addr = self.get_target_address(target)?;
fn execute_movem(&mut self, target: Target, size: Size, dir: Direction, mask: u16) -> Result<(), Error> {
let addr = self.get_target_address(target)?;
// If we're using a MC68020 or higher, and it was Post-Inc/Pre-Dec target, then update the value before it's stored
if self.cputype >= M68kType::MC68020 {
@ -786,13 +786,13 @@ impl M68k {
}
let post_addr = match target {
Target::IndirectARegInc(reg) => {
Target::IndirectARegInc(_) => {
if dir != Direction::FromTarget {
return Err(Error::new(&format!("Cannot use {:?} with {:?}", target, dir)));
}
self.move_memory_to_registers(addr, size, mask)?
},
Target::IndirectARegDec(reg) => {
Target::IndirectARegDec(_) => {
if dir != Direction::ToTarget {
return Err(Error::new(&format!("Cannot use {:?} with {:?}", target, dir)));
}
@ -937,7 +937,7 @@ impl M68k {
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size)
},
Target::IndirectMemory(addr) => {
Target::IndirectMemory(addr, _) => {
self.get_address_sized(addr as Address, size)
},
}
@ -984,7 +984,7 @@ impl M68k {
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size)?;
},
Target::IndirectMemory(addr) => {
Target::IndirectMemory(addr, _) => {
self.set_address_sized(addr as Address, value, size)?;
},
_ => return Err(Error::new(&format!("Unimplemented addressing target: {:?}", target))),
@ -1012,7 +1012,7 @@ impl M68k {
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32)
},
Target::IndirectMemory(addr) => {
Target::IndirectMemory(addr, _) => {
addr
},
_ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))),

View File

@ -91,7 +91,7 @@ pub enum Target {
IndirectRegOffset(BaseRegister, Option<IndexRegister>, i32),
IndirectMemoryPreindexed(BaseRegister, Option<IndexRegister>, i32, i32),
IndirectMemoryPostindexed(BaseRegister, Option<IndexRegister>, i32, i32),
IndirectMemory(u32),
IndirectMemory(u32, Size),
}
#[derive(Clone, Debug, PartialEq)]
@ -285,6 +285,15 @@ impl fmt::Display for ControlRegister {
}
}
impl fmt::Display for RegOrImmediate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RegOrImmediate::DReg(reg) => write!(f, "%d{}", reg),
RegOrImmediate::Immediate(value) => write!(f, "#{:#02x}", value),
}
}
}
impl fmt::Display for XRegister {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@ -339,13 +348,50 @@ impl fmt::Display for Target {
let index_str = fmt_index_disp(index_reg);
write!(f, "([{}#{:08x}]{} + #{:08x})", base_reg, base_disp, index_str, outer_disp)
},
Target::IndirectMemory(value) => write!(f, "(#{:08x})", value),
Target::IndirectMemory(value, size) => if *size == Size::Word {
write!(f, "(#{:04x})", value)
} else {
write!(f, "(#{:08x})", value)
},
}
}
}
fn fmt_movem_mask(mask: u16) -> String {
format!("something")
fn fmt_movem_mask(mut mask: u16, target: &Target) -> String {
let mut output = vec![];
match target {
Target::IndirectARegDec(_) => {
for i in (0..8).rev() {
if (mask & 0x01) != 0 {
output.push(format!("%a{}", i));
}
mask >>= 1;
}
for i in (0..8).rev() {
if (mask & 0x01) != 0 {
output.push(format!("%d{}", i));
}
mask >>= 1;
}
},
_ => {
for i in 0..8 {
if (mask & 0x01) != 0 {
output.push(format!("%d{}", i));
}
mask >>= 1;
}
for i in 0..8 {
if (mask & 0x01) != 0 {
output.push(format!("%a{}", i));
}
mask >>= 1;
}
},
}
output.join("/")
}
impl fmt::Display for Instruction {
@ -353,6 +399,8 @@ impl fmt::Display for Instruction {
match self {
Instruction::ABCD(src, dest) => write!(f, "abcd\t{}, {}", src, dest),
Instruction::ADD(src, dest, size) => write!(f, "add{}\t{}, {}", size, src, dest),
Instruction::ADDA(target, reg, size) => write!(f, "adda{}\t{}, %a{}", size, target, reg),
Instruction::ADDX(src, dest, size) => write!(f, "addx{}\t{}, {}", size, src, dest),
Instruction::AND(src, dest, size) => write!(f, "and{}\t{}, {}", size, src, dest),
Instruction::ANDtoCCR(value) => write!(f, "andb\t{:02x}, %ccr", value),
Instruction::ANDtoSR(value) => write!(f, "andw\t{:04x}, %sr", value),
@ -365,7 +413,15 @@ impl fmt::Display for Instruction {
Instruction::BCLR(src, dest, size) => write!(f, "bclr{}\t{}, {}", size, src, dest),
Instruction::BSET(src, dest, size) => write!(f, "bset{}\t{}, {}", size, src, dest),
Instruction::BTST(src, dest, size) => write!(f, "btst{}\t{}, {}", size, src, dest),
//Instruction::BKPT(value),
Instruction::BFCHG(target, offset, width) => write!(f, "bfchg\t{}, {}, {}", target, offset, width),
Instruction::BFCLR(target, offset, width) => write!(f, "bfclr\t{}, {}, {}", target, offset, width),
Instruction::BFEXTS(target, offset, width, reg) => write!(f, "bfexts\t{}, {}, {}, %d{}", target, offset, width, reg),
Instruction::BFEXTU(target, offset, width, reg) => write!(f, "bfextu\t{}, {}, {}, %d{}", target, offset, width, reg),
Instruction::BFFFO(target, offset, width, reg) => write!(f, "bfffo\t{}, {}, {}, %d{}", target, offset, width, reg),
Instruction::BFINS(reg, target, offset, width) => write!(f, "bfins\t%d{}, {}, {}, {}", reg, target, offset, width),
Instruction::BFSET(target, offset, width) => write!(f, "bfset\t{}, {}, {}", target, offset, width),
Instruction::BFTST(target, offset, width) => write!(f, "bftst\t{}, {}, {}", target, offset, width),
Instruction::BKPT(value) => write!(f, "bkpt\t{}", value),
Instruction::CHK(target, reg, size) => write!(f, "chk{}\t{}, %d{}", size, target, reg),
Instruction::CLR(target, size) => write!(f, "clr{}\t{}", size, target),
@ -405,8 +461,8 @@ impl fmt::Display for Instruction {
Direction::FromTarget => write!(f, "movec\t{}, {}", target, reg),
},
Instruction::MOVEM(target, size, dir, mask) => match dir {
Direction::ToTarget => write!(f, "movem{}\t{}, {}", size, fmt_movem_mask(*mask), target),
Direction::FromTarget => write!(f, "movem{}\t{}, {}", size, target, fmt_movem_mask(*mask)),
Direction::ToTarget => write!(f, "movem{}\t{}, {}", size, fmt_movem_mask(*mask, target), target),
Direction::FromTarget => write!(f, "movem{}\t{}, {}", size, target, fmt_movem_mask(*mask, target)),
},
Instruction::MOVEP(dreg, areg, offset, size, dir) => match dir {
Direction::ToTarget => write!(f, "movep{}\t%d{}, ({}, %a{})", size, dreg, areg, offset),
@ -448,6 +504,8 @@ impl fmt::Display for Instruction {
Instruction::Scc(cond, target) => write!(f, "s{}\t{}", cond, target),
Instruction::STOP(value) => write!(f, "stop\t#{:04x}", value),
Instruction::SUB(src, dest, size) => write!(f, "sub{}\t{}, {}", size, src, dest),
Instruction::SUBA(target, reg, size) => write!(f, "suba{}\t{}, %a{}", size, target, reg),
Instruction::SUBX(src, dest, size) => write!(f, "subx{}\t{}, {}", size, src, dest),
Instruction::SWAP(reg) => write!(f, "swap\t%d{}", reg),
Instruction::TAS(target) => write!(f, "tas\t{}", target),
@ -456,7 +514,8 @@ impl fmt::Display for Instruction {
Instruction::TRAPV => write!(f, "trapv"),
Instruction::UNLK(reg) => write!(f, "unlk\t%a{}", reg),
_ => write!(f, "UNIMPL"),
Instruction::UnimplementedA(ins) => write!(f, "coproc_a\t{:#06x}", ins),
Instruction::UnimplementedF(ins) => write!(f, "coproc_f\t{:#06x}", ins),
}
}
}

View File

@ -1,7 +1,7 @@
use crate::error::Error;
use crate::system::System;
use crate::devices::{Address, Addressable, Debuggable};
use crate::devices::{Address, Debuggable};
use super::state::Z80;
use super::decode::Z80Decoder;

View File

@ -217,6 +217,10 @@ impl BusPort {
pub fn dump_memory(&mut self, addr: Address, count: Address) {
self.subdevice.borrow_mut().dump_memory(self.offset + (addr & self.address_mask), count)
}
pub fn data_width(&self) -> u8 {
self.data_width
}
}
impl Addressable for BusPort {

View File

@ -1,4 +1,25 @@
* when a MOVE's targets are both ARegDec, the 2 extra clocks can be combined (-2 clocks in this one case)
* should you rename devices.rs traits.rs?
* add command line arguments to speed up or slow down either the frame rate limiter or the simulated time per frame
* can you make the connections between things (like memory adapters), be expressed in a way that's more similar to the electrical design?
like specifying that address pins 10-7 should be ignored/unconnected, pin 11 will connect to "chip select", etc
* should you add a unique ID to devices, such that they can be indexed, and their step functions can reset the next_run count and run them immediately
* should you simulate bus arbitration?
* interrupts could be done in a better way
* need a better way of handling disparate reads/writes to I/O spaces, rather than having multiple devices or having a massive chunk of address space allocated, continuously
* should you modify Addressable to also take the absolute address as input? I'm thinking of how the same device could be mapped to multiple addresses in memory instead
of taking up a whole range of addresses
* you could modify read()/write() in Addressable to return the number of bytes read or written for dynamic bus sizing used by the MC68020+
Audio:
* for the mixer, it might be easier to have a buffer for each source, but then you'd need to have a list of all sources, even though
each source has a copy of the mixer as well... Likely there'd be a sub object in Source which is the buffer and anything else needed
by the mixer
@ -16,21 +37,6 @@
a callback with the frontend sound system that is called when it needs data, or you write to a shared buffer which is passed back to the
frontend when it needs it, or it has a copy it can use directly
* should you rename devices.rs traits.rs?
* add command line arguments to speed up or slow down either the frame rate limiter or the simulated time per frame
* can you make the connections between things (like memory adapters), be expressed in a way that's more similar to the electrical design?
like specifying that address pins 10-7 should be ignored/unconnected, pin 11 will connect to "chip select", etc
* should you add a unique ID to devices, such that they can be indexed, and their step functions can reset the next_run count and run them immediately
* should you simulate bus arbitration?
* interrupts could be done in a better way
* need a better way of handling disparate reads/writes to I/O spaces, rather than having multiple devices or having a massive chunk of address space allocated, continuously
* should you modify Addressable to also take the absolute address as input? I'm thinking of how the same device could be mapped to multiple addresses in memory instead
of taking up a whole range of addresses
* you could modify read()/write() in Addressable to return the number of bytes read or written for dynamic bus sizing used by the MC68020+
Debugger: