Added the Asd, LINK, and UNLK instructions

This commit is contained in:
transistor 2021-10-02 15:35:08 -07:00
parent 80c8fe9797
commit 98883e3daa
4 changed files with 103 additions and 24 deletions

View File

@ -115,7 +115,7 @@ pub enum Instruction {
CMP(Target, Target, Size),
CMPA(Target, u8, Size),
DBcc(Condition, u16),
DBcc(Condition, i16),
DIV(Target, Target, Size, Sign),
EOR(Target, Target, Size),
@ -130,7 +130,7 @@ pub enum Instruction {
JSR(Target),
LEA(Target, u8),
LINK(u8, u16),
LINK(u8, i16),
LSd(Target, Target, Size, ShiftDirection),
MOVE(Target, Target, Size),
@ -378,7 +378,7 @@ impl M68kDecoder {
let reg = get_low_reg(ins);
if (ins & 0b1000) == 0 {
let data = self.read_instruction_word(space)?;
Ok(Instruction::LINK(reg, data))
Ok(Instruction::LINK(reg, data as i16))
} else {
Ok(Instruction::UNLK(reg))
}
@ -435,15 +435,15 @@ impl M68kDecoder {
}
},
OPCG_BRANCH => {
let mut disp = ((ins & 0xFF) as i8) as u16;
let mut disp = ((ins & 0xFF) as i8) as i16;
if disp == 0 {
disp = self.read_instruction_word(space)?;
disp = self.read_instruction_word(space)? as i16;
}
let condition = get_condition(ins);
match condition {
Condition::True => Ok(Instruction::BRA(disp as i16)),
Condition::False => Ok(Instruction::BSR(disp as i16)),
_ => Ok(Instruction::Bcc(condition, disp as i16)),
Condition::True => Ok(Instruction::BRA(disp)),
Condition::False => Ok(Instruction::BSR(disp)),
_ => Ok(Instruction::Bcc(condition, disp)),
}
},
OPCG_MOVEQ => {

View File

@ -141,15 +141,14 @@ impl MC68010 {
}
pub(crate) fn decode_next(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
self.decoder = M68kDecoder::decode_at(space, self.state.pc)?;
self.state.pc = self.decoder.end;
self.check_breakpoints();
self.decoder = M68kDecoder::decode_at(space, self.state.pc)?;
if self.debugger.use_tracing {
// Print instruction bytes for debugging
let ins_data: Result<String, Error> =
(0..((self.state.pc - self.decoder.start) / 2)).map(|offset|
(0..((self.decoder.end - self.decoder.start) / 2)).map(|offset|
Ok(format!("{:04x} ", space.read_beu16((self.decoder.start + (offset * 2)) as Address)?))
).collect();
debug!("{:#010x}: {}\n\t{:?}\n", self.decoder.start, ins_data?, self.decoder.instruction);
@ -158,6 +157,8 @@ impl MC68010 {
if self.debugger.use_debugger {
self.run_debugger(space);
}
self.state.pc = self.decoder.end;
Ok(())
}
@ -192,8 +193,22 @@ impl MC68010 {
Instruction::ANDtoSR(value) => {
self.state.sr = self.state.sr | value;
},
//Instruction::ASd(Target, Target, Size, ShiftDirection) => {
//},
Instruction::ASd(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);
let original = pair.0;
for _ in 0..count {
pair = shift_operation(pair.0, size, shift_dir, true);
}
self.set_compare_flags(pair.0, size, false);
if pair.1 {
self.state.sr |= FLAGS_EXTEND | FLAGS_CARRY;
}
if get_msb(pair.0, size) != get_msb(original, size) {
self.state.sr |= FLAGS_OVERFLOW;
}
self.set_target_value(space, target, pair.0, size)?;
},
Instruction::Bcc(cond, offset) => {
let should_branch = self.get_current_condition(cond);
if should_branch {
@ -236,7 +251,7 @@ impl MC68010 {
Instruction::CLR(target, size) => {
self.set_target_value(space, target, 0, size)?;
// Clear flags except Zero flag
self.state.sr = (self.state.sr & 0xFFF0) | 0x0004;
self.state.sr = (self.state.sr & 0xFFF0) | FLAGS_ZERO;
},
Instruction::CMP(src, dest, size) => {
let value = self.get_target_value(space, src, size)?;
@ -289,8 +304,14 @@ impl MC68010 {
let addr = self.get_a_reg_mut(reg);
*addr = value;
},
//Instruction::LINK(u8, u16) => {
//},
Instruction::LINK(reg, offset) => {
let value = *self.get_a_reg_mut(reg);
self.push_long(space, value)?;
let sp = *self.get_stack_pointer_mut();
let addr = self.get_a_reg_mut(reg);
*addr = sp;
*self.get_stack_pointer_mut() = sp + (offset as i32) as u32;
},
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);
@ -337,8 +358,12 @@ impl MC68010 {
},
}
},
//Instruction::MOVEUSP(Target, Direction) => {
//},
Instruction::MOVEUSP(target, dir) => {
match dir {
Direction::ToTarget => self.set_target_value(space, target, self.state.usp, Size::Long)?,
Direction::FromTarget => { self.state.usp = self.get_target_value(space, target, Size::Long)?; },
}
},
Instruction::MOVEM(target, size, dir, mask) => {
// TODO moving words requires a sign extension to 32 bits
if size != Size::Long { return Err(Error::new("Unsupported size in MOVEM instruction")); }
@ -390,8 +415,12 @@ impl MC68010 {
//Instruction::NEGX(Target, Size) => {
//},
Instruction::NOP => { },
//Instruction::NOT(target, size) => {
//},
Instruction::NOT(target, size) => {
let mut value = self.get_target_value(space, target, size)?;
value = get_value_sized(!value, size);
self.set_target_value(space, target, value, size)?;
self.set_logic_flags(value, size);
},
Instruction::OR(src, dest, size) => {
let value = self.get_target_value(space, src, size)?;
let existing = self.get_target_value(space, dest, size)?;
@ -443,8 +472,13 @@ impl MC68010 {
//},
//Instruction::TRAPV => {
//},
//Instruction::UNLK(u8) => {
//},
Instruction::UNLK(reg) => {
let value = *self.get_a_reg_mut(reg);
*self.get_stack_pointer_mut() = value;
let new_value = self.pop_long(space)?;
let addr = self.get_a_reg_mut(reg);
*addr = new_value;
},
_ => { panic!(""); },
}
@ -490,7 +524,9 @@ impl MC68010 {
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, 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 as u32).wrapping_add(offset as u32) as Address, size)
let result = get_address_sized(space, (*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) as Address, size);
println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32), result.as_ref().unwrap());
result
},
Target::IndirectMemory(addr) => {
get_address_sized(space, addr as Address, size)

View File

@ -53,5 +53,47 @@ mod tests {
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.a_reg[0], 0x000000FF);
}
#[test]
fn instruction_cmpi_equal() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0x7020).unwrap();
space.write_beu16(INIT_ADDR + 2, 0x0C00).unwrap();
space.write_beu16(INIT_ADDR + 4, 0x0020).unwrap();
cpu.step(&mut space).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte));
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.sr & 0x0F, 0x04);
}
#[test]
fn instruction_cmpi_greater() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0x7020).unwrap();
space.write_beu16(INIT_ADDR + 2, 0x0C00).unwrap();
space.write_beu16(INIT_ADDR + 4, 0x0030).unwrap();
cpu.step(&mut space).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte));
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.sr & 0x0F, 0x00B);
}
#[test]
fn instruction_cmpi_less() {
let (mut cpu, mut space) = init_test();
space.write_beu16(INIT_ADDR, 0x7020).unwrap();
space.write_beu16(INIT_ADDR + 2, 0x0C00).unwrap();
space.write_beu16(INIT_ADDR + 4, 0x0010).unwrap();
cpu.step(&mut space).unwrap();
cpu.decode_next(&mut space).unwrap();
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte));
cpu.execute_current(&mut space).unwrap();
assert_eq!(cpu.state.sr & 0x0F, 0x00);
}
}

View File

@ -30,6 +30,7 @@ fn main() {
//cpu.add_breakpoint(0x0838);
//cpu.add_breakpoint(0x0ea0);
cpu.add_breakpoint(0x0034);
cpu.enable_tracing();
while cpu.is_running() {
match cpu.step(&mut space) {