mirror of
https://github.com/transistorfet/moa.git
synced 2024-05-29 04:41:29 +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 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user