Fixed indexing, flags, and added logical shift

The effective modes that used signed offsets were not properly
sign extending the immediate or register index values before adding
them to the address, resulting in incorrect addresses.

The flags were incorrect for some instructions, and I added the
logical shift instruction implementation
This commit is contained in:
transistor 2021-10-01 15:38:21 -07:00
parent f7529bbb41
commit a5cac4d309
3 changed files with 78 additions and 43 deletions

View File

@ -552,7 +552,7 @@ impl MC68010 {
let reg = get_low_reg(ins);
let rotation = get_high_reg(ins);
let count = if (ins & 0x0020) == 0 {
Target::Immediate(rotation as u32)
Target::Immediate(if rotation != 0 { rotation as u32 } else { 8 })
} else {
Target::DirectDReg(rotation)
};
@ -595,8 +595,8 @@ impl MC68010 {
self.get_mode_as_target(space, mode, reg, size)
}
fn decode_brief_extension_word(&self, brief_extension: u16) -> (RegisterType, u8, u16, Size) {
let data = brief_extension & 0x00FF;
fn decode_brief_extension_word(&self, brief_extension: u16) -> (RegisterType, u8, i32, Size) {
let data = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte);
let xreg = ((brief_extension & 0x7000) >> 12) as u8;
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
@ -613,13 +613,13 @@ impl MC68010 {
0b011 => Target::IndirectARegInc(reg),
0b100 => Target::IndirectARegDec(reg),
0b101 => {
let data = self.read_instruction_word(space)?;
Target::IndirectARegOffset(reg, (data as i16) as i32)
let data = sign_extend_to_long(self.read_instruction_word(space)? as u32, Size::Word);
Target::IndirectARegOffset(reg, data)
},
0b110 => {
let brief_extension = self.read_instruction_word(space)?;
let (rtype, xreg, data, size) = self.decode_brief_extension_word(brief_extension);
Target::IndirectARegXRegOffset(reg, rtype, xreg, (data as i16) as i32, size)
Target::IndirectARegXRegOffset(reg, rtype, xreg, data, size)
},
0b111 => {
match reg {
@ -632,13 +632,13 @@ impl MC68010 {
Target::IndirectMemory(value)
},
0b010 => {
let data = self.read_instruction_word(space)?;
Target::IndirectPCOffset((data as i16) as i32)
let data = sign_extend_to_long(self.read_instruction_word(space)? as u32, Size::Word);
Target::IndirectPCOffset(data)
},
0b011 => {
let brief_extension = self.read_instruction_word(space)?;
let (rtype, xreg, data, size) = self.decode_brief_extension_word(brief_extension);
Target::IndirectPCXRegOffset(rtype, xreg, (data as i16) as i32, size)
Target::IndirectPCXRegOffset(rtype, xreg, data, size)
},
0b100 => {
let data = match size {
@ -731,3 +731,11 @@ impl Size {
}
}
pub fn sign_extend_to_long(value: u32, from: Size) -> i32 {
match from {
Size::Byte => ((value as u8) as i8) as i32,
Size::Word => ((value as u16) as i16) as i32,
Size::Long => value as i32,
}
}

View File

@ -2,7 +2,7 @@
use crate::error::Error;
use crate::memory::{Address, AddressSpace};
use super::decode::{Instruction, Target, Size, Direction, Condition, ControlRegister, RegisterType};
use super::decode::{Instruction, Target, Size, Direction, Condition, ShiftDirection, ControlRegister, RegisterType, sign_extend_to_long};
/*
pub trait Processor {
@ -18,6 +18,7 @@ pub const FLAGS_CARRY: u16 = 0x0001;
pub const FLAGS_OVERFLOW: u16 = 0x0002;
pub const FLAGS_ZERO: u16 = 0x0004;
pub const FLAGS_NEGATIVE: u16 = 0x0008;
pub const FLAGS_EXTEND: u16 = 0x0010;
pub const FLAGS_SUPERVISOR: u16 = 0x2000;
pub const ERR_BUS_ERROR: u32 = 2;
@ -200,7 +201,7 @@ impl MC68010 {
},
Size::Long => existing.overflowing_add(value),
};
self.set_compare_flags(result, overflow, size);
self.set_compare_flags(result, size, overflow);
self.set_target_value(space, dest, result, size)?;
},
Instruction::AND(src, dest, size) => {
@ -309,11 +310,21 @@ impl MC68010 {
},
//Instruction::LINK(u8, u16) => {
//},
//Instruction::LSd(Target, Target, Size, ShiftDirection) => {
//},
Instruction::LSd(count, target, size, shift_dir) => {
let count = self.get_target_value(space, count, size)? % 64;
let mut pair = (self.get_target_value(space, target, size)?, false);
for _ in 0..count {
pair = shift_operation(pair.0, size, shift_dir, false);
}
self.set_compare_flags(pair.0, size, false);
if pair.1 {
self.sr |= FLAGS_EXTEND | FLAGS_CARRY;
}
self.set_target_value(space, target, pair.0, size)?;
},
Instruction::MOVE(src, dest, size) => {
let value = self.get_target_value(space, src, size)?;
self.set_compare_flags(value, false, size);
self.set_compare_flags(value, size, false);
self.set_target_value(space, dest, value, size)?;
},
Instruction::MOVEA(src, reg, size) => {
@ -386,7 +397,7 @@ impl MC68010 {
Instruction::MOVEQ(data, reg) => {
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
self.d_reg[reg as usize] = value;
self.set_compare_flags(value, false, Size::Long);
self.set_compare_flags(value, Size::Long, false);
},
//Instruction::MUL(Target, Target, Size, Sign) => {
//},
@ -444,7 +455,7 @@ impl MC68010 {
//},
Instruction::TST(target, size) => {
let value = self.get_target_value(space, target, size)?;
self.set_compare_flags(value, false, size);
self.set_compare_flags(value, size, false);
},
//Instruction::TRAP(u8) => {
//},
@ -480,9 +491,9 @@ impl MC68010 {
get_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, size)
},
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_size) => {
let reg_offset = get_value_sized(self.get_x_reg_value(rtype, xreg), target_size);
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
let addr = self.get_a_reg_mut(reg);
get_address_sized(space, (*addr).wrapping_add(reg_offset).wrapping_add(offset as u32) as Address, size)
get_address_sized(space, (*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) as Address, size)
},
Target::IndirectMemory(addr) => {
get_address_sized(space, addr as Address, size)
@ -491,8 +502,8 @@ impl MC68010 {
get_address_sized(space, self.pc.wrapping_add(offset as u32) as Address, size)
},
Target::IndirectPCXRegOffset(rtype, xreg, offset, target_size) => {
let reg_offset = get_value_sized(self.get_x_reg_value(rtype, xreg), target_size);
get_address_sized(space, self.pc.wrapping_add(reg_offset).wrapping_add(offset as u32) as Address, size)
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
get_address_sized(space, self.pc.wrapping_add(reg_offset as u32).wrapping_add(offset as u32) as Address, size)
},
}
}
@ -523,9 +534,9 @@ impl MC68010 {
set_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, value, size)?;
},
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_size) => {
let reg_offset = get_value_sized(self.get_x_reg_value(rtype, xreg), target_size);
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
let addr = self.get_a_reg_mut(reg);
set_address_sized(space, (*addr).wrapping_add(reg_offset).wrapping_add(offset as u32) as Address, value, size)?;
set_address_sized(space, (*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) as Address, value, size)?;
},
Target::IndirectMemory(addr) => {
set_address_sized(space, addr as Address, value, size)?;
@ -543,9 +554,9 @@ impl MC68010 {
(*addr).wrapping_add(offset as u32)
},
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_size) => {
let reg_offset = get_value_sized(self.get_x_reg_value(rtype, xreg), target_size);
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
let addr = self.get_a_reg_mut(reg);
(*addr).wrapping_add(reg_offset).wrapping_add(offset as u32)
(*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32)
},
Target::IndirectMemory(addr) => {
addr
@ -554,8 +565,8 @@ impl MC68010 {
self.pc.wrapping_add(offset as u32)
},
Target::IndirectPCXRegOffset(rtype, xreg, offset, target_size) => {
let reg_offset = get_value_sized(self.get_x_reg_value(rtype, xreg), target_size);
self.pc.wrapping_add(reg_offset).wrapping_add(offset as u32)
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
self.pc.wrapping_add(reg_offset as u32).wrapping_add(offset as u32)
},
_ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))),
};
@ -574,7 +585,7 @@ impl MC68010 {
},
Size::Long => existing.overflowing_sub(diff),
};
self.set_compare_flags(result, overflow, size);
self.set_compare_flags(result, size, overflow);
result
}
@ -613,7 +624,7 @@ impl MC68010 {
}
}
fn set_compare_flags(&mut self, value: u32, carry: bool, size: Size) {
fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool) {
let value = sign_extend_to_long(value, size);
let mut flags = 0x0000;
@ -631,11 +642,8 @@ impl MC68010 {
fn set_logic_flags(&mut self, value: u32, size: Size) {
let mut flags = 0x0000;
match size {
Size::Byte if value & 0x80 != 0 => flags |= FLAGS_NEGATIVE,
Size::Word if value & 0x8000 != 0 => flags |= FLAGS_NEGATIVE,
Size::Long if value & 0x80000000 != 0 => flags |= FLAGS_NEGATIVE,
_ => { },
if get_msb(value, size) {
flags |= FLAGS_NEGATIVE;
}
if value == 0 {
flags |= FLAGS_ZERO
@ -710,16 +718,35 @@ fn set_address_sized(space: &mut AddressSpace, addr: Address, value: u32, size:
}
}
fn sign_extend_to_long(value: u32, from: Size) -> i32 {
match from {
Size::Byte => ((value as u8) as i8) as i32,
Size::Word => ((value as u16) as i16) as i32,
Size::Long => value as i32,
fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) {
match dir {
ShiftDirection::Left => {
match size {
Size::Byte => (((value as u8) << 1) as u32, get_msb(value, size)),
Size::Word => (((value as u16) << 1) as u32, get_msb(value, size)),
Size::Long => ((value << 1) as u32, get_msb(value, size)),
}
},
ShiftDirection::Right => {
let mask = if arithmetic { get_msb_mask(value, size) } else { 0 };
((value >> 1) | mask, (value & 0x1) != 0)
},
}
}
/*
impl Processor for MC68010 {
fn get_msb(value: u32, size: Size) -> bool {
match size {
Size::Byte => (value & 0x00000080) != 0,
Size::Word => (value & 0x00008000) != 0,
Size::Long => (value & 0x80000000) != 0,
}
}
*/
fn get_msb_mask(value: u32, size: Size) -> u32 {
match size {
Size::Byte => value & 0x00000080,
Size::Word => value & 0x00008000,
Size::Long => value & 0x80000000,
}
}

View File

@ -25,7 +25,7 @@ fn main() {
space.insert(0x00700000, Box::new(serial));
let mut cpu = MC68010::new();
//cpu.set_breakpoint(0x0224);
//cpu.set_breakpoint(0x02bc);
cpu.use_tracing = true;
while cpu.is_running() {
match cpu.step(&mut space) {