mirror of
https://github.com/transistorfet/moa.git
synced 2024-12-22 12:29:51 +00:00
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:
parent
f7529bbb41
commit
a5cac4d309
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user