mirror of
https://github.com/transistorfet/moa.git
synced 2025-04-06 11:38:21 +00:00
Fixed a number of instruction bugs with m68k
This commit is contained in:
parent
b6cccea437
commit
2cb21d7b8d
@ -347,10 +347,18 @@ impl M68kDecoder {
|
||||
data = 8;
|
||||
}
|
||||
|
||||
if (ins & 0x0100) == 0 {
|
||||
Ok(Instruction::ADD(Target::Immediate(data), target, size))
|
||||
if let Target::DirectAReg(reg) = target {
|
||||
if (ins & 0x0100) == 0 {
|
||||
Ok(Instruction::ADDA(Target::Immediate(data), reg, size))
|
||||
} else {
|
||||
Ok(Instruction::SUBA(Target::Immediate(data), reg, size))
|
||||
}
|
||||
} else {
|
||||
Ok(Instruction::SUB(Target::Immediate(data), target, size))
|
||||
if (ins & 0x0100) == 0 {
|
||||
Ok(Instruction::ADD(Target::Immediate(data), target, size))
|
||||
} else {
|
||||
Ok(Instruction::SUB(Target::Immediate(data), target, size))
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
|
@ -97,6 +97,7 @@ impl M68k {
|
||||
//}
|
||||
|
||||
self.check_pending_interrupts(system)?;
|
||||
self.check_breakpoints(system);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -129,7 +130,7 @@ impl M68k {
|
||||
}
|
||||
|
||||
pub fn exception(&mut self, system: &System, number: u8, is_interrupt: bool) -> Result<(), Error> {
|
||||
debug!("{}: raising exception {}", DEV_NAME, number);
|
||||
info!("{}: raising exception {}", DEV_NAME, number);
|
||||
let offset = (number as u16) << 2;
|
||||
if self.cputype >= M68kType::MC68010 {
|
||||
self.push_word(system, offset)?;
|
||||
@ -150,8 +151,6 @@ impl M68k {
|
||||
}
|
||||
|
||||
pub fn decode_next(&mut self, system: &System) -> Result<(), Error> {
|
||||
self.check_breakpoints(system);
|
||||
|
||||
self.timer.decode.start();
|
||||
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
||||
self.timer.decode.end();
|
||||
@ -161,12 +160,15 @@ impl M68k {
|
||||
}
|
||||
|
||||
self.state.pc = self.decoder.end;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn execute_current(&mut self, system: &System) -> Result<(), Error> {
|
||||
self.timer.execute.start();
|
||||
match self.decoder.instruction {
|
||||
//Instruction::ABCD(Target) => {
|
||||
//},
|
||||
Instruction::ADD(src, dest, size) => {
|
||||
let value = self.get_target_value(system, src, size)?;
|
||||
let existing = self.get_target_value(system, dest, size)?;
|
||||
@ -175,11 +177,13 @@ impl M68k {
|
||||
self.set_target_value(system, dest, result, size)?;
|
||||
},
|
||||
Instruction::ADDA(src, dest, size) => {
|
||||
let value = self.get_target_value(system, src, size)?;
|
||||
let value = sign_extend_to_long(self.get_target_value(system, src, size)?, size) as u32;
|
||||
let existing = *self.get_a_reg_mut(dest);
|
||||
let (result, carry) = overflowing_add_sized(existing, value, Size::Long);
|
||||
let (result, _) = overflowing_add_sized(existing, value, Size::Long);
|
||||
*self.get_a_reg_mut(dest) = result;
|
||||
},
|
||||
//Instruction::ADDX(Target) => {
|
||||
//},
|
||||
Instruction::AND(src, dest, size) => {
|
||||
let value = self.get_target_value(system, src, size)?;
|
||||
let existing = self.get_target_value(system, dest, size)?;
|
||||
@ -188,7 +192,7 @@ impl M68k {
|
||||
self.set_logic_flags(result, size);
|
||||
},
|
||||
Instruction::ANDtoCCR(value) => {
|
||||
self.state.sr = self.state.sr & (value as u16);
|
||||
self.state.sr = (self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) & (value as u16));
|
||||
},
|
||||
Instruction::ANDtoSR(value) => {
|
||||
self.require_supervisor()?;
|
||||
@ -226,32 +230,32 @@ impl M68k {
|
||||
self.debugger.stack_tracer.push_return(sp);
|
||||
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
|
||||
},
|
||||
Instruction::BTST(bitnum, target, size) => {
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
||||
let value = self.get_target_value(system, target, size)?;
|
||||
self.set_bit_test_flags(value, bitnum, size);
|
||||
},
|
||||
Instruction::BCHG(bitnum, target, size) => {
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)? % get_bit_op_max(size);
|
||||
let mut value = self.get_target_value(system, target, size)?;
|
||||
let mask = self.set_bit_test_flags(value, bitnum, size);
|
||||
value = (value & !mask) | (!(value & mask) & mask);
|
||||
self.set_target_value(system, target, value, size)?;
|
||||
},
|
||||
Instruction::BCLR(bitnum, target, size) => {
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)? % get_bit_op_max(size);
|
||||
let mut value = self.get_target_value(system, target, size)?;
|
||||
let mask = self.set_bit_test_flags(value, bitnum, size);
|
||||
value = value & !mask;
|
||||
self.set_target_value(system, target, value, size)?;
|
||||
},
|
||||
Instruction::BSET(bitnum, target, size) => {
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)? % get_bit_op_max(size);
|
||||
let mut value = self.get_target_value(system, target, size)?;
|
||||
let mask = self.set_bit_test_flags(value, bitnum, size);
|
||||
value = value | mask;
|
||||
self.set_target_value(system, target, value, size)?;
|
||||
},
|
||||
Instruction::BTST(bitnum, target, size) => {
|
||||
let bitnum = self.get_target_value(system, bitnum, Size::Byte)? % get_bit_op_max(size);
|
||||
let value = self.get_target_value(system, target, size)?;
|
||||
self.set_bit_test_flags(value, bitnum, size);
|
||||
},
|
||||
Instruction::BFCHG(target, offset, width) => {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -311,6 +315,8 @@ impl M68k {
|
||||
},
|
||||
//Instruction::BKPT(u8) => {
|
||||
//},
|
||||
//Instruction::CHK(Target, Size) => {
|
||||
//},
|
||||
Instruction::CLR(target, size) => {
|
||||
self.set_target_value(system, target, 0, size)?;
|
||||
// Clear flags except Zero flag
|
||||
@ -396,18 +402,18 @@ impl M68k {
|
||||
self.set_logic_flags(result, size);
|
||||
},
|
||||
Instruction::EORtoCCR(value) => {
|
||||
self.state.sr = self.state.sr ^ (value as u16);
|
||||
self.state.sr = (self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) ^ (value as u16));
|
||||
},
|
||||
Instruction::EORtoSR(value) => {
|
||||
self.require_supervisor()?;
|
||||
self.state.sr = self.state.sr ^ value;
|
||||
},
|
||||
//Instruction::EXG(target1, target2) => {
|
||||
// let value1 = self.get_target_value(system, target1, Size::Long)?;
|
||||
// let value2 = self.get_target_value(system, target2, Size::Long)?;
|
||||
// self.set_target_value(system, target1, value2, Size::Long)?;
|
||||
// self.set_target_value(system, target2, value1, Size::Long)?;
|
||||
//},
|
||||
Instruction::EXG(target1, target2) => {
|
||||
let value1 = self.get_target_value(system, target1, Size::Long)?;
|
||||
let value2 = self.get_target_value(system, target2, Size::Long)?;
|
||||
self.set_target_value(system, target1, value2, Size::Long)?;
|
||||
self.set_target_value(system, target2, value1, Size::Long)?;
|
||||
},
|
||||
Instruction::EXT(reg, from_size, to_size) => {
|
||||
let input = self.state.d_reg[reg as usize];
|
||||
let result = match (from_size, to_size) {
|
||||
@ -494,6 +500,16 @@ impl M68k {
|
||||
},
|
||||
}
|
||||
},
|
||||
Instruction::MOVEM(target, size, dir, mask) => {
|
||||
self.execute_movem(system, target, size, dir, mask)?;
|
||||
},
|
||||
//Instruction::MOVEP(Register, Target, Size, Direction) => {
|
||||
//},
|
||||
Instruction::MOVEQ(data, reg) => {
|
||||
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
|
||||
self.state.d_reg[reg as usize] = value;
|
||||
self.set_logic_flags(value, Size::Long);
|
||||
},
|
||||
Instruction::MOVEUSP(target, dir) => {
|
||||
self.require_supervisor()?;
|
||||
match dir {
|
||||
@ -501,14 +517,6 @@ impl M68k {
|
||||
Direction::FromTarget => { self.state.usp = self.get_target_value(system, target, Size::Long)?; },
|
||||
}
|
||||
},
|
||||
Instruction::MOVEM(target, size, dir, mask) => {
|
||||
self.execute_movem(system, target, size, dir, mask)?;
|
||||
},
|
||||
Instruction::MOVEQ(data, reg) => {
|
||||
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
|
||||
self.state.d_reg[reg as usize] = value;
|
||||
self.set_logic_flags(value, Size::Long);
|
||||
},
|
||||
Instruction::MULW(src, dest, sign) => {
|
||||
let value = self.get_target_value(system, src, Size::Word)?;
|
||||
let existing = get_value_sized(self.state.d_reg[dest as usize], Size::Word);
|
||||
@ -559,7 +567,7 @@ impl M68k {
|
||||
self.set_logic_flags(result, size);
|
||||
},
|
||||
Instruction::ORtoCCR(value) => {
|
||||
self.state.sr = self.state.sr | (value as u16);
|
||||
self.state.sr = (self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) | (value as u16));
|
||||
},
|
||||
Instruction::ORtoSR(value) => {
|
||||
self.require_supervisor()?;
|
||||
@ -611,6 +619,8 @@ impl M68k {
|
||||
self.debugger.stack_tracer.pop_return();
|
||||
self.state.pc = self.pop_long(system)?;
|
||||
},
|
||||
//Instruction::RTD(i16) => {
|
||||
//},
|
||||
Instruction::Scc(cond, target) => {
|
||||
let condition_true = self.get_current_condition(cond);
|
||||
if condition_true {
|
||||
@ -624,6 +634,8 @@ impl M68k {
|
||||
self.state.sr = flags;
|
||||
self.state.status = Status::Stopped;
|
||||
},
|
||||
//Instruction::SBCD(Target) => {
|
||||
//},
|
||||
Instruction::SUB(src, dest, size) => {
|
||||
let value = self.get_target_value(system, src, size)?;
|
||||
let existing = self.get_target_value(system, dest, size)?;
|
||||
@ -632,11 +644,13 @@ impl M68k {
|
||||
self.set_target_value(system, dest, result, size)?;
|
||||
},
|
||||
Instruction::SUBA(src, dest, size) => {
|
||||
let value = self.get_target_value(system, src, size)?;
|
||||
let value = sign_extend_to_long(self.get_target_value(system, src, size)?, size) as u32;
|
||||
let existing = *self.get_a_reg_mut(dest);
|
||||
let (result, carry) = overflowing_sub_sized(existing, value, size);
|
||||
let (result, _) = overflowing_sub_sized(existing, value, Size::Long);
|
||||
*self.get_a_reg_mut(dest) = result;
|
||||
},
|
||||
//Instruction::SUBX(Target) => {
|
||||
//},
|
||||
Instruction::SWAP(reg) => {
|
||||
let value = self.state.d_reg[reg as usize];
|
||||
self.state.d_reg[reg as usize] = ((value & 0x0000FFFF) << 16) | ((value & 0xFFFF0000) >> 16);
|
||||
@ -1156,6 +1170,14 @@ fn get_msb_mask(value: u32, size: Size) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bit_op_max(size: Size) -> u32 {
|
||||
match size {
|
||||
Size::Byte => 8,
|
||||
Size::Long => 32,
|
||||
Size::Word => panic!("bit ops cannot be word size"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bit_field_mask(offset: u32, width: u32) -> u32 {
|
||||
let mut mask = 0;
|
||||
for _ in 0..width {
|
||||
|
@ -181,9 +181,9 @@ pub enum Instruction {
|
||||
RTS,
|
||||
RTD(i16),
|
||||
|
||||
SBCD(Target, Target),
|
||||
Scc(Condition, Target),
|
||||
STOP(u16),
|
||||
SBCD(Target, Target),
|
||||
SUB(Target, Target, Size),
|
||||
SUBA(Target, Register, Size),
|
||||
SUBX(Target, Target, Size),
|
||||
|
@ -531,7 +531,7 @@ mod execute_tests {
|
||||
use crate::devices::{Address, Addressable, Steppable, wrap_transmutable};
|
||||
|
||||
use crate::cpus::m68k::{M68k, M68kType};
|
||||
use crate::cpus::m68k::instructions::{Instruction, Target, Size, Sign, ShiftDirection};
|
||||
use crate::cpus::m68k::instructions::{Instruction, Target, Size, Sign, ShiftDirection, Condition};
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
@ -553,6 +553,7 @@ mod execute_tests {
|
||||
};
|
||||
let mut cpu = M68k::new(cputype, 10_000_000, port);
|
||||
cpu.step(&system).unwrap();
|
||||
cpu.decoder.init(cpu.state.pc);
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.msp, INIT_STACK as u32);
|
||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
||||
@ -616,6 +617,39 @@ mod execute_tests {
|
||||
assert_eq!(cpu.state, expected_state);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_blt() {
|
||||
let (mut cpu, system) = init_test(M68kType::MC68010);
|
||||
|
||||
cpu.state.d_reg[0] = 0x20;
|
||||
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte);
|
||||
cpu.execute_current(&system).unwrap();
|
||||
cpu.decoder.instruction = Instruction::Bcc(Condition::LessThan, 8);
|
||||
|
||||
let mut expected_state = cpu.state.clone();
|
||||
expected_state.pc = expected_state.pc + 8 + 2;
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_eq!(cpu.state, expected_state);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_blt_not() {
|
||||
let (mut cpu, system) = init_test(M68kType::MC68010);
|
||||
|
||||
cpu.state.d_reg[0] = 0x30;
|
||||
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte);
|
||||
cpu.execute_current(&system).unwrap();
|
||||
cpu.decoder.instruction = Instruction::Bcc(Condition::LessThan, 8);
|
||||
|
||||
let mut expected_state = cpu.state.clone();
|
||||
expected_state.pc = expected_state.pc + 8 + 2;
|
||||
|
||||
cpu.execute_current(&system).unwrap();
|
||||
assert_ne!(cpu.state, expected_state);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn instruction_cmpi_less() {
|
||||
let (mut cpu, system) = init_test(M68kType::MC68010);
|
||||
|
@ -1,4 +1,6 @@
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::system::System;
|
||||
use crate::devices::{Address, Debuggable, TransmutableBox};
|
||||
@ -55,6 +57,7 @@ impl Debugger {
|
||||
|
||||
loop {
|
||||
let mut buffer = String::new();
|
||||
std::io::stdout().write_all(b"> ");
|
||||
std::io::stdin().read_line(&mut buffer).unwrap();
|
||||
let args: Vec<&str> = buffer.split_whitespace().collect();
|
||||
match self.run_debugger_command(system, debug_obj, &args) {
|
||||
@ -83,14 +86,14 @@ impl Debugger {
|
||||
println!("Breakpoint set for {:08x}", addr);
|
||||
}
|
||||
},
|
||||
"c" | "continue" => {
|
||||
if args.len() > 1 {
|
||||
self.repeat = u32::from_str_radix(args[1], 10).map_err(|_| Error::new("Unable to parse repeat number"))?;
|
||||
self.last_command = Some("c".to_string());
|
||||
"r" | "remove" => {
|
||||
if args.len() != 2 {
|
||||
println!("Usage: breakpoint <addr>");
|
||||
} else {
|
||||
let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse breakpoint address"))?;
|
||||
debug_obj.remove_breakpoint(addr as Address);
|
||||
println!("Breakpoint removed for {:08x}", addr);
|
||||
}
|
||||
|
||||
system.disable_debugging();
|
||||
return Ok(true);
|
||||
},
|
||||
"d" | "dump" => {
|
||||
if args.len() > 1 {
|
||||
@ -104,7 +107,13 @@ impl Debugger {
|
||||
"dis" | "disassemble" => {
|
||||
debug_obj.print_disassembly(0, 0);
|
||||
},
|
||||
"c" | "continue" => {
|
||||
self.check_repeat_arg(args)?;
|
||||
system.disable_debugging();
|
||||
return Ok(true);
|
||||
},
|
||||
"s" | "step" => {
|
||||
self.check_repeat_arg(args)?;
|
||||
return Ok(true);
|
||||
},
|
||||
//"ds" | "stack" | "dumpstack" => {
|
||||
@ -125,5 +134,13 @@ impl Debugger {
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn check_repeat_arg(&mut self, args: &[&str]) -> Result<(), Error> {
|
||||
if args.len() > 1 {
|
||||
self.repeat = u32::from_str_radix(args[1], 10).map_err(|_| Error::new("Unable to parse repeat number"))?;
|
||||
self.last_command = Some("c".to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user