Added bit field instructions, and fixed some bugs

This commit is contained in:
transistor 2021-10-17 21:18:59 -07:00
parent 758621c410
commit 32d2d591ce
3 changed files with 188 additions and 41 deletions

View File

@ -29,6 +29,8 @@ const OPCG_RESERVED1: u8 = 0xA;
const OPCG_RESERVED2: u8 = 0xF;
pub type Register = u8;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Sign {
Signed,
@ -53,6 +55,13 @@ pub enum XRegister {
Address(u8),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RegOrImmediate {
DReg(u8),
Immediate(u8),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ControlRegister {
VBR,
@ -88,13 +97,13 @@ pub enum Condition {
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Target {
Immediate(u32),
DirectDReg(u8),
DirectAReg(u8),
IndirectAReg(u8),
IndirectARegInc(u8),
IndirectARegDec(u8),
IndirectARegOffset(u8, i32),
IndirectARegXRegOffset(u8, XRegister, i32, u8, Size),
DirectDReg(Register),
DirectAReg(Register),
IndirectAReg(Register),
IndirectARegInc(Register),
IndirectARegDec(Register),
IndirectARegOffset(Register, i32),
IndirectARegXRegOffset(Register, XRegister, i32, u8, Size),
IndirectMemory(u32),
IndirectPCOffset(i32),
IndirectPCXRegOffset(XRegister, i32, u8, Size),
@ -116,41 +125,49 @@ pub enum Instruction {
BCLR(Target, Target, Size),
BSET(Target, Target, Size),
BTST(Target, Target, Size),
BFCHG(Target, RegOrImmediate, RegOrImmediate),
BFCLR(Target, RegOrImmediate, RegOrImmediate),
BFEXTS(Target, RegOrImmediate, RegOrImmediate, Register),
BFEXTU(Target, RegOrImmediate, RegOrImmediate, Register),
BFFFO(Target, RegOrImmediate, RegOrImmediate, Register),
BFINS(Register, Target, RegOrImmediate, RegOrImmediate),
BFSET(Target, RegOrImmediate, RegOrImmediate),
BFTST(Target, RegOrImmediate, RegOrImmediate),
BKPT(u8),
CHK(Target, u8, Size),
CHK(Target, Register, Size),
CLR(Target, Size),
CMP(Target, Target, Size),
CMPA(Target, u8, Size),
CMPA(Target, Register, Size),
DBcc(Condition, u8, i16),
DBcc(Condition, Register, i16),
DIV(Target, Target, Size, Sign),
EOR(Target, Target, Size),
EORtoCCR(u8),
EORtoSR(u16),
EXG(Target, Target),
EXT(u8, Size, Size),
EXT(Register, Size, Size),
ILLEGAL,
JMP(Target),
JSR(Target),
LEA(Target, u8),
LINK(u8, i16),
LEA(Target, Register),
LINK(Register, i16),
LSd(Target, Target, Size, ShiftDirection),
MOVE(Target, Target, Size),
MOVEA(Target, u8, Size),
MOVEA(Target, Register, Size),
MOVEfromSR(Target),
MOVEtoSR(Target),
MOVEfromCCR(Target),
MOVEtoCCR(Target),
MOVEC(Target, ControlRegister, Direction),
MOVEM(Target, Size, Direction, u16),
MOVEP(u8, Target, Size, Direction),
MOVEQ(u8, u8),
MOVEP(Register, Target, Size, Direction),
MOVEQ(u8, Register),
MOVEUSP(Target, Direction),
MUL(Target, Target, Size, Sign),
@ -179,14 +196,14 @@ pub enum Instruction {
Scc(Condition, Target),
STOP(u16),
SUB(Target, Target, Size),
SWAP(u8),
SWAP(Register),
TAS(Target),
TST(Target, Size),
TRAP(u8),
TRAPV,
UNLK(u8),
UNLK(Register),
}
@ -686,14 +703,44 @@ impl M68kDecoder {
},
None => {
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
let count = Target::Immediate(1);
match (ins & 0x0600) >> 9 {
0b00 => Ok(Instruction::ASd(count, target, Size::Word, dir)),
0b01 => Ok(Instruction::LSd(count, target, Size::Word, dir)),
0b10 => Ok(Instruction::ROXd(count, target, Size::Word, dir)),
0b11 => Ok(Instruction::ROd(count, target, Size::Word, dir)),
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
let count = Target::Immediate(1);
if (ins & 0x800) == 0 {
match (ins & 0x0600) >> 9 {
0b00 => Ok(Instruction::ASd(count, target, Size::Word, dir)),
0b01 => Ok(Instruction::LSd(count, target, Size::Word, dir)),
0b10 => Ok(Instruction::ROXd(count, target, Size::Word, dir)),
0b11 => Ok(Instruction::ROd(count, target, Size::Word, dir)),
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
}
} else if self.cputype > M68kType::MC68020 {
// Bitfield instructions (MC68020+)
let ext = self.read_instruction_word(memory)?;
let reg = ((ext & 0x7000) >> 12) as u8;
let offset = match (ext & 0x0800) == 0 {
true => RegOrImmediate::Immediate(((ext & 0x07C0) >> 6) as u8),
false => RegOrImmediate::DReg(((ext & 0x01C0) >> 6) as u8),
};
let width = match (ext & 0x0020) == 0 {
true => RegOrImmediate::Immediate((ext & 0x001F) as u8),
false => RegOrImmediate::DReg((ext & 0x0007) as u8),
};
match (ins & 0x0700) >> 8 {
0b010 => Ok(Instruction::BFCHG(target, offset, width)),
0b100 => Ok(Instruction::BFCLR(target, offset, width)),
0b011 => Ok(Instruction::BFEXTS(target, offset, width, reg)),
0b001 => Ok(Instruction::BFEXTU(target, offset, width, reg)),
0b101 => Ok(Instruction::BFFFO(target, offset, width, reg)),
0b111 => Ok(Instruction::BFINS(reg, target, offset, width)),
0b110 => Ok(Instruction::BFSET(target, offset, width)),
0b000 => Ok(Instruction::BFTST(target, offset, width)),
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
}
} else {
return Err(Error::processor(Exceptions::IllegalInstruction as u32));
}
},
}
@ -732,7 +779,7 @@ impl M68kDecoder {
let xreg = if (brief_extension & 0x8000) == 0 { XRegister::Data(xreg_num) } else { XRegister::Address(xreg_num) };
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
let scale = ((brief_extension & 0x0600) >> 9) as u8;
let use_full = (brief_extension & 0x0100) == 1;
let use_full = (brief_extension & 0x0100) != 0;
if !use_full {
let displacement = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte);
@ -1062,7 +1109,10 @@ impl fmt::Display for Instruction {
Direction::ToTarget => write!(f, "movem{}\t{}, {}", size, fmt_movem_mask(*mask), target),
Direction::FromTarget => write!(f, "movem{}\t{}, {}", size, target, fmt_movem_mask(*mask)),
},
//Instruction::MOVEP(reg, target, size, dir),
Instruction::MOVEP(reg, target, size, dir) => match dir {
Direction::ToTarget => write!(f, "movep{}\t%d{}, {}", size, reg, target),
Direction::FromTarget => write!(f, "movep{}\t{}, %d{}", size, target, reg),
},
Instruction::MOVEQ(value, reg) => write!(f, "moveq\t#{:02x}, %d{}", value, reg),
Instruction::MOVEUSP(target, dir) => match dir {
Direction::ToTarget => write!(f, "movel\t%usp, {}", target),

View File

@ -12,7 +12,9 @@ use super::decode::{
Condition,
ShiftDirection,
ControlRegister,
Register,
XRegister,
RegOrImmediate,
sign_extend_to_long
};
@ -78,7 +80,9 @@ impl M68k {
Status::Running => {
match self.cycle_one(system) {
Ok(()) => Ok(()),
Err(Error { err: ErrorType::Processor, native, .. }) => {
//Err(Error { err: ErrorType::Processor, native, .. }) => {
// TODO temporary: we are passing illegal instructions upward in order to fix them
Err(Error { err: ErrorType::Processor, native, .. }) if native != Exceptions::IllegalInstruction as u32 => {
self.exception(system, native as u8)?;
Ok(())
},
@ -152,8 +156,6 @@ impl M68k {
if self.debugger.use_tracing {
self.decoder.dump_decoded(system);
// TODO for debugging temporarily
self.dump_state(system);
}
if self.debugger.use_debugger {
@ -249,6 +251,65 @@ impl M68k {
value = value | mask;
self.set_target_value(system, target, value, size)?;
},
Instruction::BFCHG(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.set_target_value(system, target, (value & !mask) | (!field & mask), Size::Long)?;
},
Instruction::BFCLR(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.set_target_value(system, target, value & !mask, Size::Long)?;
},
Instruction::BFEXTS(target, offset, width, reg) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
let right_offset = 32 - offset - width;
let mut ext = 0;
for i in 0..(offset + right_offset) {
ext = (ext >> 1) | 0x80000000;
}
self.state.d_reg[reg as usize] = (field >> right_offset) | ext;
},
Instruction::BFEXTU(target, offset, width, reg) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.state.d_reg[reg as usize] = field >> (32 - offset - width);
},
//Instruction::BFFFO(target, offset, width, reg) => {
//},
//Instruction::BFINS(reg, target, offset, width) => {
//},
Instruction::BFSET(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.set_target_value(system, target, value | mask, Size::Long)?;
},
Instruction::BFTST(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
},
//Instruction::BKPT(u8) => {
//},
Instruction::CLR(target, size) => {
self.set_target_value(system, target, 0, size)?;
// Clear flags except Zero flag
@ -722,6 +783,22 @@ impl M68k {
Ok(addr)
}
pub fn get_bit_field_args(&self, offset: RegOrImmediate, width: RegOrImmediate) -> (u32, u32) {
let offset = self.get_reg_or_immediate(offset);
let mut width = self.get_reg_or_immediate(width) % 32;
if width == 0 {
width = 32;
}
(offset, width)
}
fn get_reg_or_immediate(&self, value: RegOrImmediate) -> u32 {
match value {
RegOrImmediate::DReg(reg) => self.state.d_reg[reg as usize],
RegOrImmediate::Immediate(value) => value as u32,
}
}
fn get_control_reg_mut(&mut self, control_reg: ControlRegister) -> &mut u32 {
match control_reg {
ControlRegister::VBR => &mut self.state.vbr,
@ -734,7 +811,7 @@ impl M68k {
}
#[inline(always)]
fn get_a_reg_mut(&mut self, reg: u8) -> &mut u32 {
fn get_a_reg_mut(&mut self, reg: Register) -> &mut u32 {
if reg == 7 {
if self.is_supervisor() { &mut self.state.msp } else { &mut self.state.usp }
} else {
@ -809,6 +886,16 @@ impl M68k {
mask
}
fn set_bit_field_test_flags(&mut self, field: u32, msb_mask: u32) {
let mut flags = 0x0000;
if (field & msb_mask) != 0 {
flags |= Flags::Negative as u16;
}
if field == 0 {
flags |= Flags::Zero as u16;
}
self.state.sr = (self.state.sr & 0xFFF0) | flags;
}
fn get_current_condition(&self, cond: Condition) -> bool {
match cond {
@ -959,3 +1046,16 @@ fn get_msb_mask(value: u32, size: Size) -> u32 {
}
}
fn get_bit_field_mask(offset: u32, width: u32) -> u32 {
let mut mask = 0;
for i in 0..width {
mask = (mask >> 1) | 0x80000000;
}
mask >> offset
}
fn get_bit_field_msb(offset: u32) -> u32 {
0x80000000 >> offset
}

View File

@ -1,22 +1,19 @@
* can you make Bus be an AddressableDeviceBox so that the CPU can have a ref to it instead of calling system.get_bus()
the alternative is having system.get_bus() take an argument or something to figure out what bus to return of multiple, for multibus systems
* can you eventually make this all configurable via a config file?
* can you eventually make the system connections all configurable via a config file?
* test using mpsc to pass messages with the tty IO thread, and test if it's slower than what you have now
* make it possible to break out of the current execution, into the debugger, by using a certain keystroke
* add support for MC68020+ indexing modes
* add support for MMU
* add support for FPU
* add support for MC68020+ indexing modes, implement the full extension word for MC68020+
* make tests for each instruction
* unimplemented: ABCD, ADDX, BKPT, CHK, EXG, ILLEGAL, MOVEfromCCR, MOVEP, RTR, RTD, SBCD, SUBX
* unimplemented: ABCD, ADDX, BFFFO, BFINS, BKPT, CHK, EXG, ILLEGAL, MOVEfromCCR, MOVEP, RTR, RTD, SBCD, SUBX
* undecoded: ADDX, SUBX
* modify execution for >=MC68020: DIVSL, DIVUL, LINK, MOVEM, MULSL, MULUL, RTM, TRAPcc, UNPK
* implement the full extension word for MC68020+
* >=MC68020 undecoded & unimplemented: CALLM, CAS, CAS2, CHK2, CMP2, PACK
* >=MC68020 instructions: BFCHG, BFCLR, BFEXTS, BFEXTU, BFFFO, BFINS, BFSET, BFTST, CALLM, CAS, CAS2, CHK2, CMP2, PACK
* add support for MMU
* add support for FPU
* Coprocessor instructions: cpBcc, cpDBcc, cpGEN, cpScc, cpTRAPcc