Added MC68020+ addressing modes

This commit is contained in:
transistor 2021-10-18 15:44:42 -07:00
parent 3fc76335d0
commit 731c89845e
4 changed files with 182 additions and 77 deletions

View File

@ -10,6 +10,8 @@ use super::instructions::{
Direction,
ShiftDirection,
XRegister,
BaseRegister,
IndexRegister,
RegOrImmediate,
ControlRegister,
Condition,
@ -108,7 +110,7 @@ impl M68kDecoder {
let dir = if (ins & 0x0800) == 0 { Direction::FromTarget } else { Direction::ToTarget };
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
let offset = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Ok(Instruction::MOVEP(dreg, Target::IndirectARegOffset(areg, offset), size, dir))
Ok(Instruction::MOVEP(dreg, Target::IndirectRegOffset(BaseRegister::AReg(areg), None, offset), size, dir))
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
let bitnum = if (ins & 0x0100) == 0x0100 {
Target::DirectDReg(get_high_reg(ins))
@ -606,25 +608,53 @@ impl M68kDecoder {
self.get_mode_as_target(memory, mode, reg, size)
}
fn get_extension_displacement(&mut self, memory: &mut dyn Addressable, select: u16) -> Result<i32, Error> {
let result = match select {
0b00 | 0b01 => 0,
0b10 => sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word),
0b11 => self.read_instruction_long(memory)? as i32,
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
};
Ok(result)
}
fn decode_extension_word(&mut self, memory: &mut dyn Addressable, areg: Option<u8>) -> Result<Target, Error> {
let brief_extension = self.read_instruction_word(memory)?;
let use_full = (brief_extension & 0x0100) != 0;
// Decode Index Register
let xreg_num = ((brief_extension & 0x7000) >> 12) as u8;
let xreg = if (brief_extension & 0x8000) == 0 { XRegister::Data(xreg_num) } else { XRegister::Address(xreg_num) };
let xreg = if (brief_extension & 0x8000) == 0 { XRegister::DReg(xreg_num) } else { XRegister::AReg(xreg_num) };
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
let scale = ((brief_extension & 0x0600) >> 9) as u8;
let use_full = (brief_extension & 0x0100) != 0;
let index_reg = IndexRegister { xreg, scale, size };
if !use_full {
let displacement = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte);
match areg {
Some(areg) => Ok(Target::IndirectARegXRegOffset(areg, xreg, displacement, scale, size)),
None => Ok(Target::IndirectPCXRegOffset(xreg, displacement, scale, size)),
Some(areg) => Ok(Target::IndirectRegOffset(BaseRegister::AReg(areg), Some(index_reg), displacement)),
None => Ok(Target::IndirectRegOffset(BaseRegister::PC, Some(index_reg), displacement)),
}
} else if self.cputype >= M68kType::MC68020 {
let use_base = (brief_extension & 0x0080) == 0;
let use_base_reg = (brief_extension & 0x0080) == 0;
let use_index = (brief_extension & 0x0040) == 0;
let use_sub_indirect = (brief_extension & 0x0007) != 0;
let pre_not_post = (brief_extension & 0x0004) == 0;
panic!("Not Implemented");
let opt_base_reg = match (use_base_reg, areg) {
(false, _) => BaseRegister::None,
(true, None) => BaseRegister::PC,
(true, Some(areg)) => BaseRegister::AReg(areg),
};
let opt_index_reg = if use_index { Some(index_reg) } else { None };
let base_disp = self.get_extension_displacement(memory, (brief_extension & 0x0030) >> 4)?;
let outer_disp = self.get_extension_displacement(memory, brief_extension & 0x0003)?;
match (use_sub_indirect, pre_not_post) {
(false, _) => Ok(Target::IndirectRegOffset(opt_base_reg, opt_index_reg, base_disp)),
(true, true) => Ok(Target::IndirectMemoryPreindexed(opt_base_reg, opt_index_reg, base_disp, outer_disp)),
(true, false) => Ok(Target::IndirectMemoryPostindexed(opt_base_reg, opt_index_reg, base_disp, outer_disp)),
}
} else {
Err(Error::processor(Exceptions::IllegalInstruction as u32))
}
@ -638,8 +668,8 @@ impl M68kDecoder {
0b011 => Target::IndirectARegInc(reg),
0b100 => Target::IndirectARegDec(reg),
0b101 => {
let data = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Target::IndirectARegOffset(reg, data)
let displacement = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Target::IndirectRegOffset(BaseRegister::AReg(reg), None, displacement)
},
0b110 => {
self.decode_extension_word(memory, Some(reg))?
@ -655,8 +685,8 @@ impl M68kDecoder {
Target::IndirectMemory(value)
},
0b010 => {
let data = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Target::IndirectPCOffset(data)
let displacement = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Target::IndirectRegOffset(BaseRegister::PC, None, displacement)
},
0b011 => {
self.decode_extension_word(memory, None)?

View File

@ -10,6 +10,8 @@ use super::instructions::{
Direction,
ShiftDirection,
XRegister,
BaseRegister,
IndexRegister,
RegOrImmediate,
ControlRegister,
Condition,
@ -389,16 +391,16 @@ impl M68k {
//Instruction::ILLEGAL => {
//},
Instruction::JMP(target) => {
self.state.pc = self.get_target_address(target)?;
self.state.pc = self.get_target_address(system, target)?;
},
Instruction::JSR(target) => {
self.push_long(system, self.state.pc)?;
let sp = *self.get_stack_pointer_mut();
self.debugger.stack_tracer.push_return(sp);
self.state.pc = self.get_target_address(target)?;
self.state.pc = self.get_target_address(system, target)?;
},
Instruction::LEA(target, reg) => {
let value = self.get_target_address(target)?;
let value = self.get_target_address(system, target)?;
let addr = self.get_a_reg_mut(reg);
*addr = value;
},
@ -472,7 +474,7 @@ impl M68k {
// TODO moving words requires a sign extension to 32 bits
if size != Size::Long { return Err(Error::new("Unsupported size in MOVEM instruction")); }
let mut addr = self.get_target_address(target)?;
let mut addr = self.get_target_address(system, target)?;
if dir == Direction::ToTarget {
let mut mask = mask;
for i in (0..8).rev() {
@ -567,7 +569,7 @@ impl M68k {
self.state.sr = self.state.sr | value;
},
Instruction::PEA(target) => {
let value = self.get_target_address(target)?;
let value = self.get_target_address(system, target)?;
self.push_long(system, value)?;
},
//Instruction::RESET => {
@ -697,25 +699,29 @@ impl M68k {
*addr -= size.in_bytes();
get_address_sized(system, *addr as Address, size)
},
Target::IndirectARegOffset(reg, offset) => {
let addr = self.get_a_reg_mut(reg);
get_address_sized(system, (*addr).wrapping_add(offset as u32) as Address, size)
Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
get_address_sized(system, base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, size)
},
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, target_size) => {
let index = sign_extend_to_long(self.get_x_reg_value(xreg), target_size) << scale;
let addr = self.get_a_reg_mut(reg);
get_address_sized(system, (*addr).wrapping_add(offset as u32).wrapping_add(index as u32) as Address, size)
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
get_address_sized(system, intermediate.wrapping_add(outer_disp as u32) as Address, size)
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
get_address_sized(system, intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size)
},
Target::IndirectMemory(addr) => {
get_address_sized(system, addr as Address, size)
},
Target::IndirectPCOffset(offset) => {
get_address_sized(system, (self.decoder.start + 2).wrapping_add(offset as u32) as Address, size)
},
Target::IndirectPCXRegOffset(xreg, offset, scale, target_size) => {
let index = sign_extend_to_long(self.get_x_reg_value(xreg), target_size) << scale;
get_address_sized(system, (self.decoder.start + 2).wrapping_add(offset as u32).wrapping_add(index as u32) as Address, size)
},
_ => return Err(Error::new(&format!("Unimplemented addressing target: {:?}", target))),
}
}
@ -740,14 +746,22 @@ impl M68k {
*addr -= size.in_bytes();
set_address_sized(system, *addr as Address, value, size)?;
},
Target::IndirectARegOffset(reg, offset) => {
let addr = self.get_a_reg_mut(reg);
set_address_sized(system, (*addr).wrapping_add(offset as u32) as Address, value, size)?;
Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
set_address_sized(system, base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, value, size)?;
},
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, target_size) => {
let index = sign_extend_to_long(self.get_x_reg_value(xreg), target_size) << scale;
let addr = self.get_a_reg_mut(reg);
set_address_sized(system, (*addr).wrapping_add(offset as u32).wrapping_add(index as u32) as Address, value, size)?;
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
set_address_sized(system, intermediate.wrapping_add(outer_disp as u32) as Address, value, size);
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
set_address_sized(system, intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size);
},
Target::IndirectMemory(addr) => {
set_address_sized(system, addr as Address, value, size)?;
@ -757,28 +771,29 @@ impl M68k {
Ok(())
}
pub fn get_target_address(&mut self, target: Target) -> Result<u32, Error> {
pub fn get_target_address(&mut self, system: &System, target: Target) -> Result<u32, Error> {
let addr = match target {
Target::IndirectAReg(reg) | Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => *self.get_a_reg_mut(reg),
Target::IndirectARegOffset(reg, offset) => {
let addr = self.get_a_reg_mut(reg);
(*addr).wrapping_add(offset as u32)
Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32)
},
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, target_size) => {
let index = sign_extend_to_long(self.get_x_reg_value(xreg), target_size) << scale;
let addr = self.get_a_reg_mut(reg);
(*addr).wrapping_add(offset as u32).wrapping_add(index as u32)
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
intermediate.wrapping_add(outer_disp as u32)
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, 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) => {
addr
},
Target::IndirectPCOffset(offset) => {
(self.decoder.start + 2).wrapping_add(offset as u32)
},
Target::IndirectPCXRegOffset(xreg, offset, scale, target_size) => {
let index = sign_extend_to_long(self.get_x_reg_value(xreg), target_size) << scale;
(self.decoder.start + 2).wrapping_add(offset as u32).wrapping_add(index as u32)
},
_ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))),
};
Ok(addr)
@ -800,6 +815,31 @@ impl M68k {
}
}
fn get_x_reg_value(&self, xreg: XRegister) -> u32 {
match xreg {
XRegister::DReg(reg) => self.state.d_reg[reg as usize],
XRegister::AReg(reg) => self.state.a_reg[reg as usize],
}
}
fn get_base_reg_value(&self, base_reg: BaseRegister) -> u32 {
match base_reg {
BaseRegister::None => 0,
BaseRegister::PC => self.decoder.start + 2,
BaseRegister::AReg(reg) if reg == 7 => if self.is_supervisor() { self.state.msp } else { self.state.usp },
BaseRegister::AReg(reg) => self.state.a_reg[reg as usize],
}
}
fn get_index_reg_value(&self, index_reg: &Option<IndexRegister>) -> i32 {
match index_reg {
None => 0,
Some(IndexRegister { xreg, scale, size }) => {
sign_extend_to_long(self.get_x_reg_value(*xreg), *size) << scale
}
}
}
fn get_control_reg_mut(&mut self, control_reg: ControlRegister) -> &mut u32 {
match control_reg {
ControlRegister::VBR => &mut self.state.vbr,
@ -820,13 +860,6 @@ impl M68k {
}
}
fn get_x_reg_value(&self, xreg: XRegister) -> u32 {
match xreg {
XRegister::Data(reg) => self.state.d_reg[reg as usize],
XRegister::Address(reg) => self.state.a_reg[reg as usize],
}
}
#[inline(always)]
fn is_supervisor(&self) -> bool {
self.state.sr & (Flags:: Supervisor as u16) != 0

View File

@ -31,8 +31,22 @@ pub enum ShiftDirection {
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum XRegister {
Data(u8),
Address(u8),
DReg(u8),
AReg(u8),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BaseRegister {
None,
PC,
AReg(u8),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct IndexRegister {
pub xreg: XRegister,
pub scale: u8,
pub size: Size,
}
#[derive(Copy, Clone, Debug, PartialEq)]
@ -41,11 +55,11 @@ pub enum RegOrImmediate {
Immediate(u8),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ControlRegister {
VBR,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Condition {
True,
@ -74,11 +88,10 @@ pub enum Target {
IndirectAReg(Register),
IndirectARegInc(Register),
IndirectARegDec(Register),
IndirectARegOffset(Register, i32),
IndirectARegXRegOffset(Register, XRegister, i32, u8, Size),
IndirectRegOffset(BaseRegister, Option<IndexRegister>, i32),
IndirectMemoryPreindexed(BaseRegister, Option<IndexRegister>, i32, i32),
IndirectMemoryPostindexed(BaseRegister, Option<IndexRegister>, i32, i32),
IndirectMemory(u32),
IndirectPCOffset(i32),
IndirectPCXRegOffset(XRegister, i32, u8, Size),
}
#[derive(Clone, Debug, PartialEq)]
@ -267,12 +280,36 @@ impl fmt::Display for ControlRegister {
impl fmt::Display for XRegister {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
XRegister::Data(reg) => write!(f, "d{}", reg),
XRegister::Address(reg) => write!(f, "a{}", reg),
XRegister::DReg(reg) => write!(f, "d{}", reg),
XRegister::AReg(reg) => write!(f, "a{}", reg),
}
}
}
impl fmt::Display for BaseRegister {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BaseRegister::None => Ok(()),
BaseRegister::PC => write!(f, "%pc + "),
BaseRegister::AReg(reg) => write!(f, "%a{} + ", reg),
}
}
}
fn fmt_index_disp(index: &Option<IndexRegister>) -> String {
match index {
Some(index) => {
let mut result = format!("%{}", index.xreg);
if index.scale != 0 {
result += &format!("<< {}", index.scale);
}
result += " + ";
result
},
None => "".to_string(),
}
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@ -282,17 +319,19 @@ impl fmt::Display for Target {
Target::IndirectAReg(reg) => write!(f, "(%a{})", reg),
Target::IndirectARegInc(reg) => write!(f, "(%a{})+", reg),
Target::IndirectARegDec(reg) => write!(f, "-(%a{})", reg),
Target::IndirectARegOffset(reg, offset) => write!(f, "(%a{} + #{:04x})", reg, offset),
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, _) => {
let scale_str = if *scale != 0 { format!("<< {}", scale) } else { "".to_string() };
write!(f, "(%a{} + %{} + #{:04x}{})", reg, xreg, offset, scale_str)
Target::IndirectRegOffset(base_reg, index_reg, offset) => {
let index_str = fmt_index_disp(index_reg);
write!(f, "({}{}#{:04x})", base_reg, index_str, offset)
},
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let index_str = fmt_index_disp(index_reg);
write!(f, "([{}{}#{:08x}] + #{:08x})", base_reg, index_str, base_disp, outer_disp)
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
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::IndirectPCOffset(offset) => write!(f, "(%pc + #{:04x})", offset),
Target::IndirectPCXRegOffset(xreg, offset, scale, _) => {
let scale_str = if *scale != 0 { format!("<< {}", scale) } else { "".to_string() };
write!(f, "(%pc + %{} + #{:04x}{})", xreg, offset, scale_str)
},
}
}
}

View File

@ -1,4 +1,7 @@
* rearrange the order of Target::IndirectARegXReg...
* should you make a new type for the index, c/w proper Display formatter
* can you eventually make the system connections all configurable via a config file?
* test using mpsc to pass messages with the tty IO thread, and test if it's slower than what you have now