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 reg = get_low_reg(ins);
let rotation = get_high_reg(ins); let rotation = get_high_reg(ins);
let count = if (ins & 0x0020) == 0 { let count = if (ins & 0x0020) == 0 {
Target::Immediate(rotation as u32) Target::Immediate(if rotation != 0 { rotation as u32 } else { 8 })
} else { } else {
Target::DirectDReg(rotation) Target::DirectDReg(rotation)
}; };
@ -595,8 +595,8 @@ impl MC68010 {
self.get_mode_as_target(space, mode, reg, size) self.get_mode_as_target(space, mode, reg, size)
} }
fn decode_brief_extension_word(&self, brief_extension: u16) -> (RegisterType, u8, u16, Size) { fn decode_brief_extension_word(&self, brief_extension: u16) -> (RegisterType, u8, i32, Size) {
let data = brief_extension & 0x00FF; let data = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte);
let xreg = ((brief_extension & 0x7000) >> 12) as u8; let xreg = ((brief_extension & 0x7000) >> 12) as u8;
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long }; let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
@ -613,13 +613,13 @@ impl MC68010 {
0b011 => Target::IndirectARegInc(reg), 0b011 => Target::IndirectARegInc(reg),
0b100 => Target::IndirectARegDec(reg), 0b100 => Target::IndirectARegDec(reg),
0b101 => { 0b101 => {
let data = self.read_instruction_word(space)?; let data = sign_extend_to_long(self.read_instruction_word(space)? as u32, Size::Word);
Target::IndirectARegOffset(reg, (data as i16) as i32) Target::IndirectARegOffset(reg, data)
}, },
0b110 => { 0b110 => {
let brief_extension = self.read_instruction_word(space)?; let brief_extension = self.read_instruction_word(space)?;
let (rtype, xreg, data, size) = self.decode_brief_extension_word(brief_extension); 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 => { 0b111 => {
match reg { match reg {
@ -632,13 +632,13 @@ impl MC68010 {
Target::IndirectMemory(value) Target::IndirectMemory(value)
}, },
0b010 => { 0b010 => {
let data = self.read_instruction_word(space)?; let data = sign_extend_to_long(self.read_instruction_word(space)? as u32, Size::Word);
Target::IndirectPCOffset((data as i16) as i32) Target::IndirectPCOffset(data)
}, },
0b011 => { 0b011 => {
let brief_extension = self.read_instruction_word(space)?; let brief_extension = self.read_instruction_word(space)?;
let (rtype, xreg, data, size) = self.decode_brief_extension_word(brief_extension); 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 => { 0b100 => {
let data = match size { 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::error::Error;
use crate::memory::{Address, AddressSpace}; 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 { pub trait Processor {
@ -18,6 +18,7 @@ pub const FLAGS_CARRY: u16 = 0x0001;
pub const FLAGS_OVERFLOW: u16 = 0x0002; pub const FLAGS_OVERFLOW: u16 = 0x0002;
pub const FLAGS_ZERO: u16 = 0x0004; pub const FLAGS_ZERO: u16 = 0x0004;
pub const FLAGS_NEGATIVE: u16 = 0x0008; pub const FLAGS_NEGATIVE: u16 = 0x0008;
pub const FLAGS_EXTEND: u16 = 0x0010;
pub const FLAGS_SUPERVISOR: u16 = 0x2000; pub const FLAGS_SUPERVISOR: u16 = 0x2000;
pub const ERR_BUS_ERROR: u32 = 2; pub const ERR_BUS_ERROR: u32 = 2;
@ -200,7 +201,7 @@ impl MC68010 {
}, },
Size::Long => existing.overflowing_add(value), 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)?; self.set_target_value(space, dest, result, size)?;
}, },
Instruction::AND(src, dest, size) => { Instruction::AND(src, dest, size) => {
@ -309,11 +310,21 @@ impl MC68010 {
}, },
//Instruction::LINK(u8, u16) => { //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) => { Instruction::MOVE(src, dest, size) => {
let value = self.get_target_value(space, src, 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)?; self.set_target_value(space, dest, value, size)?;
}, },
Instruction::MOVEA(src, reg, size) => { Instruction::MOVEA(src, reg, size) => {
@ -386,7 +397,7 @@ impl MC68010 {
Instruction::MOVEQ(data, reg) => { Instruction::MOVEQ(data, reg) => {
let value = sign_extend_to_long(data as u32, Size::Byte) as u32; let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
self.d_reg[reg as usize] = value; 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) => { //Instruction::MUL(Target, Target, Size, Sign) => {
//}, //},
@ -444,7 +455,7 @@ impl MC68010 {
//}, //},
Instruction::TST(target, size) => { Instruction::TST(target, size) => {
let value = self.get_target_value(space, 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) => { //Instruction::TRAP(u8) => {
//}, //},
@ -480,9 +491,9 @@ impl MC68010 {
get_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, size) get_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, size)
}, },
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_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); 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) => { Target::IndirectMemory(addr) => {
get_address_sized(space, addr as Address, size) 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) get_address_sized(space, self.pc.wrapping_add(offset as u32) as Address, size)
}, },
Target::IndirectPCXRegOffset(rtype, xreg, offset, target_size) => { Target::IndirectPCXRegOffset(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);
get_address_sized(space, self.pc.wrapping_add(reg_offset).wrapping_add(offset as u32) as Address, 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)?; set_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, value, size)?;
}, },
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_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); 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) => { Target::IndirectMemory(addr) => {
set_address_sized(space, addr as Address, value, size)?; set_address_sized(space, addr as Address, value, size)?;
@ -543,9 +554,9 @@ impl MC68010 {
(*addr).wrapping_add(offset as u32) (*addr).wrapping_add(offset as u32)
}, },
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_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); 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) => { Target::IndirectMemory(addr) => {
addr addr
@ -554,8 +565,8 @@ impl MC68010 {
self.pc.wrapping_add(offset as u32) self.pc.wrapping_add(offset as u32)
}, },
Target::IndirectPCXRegOffset(rtype, xreg, offset, target_size) => { Target::IndirectPCXRegOffset(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);
self.pc.wrapping_add(reg_offset).wrapping_add(offset as u32) self.pc.wrapping_add(reg_offset as u32).wrapping_add(offset as u32)
}, },
_ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))), _ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))),
}; };
@ -574,7 +585,7 @@ impl MC68010 {
}, },
Size::Long => existing.overflowing_sub(diff), Size::Long => existing.overflowing_sub(diff),
}; };
self.set_compare_flags(result, overflow, size); self.set_compare_flags(result, size, overflow);
result 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 value = sign_extend_to_long(value, size);
let mut flags = 0x0000; let mut flags = 0x0000;
@ -631,11 +642,8 @@ impl MC68010 {
fn set_logic_flags(&mut self, value: u32, size: Size) { fn set_logic_flags(&mut self, value: u32, size: Size) {
let mut flags = 0x0000; let mut flags = 0x0000;
match size { if get_msb(value, size) {
Size::Byte if value & 0x80 != 0 => flags |= FLAGS_NEGATIVE, flags |= FLAGS_NEGATIVE;
Size::Word if value & 0x8000 != 0 => flags |= FLAGS_NEGATIVE,
Size::Long if value & 0x80000000 != 0 => flags |= FLAGS_NEGATIVE,
_ => { },
} }
if value == 0 { if value == 0 {
flags |= FLAGS_ZERO 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 { fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) {
match from { match dir {
Size::Byte => ((value as u8) as i8) as i32, ShiftDirection::Left => {
Size::Word => ((value as u16) as i16) as i32, match size {
Size::Long => value as i32, 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)
},
} }
} }
/* fn get_msb(value: u32, size: Size) -> bool {
impl Processor for MC68010 { 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)); space.insert(0x00700000, Box::new(serial));
let mut cpu = MC68010::new(); let mut cpu = MC68010::new();
//cpu.set_breakpoint(0x0224); //cpu.set_breakpoint(0x02bc);
cpu.use_tracing = true; cpu.use_tracing = true;
while cpu.is_running() { while cpu.is_running() {
match cpu.step(&mut space) { match cpu.step(&mut space) {