mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-10 07:29:31 +00:00
Completed most of the instruction decode
This commit is contained in:
parent
6a4f53ca2b
commit
f22aa23dfa
587
src/m68k.rs
587
src/m68k.rs
|
@ -43,6 +43,22 @@ enum Sign {
|
|||
Unsigned,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum Direction {
|
||||
FromTarget,
|
||||
ToTarget,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum ShiftDirection {
|
||||
Right,
|
||||
Left,
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum ControlRegister {
|
||||
VBR,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum Size {
|
||||
Byte,
|
||||
|
@ -52,18 +68,22 @@ enum Size {
|
|||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum Condition {
|
||||
True,
|
||||
False,
|
||||
High,
|
||||
LowOrSame,
|
||||
CarryClear,
|
||||
CarrySet,
|
||||
Equal,
|
||||
NotEqual,
|
||||
GreaterThanOrEqual,
|
||||
GreaterThan,
|
||||
LessThanOrEqual,
|
||||
LessThan,
|
||||
Minus,
|
||||
Plus,
|
||||
Equal,
|
||||
OverflowClear,
|
||||
OverflowSet,
|
||||
Plus,
|
||||
Minus,
|
||||
GreaterThanOrEqual,
|
||||
LessThan,
|
||||
GreaterThan,
|
||||
LessThanOrEqual,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -75,22 +95,28 @@ enum Target {
|
|||
IndirectARegInc(u8),
|
||||
IndirectARegDec(u8),
|
||||
IndirectARegOffset(u8, u16),
|
||||
IndirectARegDRegOffset(u8, u8, u16),
|
||||
IndirectARegXRegOffset(u8, Box<Target>, u16, Size),
|
||||
IndirectMemory(u32),
|
||||
IndirectPCOffset(u16),
|
||||
IndirectPCRegOffset(u8, u16),
|
||||
IndirectPCXRegOffset(Box<Target>, u16, Size),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum Instruction {
|
||||
//ABCD
|
||||
ADD(Target, Target, Size),
|
||||
AND(Target, Target, Size),
|
||||
ANDCCR(u8),
|
||||
ANDSR(u16),
|
||||
ANDtoCCR(u8),
|
||||
ANDtoSR(u16),
|
||||
ASd(Target, Target, Size, ShiftDirection),
|
||||
|
||||
Bcc(Condition, u16),
|
||||
BRA(u16),
|
||||
BSR(u16),
|
||||
BTST(Target, Target, Size),
|
||||
BCHG(Target, Target, Size),
|
||||
BCLR(Target, Target, Size),
|
||||
BSET(Target, Target, Size),
|
||||
|
||||
CLR(Target, Size),
|
||||
CMP(Target, Target, Size),
|
||||
|
@ -98,16 +124,70 @@ enum Instruction {
|
|||
DBcc(Condition, u16),
|
||||
DIV(Target, Target, Size, Sign),
|
||||
|
||||
LEA(Target, u8),
|
||||
JSR(Target),
|
||||
EOR(Target, Target, Size),
|
||||
EORtoCCR(u8),
|
||||
EORtoSR(u16),
|
||||
EXG(Target, Target),
|
||||
EXT(u8, Size),
|
||||
|
||||
ILLEGAL,
|
||||
|
||||
JMP(Target),
|
||||
JSR(Target),
|
||||
|
||||
LEA(Target, u8),
|
||||
LINK(u8, u16),
|
||||
LSd(Target, Target, Size, ShiftDirection),
|
||||
|
||||
MOVE(Target, Target, Size),
|
||||
MOVEfromSR(Target),
|
||||
MOVEtoSR(Target),
|
||||
MOVEtoCCR(Target),
|
||||
MOVEC(Target, ControlRegister, Direction),
|
||||
MOVEUSP(Target, Direction),
|
||||
MOVEM(Target, Size, Direction, u16),
|
||||
MOVEQ(u8, u8),
|
||||
MUL(Target, Target, Size, Sign),
|
||||
|
||||
NBCD(Target),
|
||||
NEG(Target, Size),
|
||||
NEGX(Target, Size),
|
||||
|
||||
NOP,
|
||||
NOT(Target, Size),
|
||||
|
||||
OR(Target, Target, Size),
|
||||
ORtoCCR(u8),
|
||||
ORtoSR(u16),
|
||||
|
||||
PEA(Target),
|
||||
|
||||
RESET,
|
||||
ROd(Target, Target, Size, ShiftDirection),
|
||||
ROXd(Target, Target, Size, ShiftDirection),
|
||||
RTE,
|
||||
RTR,
|
||||
RTS,
|
||||
|
||||
//SBCD
|
||||
//Scc
|
||||
STOP(u16),
|
||||
SUB(Target, Target, Size),
|
||||
SWAP(u8),
|
||||
|
||||
TAS(Target),
|
||||
TST(Target, Size),
|
||||
TRAP(u8),
|
||||
TRAPV,
|
||||
|
||||
UNLK(u8),
|
||||
}
|
||||
|
||||
|
||||
const OPCG_BIT_OPS: u8 = 0x0;
|
||||
const OPCG_MOVE_BYTE: u8 = 0x1;
|
||||
const OPCG_MOVE_WORD: u8 = 0x2;
|
||||
const OPCG_MOVE_LONG: u8 = 0x3;
|
||||
const OPCG_MOVE_LONG: u8 = 0x2;
|
||||
const OPCG_MOVE_WORD: u8 = 0x3;
|
||||
const OPCG_MISC: u8 = 0x04;
|
||||
const OPCG_ADDQ_SUBQ: u8 = 0x5;
|
||||
const OPCG_BRANCH: u8 = 0x6;
|
||||
|
@ -116,7 +196,7 @@ const OPCG_DIV_OR: u8 = 0x8;
|
|||
const OPCG_SUB: u8 = 0x9;
|
||||
const OPCG_RESERVED1: u8 = 0xA;
|
||||
const OPCG_CMP_EOR: u8 = 0xB;
|
||||
const OPCG_MUL_EXCH: u8 = 0xC;
|
||||
const OPCG_MUL_AND: u8 = 0xC;
|
||||
const OPCG_ADD: u8 = 0xD;
|
||||
const OPCG_SHIFT: u8 = 0xE;
|
||||
const OPCG_RESERVED2: u8 = 0xF;
|
||||
|
@ -195,14 +275,18 @@ impl MC68010 {
|
|||
}
|
||||
|
||||
fn execute_one(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
||||
let addr = self.pc;
|
||||
let ins = self.decode_one(space)?;
|
||||
|
||||
println!("{:08x}: {:?}", addr, ins);
|
||||
match ins {
|
||||
/*
|
||||
Instruction::JSR(target) => {
|
||||
self.push_long(space, self.pc)?;
|
||||
self.pc = self.get_target_value(space, target)?;
|
||||
},
|
||||
_ => panic!(""),
|
||||
*/
|
||||
_ => { /* panic!(""); */ },
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -221,105 +305,423 @@ impl MC68010 {
|
|||
|
||||
match ((ins & 0xF000) >> 12) as u8 {
|
||||
OPCG_BIT_OPS => {
|
||||
panic!("");
|
||||
let optype = (ins & 0x0F00) >> 8;
|
||||
|
||||
if (ins & 0x3F) == 0b111100 {
|
||||
match (ins & 0x00C0) >> 6 {
|
||||
0b00 => {
|
||||
let data = self.read_instruction_word(space)?;
|
||||
match optype {
|
||||
0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
|
||||
0b0001 => Ok(Instruction::ANDtoCCR(data as u8)),
|
||||
0b1010 => Ok(Instruction::EORtoCCR(data as u8)),
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
0b01 => {
|
||||
let data = self.read_instruction_word(space)?;
|
||||
match optype {
|
||||
0b0000 => Ok(Instruction::ORtoSR(data)),
|
||||
0b0001 => Ok(Instruction::ANDtoSR(data)),
|
||||
0b1010 => Ok(Instruction::EORtoSR(data)),
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
|
||||
let bitnum = if (ins & 0x0100) == 0x0100 {
|
||||
Target::DirectDReg(get_high_reg(ins))
|
||||
} else {
|
||||
Target::Immediate(self.read_instruction_word(space)? as u32)
|
||||
};
|
||||
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(Size::Byte))?;
|
||||
let size = match target {
|
||||
Target::DirectAReg(_) | Target::DirectDReg(_) => Size::Long,
|
||||
_ => Size::Byte,
|
||||
};
|
||||
|
||||
match (ins & 0x00C0) >> 6 {
|
||||
0b00 => Ok(Instruction::BTST(bitnum, target, size)),
|
||||
0b01 => Ok(Instruction::BCHG(bitnum, target, size)),
|
||||
0b10 => Ok(Instruction::BCLR(bitnum, target, size)),
|
||||
0b11 => Ok(Instruction::BSET(bitnum, target, size)),
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
|
||||
} else {
|
||||
let size = get_size(ins);
|
||||
let target = self.decode_lower_effective_address(space, ins, size)?;
|
||||
let data = match size {
|
||||
Some(Size::Long) => self.read_instruction_long(space)?,
|
||||
Some(size) => self.read_instruction_word(space)? as u32,
|
||||
None => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
};
|
||||
|
||||
match optype {
|
||||
0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())),
|
||||
0b0010 => Ok(Instruction::AND(Target::Immediate(data), target, size.unwrap())),
|
||||
0b0100 => Ok(Instruction::SUB(Target::Immediate(data), target, size.unwrap())),
|
||||
0b0110 => Ok(Instruction::ADD(Target::Immediate(data), target, size.unwrap())),
|
||||
0b1010 => Ok(Instruction::EOR(Target::Immediate(data), target, size.unwrap())),
|
||||
0b1100 => Ok(Instruction::CMP(Target::Immediate(data), target, size.unwrap())),
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
}
|
||||
},
|
||||
OPCG_MOVE_BYTE => {
|
||||
let data = self.read_instruction_word(space)?;
|
||||
|
||||
panic!("");
|
||||
},
|
||||
OPCG_MOVE_WORD => {
|
||||
let data = self.read_instruction_word(space)?;
|
||||
|
||||
panic!("");
|
||||
let src = self.decode_lower_effective_address(space, ins, Some(Size::Byte))?;
|
||||
let dest = self.decode_upper_effective_address(space, ins, Some(Size::Byte))?;
|
||||
Ok(Instruction::MOVE(src, dest, Size::Byte))
|
||||
},
|
||||
OPCG_MOVE_LONG => {
|
||||
let data = self.read_instruction_long(space)?;
|
||||
|
||||
panic!("");
|
||||
let src = self.decode_lower_effective_address(space, ins, Some(Size::Long))?;
|
||||
let dest = self.decode_upper_effective_address(space, ins, Some(Size::Long))?;
|
||||
Ok(Instruction::MOVE(src, dest, Size::Long))
|
||||
},
|
||||
OPCG_MOVE_WORD => {
|
||||
let src = self.decode_lower_effective_address(space, ins, Some(Size::Word))?;
|
||||
let dest = self.decode_upper_effective_address(space, ins, Some(Size::Word))?;
|
||||
Ok(Instruction::MOVE(src, dest, Size::Word))
|
||||
},
|
||||
OPCG_MISC => {
|
||||
if (ins & 0b111000000) == 0b111000000 {
|
||||
// LEA Instruction
|
||||
|
||||
debug!("LEA");
|
||||
let src = self.decode_lower_effective_address(space, ins)?;
|
||||
if (ins & 0b000101000000) == 0b000100000000 {
|
||||
// CHK Instruction
|
||||
panic!("Not Implemented");
|
||||
} else if (ins & 0b000111000000) == 0b000111000000 {
|
||||
let src = self.decode_lower_effective_address(space, ins, None)?;
|
||||
let dest = get_high_reg(ins);
|
||||
Ok(Instruction::LEA(src, dest))
|
||||
|
||||
} else if (ins & 0b101000000) == 0b100000000 {
|
||||
// CHK Instruction
|
||||
panic!("");
|
||||
} else if (ins & 0b101110000000) == 0b100010000000 {
|
||||
// MOVEM Instruction
|
||||
panic!("");
|
||||
let target = self.decode_lower_effective_address(space, ins, None)?;
|
||||
let data = self.read_instruction_word(space)?;
|
||||
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
|
||||
let dir = if (ins & 0x0200) == 0 { Direction::ToTarget } else { Direction::FromTarget };
|
||||
Ok(Instruction::MOVEM(target, size, dir, data))
|
||||
} else if (ins & 0b100000000000) == 0 {
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(Size::Word))?;
|
||||
match (ins & 0x0700) >> 8 {
|
||||
0b000 => {
|
||||
match get_size(ins) {
|
||||
Some(size) => Ok(Instruction::NEGX(target, size)),
|
||||
None => Ok(Instruction::MOVEfromSR(target)),
|
||||
}
|
||||
},
|
||||
0b010 => {
|
||||
match get_size(ins) {
|
||||
Some(size) => Ok(Instruction::CLR(target, size)),
|
||||
None => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
0b100 => {
|
||||
match get_size(ins) {
|
||||
Some(size) => Ok(Instruction::NEG(target, size)),
|
||||
None => Ok(Instruction::MOVEtoCCR(target)),
|
||||
}
|
||||
},
|
||||
0b110 => {
|
||||
match get_size(ins) {
|
||||
Some(size) => Ok(Instruction::NOT(target, size)),
|
||||
None => Ok(Instruction::MOVEtoSR(target)),
|
||||
}
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
} else if (ins & 0b111100000000) == 0b101000000000 {
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(Size::Word))?;
|
||||
match get_size(ins) {
|
||||
Some(size) => Ok(Instruction::TST(target, size)),
|
||||
None => Ok(Instruction::TAS(target)),
|
||||
}
|
||||
} else if (ins & 0b111100000000) == 0b100000000000 {
|
||||
let subselect = (ins & 0x01C0) >> 6;
|
||||
let mode = get_low_mode(ins);
|
||||
match (subselect, mode) {
|
||||
(0b010, 0b000) => {
|
||||
Ok(Instruction::EXT(get_low_reg(ins), Size::Word))
|
||||
},
|
||||
(0b011, 0b000) => {
|
||||
Ok(Instruction::EXT(get_low_reg(ins), Size::Long))
|
||||
},
|
||||
(0b000, mode) => {
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(Size::Byte))?;
|
||||
Ok(Instruction::NBCD(target))
|
||||
},
|
||||
(0b001, 0b000) => {
|
||||
Ok(Instruction::SWAP(get_low_reg(ins)))
|
||||
},
|
||||
(0b001, mode) => {
|
||||
let target = self.decode_lower_effective_address(space, ins, None)?;
|
||||
Ok(Instruction::PEA(target))
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
} else if (ins & 0b111110000000) == 0b111010000000 {
|
||||
// JMP/JSR Instruction
|
||||
let target = self.decode_lower_effective_address(space, ins)?;
|
||||
let target = self.decode_lower_effective_address(space, ins, None)?;
|
||||
if (ins & 0b01000000) == 0 {
|
||||
Ok(Instruction::JSR(target))
|
||||
} else {
|
||||
Ok(Instruction::JMP(target))
|
||||
}
|
||||
|
||||
} else if (ins & 0b111111110000) == 0b111001010000 {
|
||||
let reg = get_low_reg(ins);
|
||||
if (ins & 0b1000) == 0 {
|
||||
let data = self.read_instruction_word(space)?;
|
||||
Ok(Instruction::LINK(reg, data))
|
||||
} else {
|
||||
Ok(Instruction::UNLK(reg))
|
||||
}
|
||||
} else if (ins & 0b111111110000) == 0b111001100000 {
|
||||
let reg = get_low_reg(ins);
|
||||
let dir = if (ins & 0b1000) == 0 { Direction::FromTarget } else { Direction::ToTarget };
|
||||
Ok(Instruction::MOVEUSP(Target::DirectAReg(reg), dir))
|
||||
} else {
|
||||
|
||||
panic!("");
|
||||
match ins & 0x0FFF {
|
||||
0xAFC => Ok(Instruction::ILLEGAL),
|
||||
0xE70 => Ok(Instruction::RESET),
|
||||
0xE71 => Ok(Instruction::NOP),
|
||||
0xE72 => {
|
||||
let data = self.read_instruction_word(space)?;
|
||||
Ok(Instruction::STOP(data))
|
||||
},
|
||||
0xE73 => Ok(Instruction::RTE),
|
||||
0xE75 => Ok(Instruction::RTS),
|
||||
0xE76 => Ok(Instruction::TRAPV),
|
||||
0xE77 => Ok(Instruction::RTR),
|
||||
0xE7A | 0xE7B => {
|
||||
let dir = if ins & 0x01 == 0 { Direction::ToTarget } else { Direction::FromTarget };
|
||||
let ins2 = self.read_instruction_word(space)?;
|
||||
let target = match ins2 & 0x8000 {
|
||||
0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8),
|
||||
_ => Target::DirectAReg(((ins2 & 0x7000) >> 12) as u8),
|
||||
};
|
||||
let creg = match ins2 & 0xFFF {
|
||||
0x801 => ControlRegister::VBR,
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
};
|
||||
Ok(Instruction::MOVEC(target, creg, dir))
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
}
|
||||
},
|
||||
OPCG_ADDQ_SUBQ => {
|
||||
let size = match get_size(ins) {
|
||||
Some(size) => size,
|
||||
None => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
};
|
||||
|
||||
panic!("");
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
let mut data = ((ins & 0x0E00) >> 9) as u32;
|
||||
if data == 0 {
|
||||
data = 8;
|
||||
}
|
||||
|
||||
if (ins & 0x0100) == 0 {
|
||||
Ok(Instruction::ADD(Target::Immediate(data), target, size))
|
||||
} else {
|
||||
Ok(Instruction::SUB(Target::Immediate(data), target, size))
|
||||
}
|
||||
},
|
||||
OPCG_BRANCH => {
|
||||
|
||||
panic!("");
|
||||
let mut disp = (ins & 0xFF);
|
||||
if disp == 0 {
|
||||
disp = self.read_instruction_word(space)?;
|
||||
}
|
||||
let condition = get_condition(ins);
|
||||
match condition {
|
||||
Condition::True => Ok(Instruction::BRA(disp)),
|
||||
Condition::False => Ok(Instruction::BSR(disp)),
|
||||
_ => Ok(Instruction::Bcc(condition, disp)),
|
||||
}
|
||||
},
|
||||
OPCG_MOVEQ => {
|
||||
|
||||
panic!("");
|
||||
// TODO make sure the 9th bit is 0
|
||||
let reg = get_high_reg(ins);
|
||||
let data = (ins & 0xFF) as u8;
|
||||
Ok(Instruction::MOVEQ(data, reg))
|
||||
},
|
||||
OPCG_DIV_OR => {
|
||||
let size = get_size(ins);
|
||||
|
||||
panic!("");
|
||||
if size.is_none() {
|
||||
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||
let effective_addr = self.decode_lower_effective_address(space, ins, size)?;
|
||||
Ok(Instruction::DIV(effective_addr, data_reg, Size::Word, sign))
|
||||
} else if (ins & 0b000111110000) == 0b000100000000 {
|
||||
// TODO SBCD
|
||||
panic!("Not Implemented");
|
||||
} else {
|
||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||
let effective_addr = self.decode_lower_effective_address(space, ins, size)?;
|
||||
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
||||
Ok(Instruction::OR(from, to, size.unwrap()))
|
||||
}
|
||||
},
|
||||
OPCG_SUB => {
|
||||
|
||||
panic!("");
|
||||
// TODO need to decode the SUBX instruction (would likely be erroneously decoded atm)
|
||||
let reg = get_high_reg(ins);
|
||||
let dir = (ins & 0x0100) >> 8;
|
||||
let size = get_size(ins);
|
||||
match size {
|
||||
Some(size) => {
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
if dir == 0 {
|
||||
Ok(Instruction::SUB(target, Target::DirectDReg(reg), size))
|
||||
} else {
|
||||
Ok(Instruction::SUB(Target::DirectDReg(reg), target, size))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let size = if dir == 0 { Size::Word } else { Size::Long };
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
Ok(Instruction::SUB(target, Target::DirectAReg(reg), size))
|
||||
},
|
||||
}
|
||||
},
|
||||
OPCG_CMP_EOR => {
|
||||
|
||||
panic!("");
|
||||
let reg = get_high_reg(ins);
|
||||
let optype = (ins & 0x0100) >> 8;
|
||||
let size = get_size(ins);
|
||||
match (optype, size) {
|
||||
(0b1, Some(size)) => {
|
||||
// TODO need to decode the CMPM instruction (mode == 0b001) (would likely be erroneously decoded atm)
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
Ok(Instruction::EOR(Target::DirectDReg(reg), target, size))
|
||||
},
|
||||
(0b0, Some(size)) => {
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
Ok(Instruction::CMP(Target::DirectDReg(reg), target, size))
|
||||
},
|
||||
(size, None) => {
|
||||
let size = if optype == 0 { Size::Word } else { Size::Long };
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
Ok(Instruction::CMP(target, Target::DirectAReg(reg), size))
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
OPCG_MUL_EXCH => {
|
||||
OPCG_MUL_AND => {
|
||||
let size = get_size(ins);
|
||||
|
||||
panic!("");
|
||||
if size.is_none() {
|
||||
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||
let effective_addr = self.decode_lower_effective_address(space, ins, size)?;
|
||||
Ok(Instruction::MUL(effective_addr, data_reg, Size::Word, sign))
|
||||
} else if (ins & 0b000111110000) == 0b000100000000 {
|
||||
// TODO ABCD or EXG
|
||||
panic!("Not Implemented");
|
||||
} else {
|
||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||
let effective_addr = self.decode_lower_effective_address(space, ins, size)?;
|
||||
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
||||
Ok(Instruction::AND(from, to, size.unwrap()))
|
||||
}
|
||||
},
|
||||
OPCG_ADD => {
|
||||
|
||||
panic!("");
|
||||
// TODO need to decode the ADDX instruction (would likely be erroneously decoded atm)
|
||||
let reg = get_high_reg(ins);
|
||||
let dir = (ins & 0x0100) >> 8;
|
||||
let size = get_size(ins);
|
||||
match size {
|
||||
Some(size) => {
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
if dir == 0 {
|
||||
Ok(Instruction::ADD(target, Target::DirectDReg(reg), size))
|
||||
} else {
|
||||
Ok(Instruction::ADD(Target::DirectDReg(reg), target, size))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let size = if dir == 0 { Size::Word } else { Size::Long };
|
||||
let target = self.decode_lower_effective_address(space, ins, Some(size))?;
|
||||
Ok(Instruction::ADD(target, Target::DirectAReg(reg), size))
|
||||
},
|
||||
}
|
||||
},
|
||||
OPCG_SHIFT => {
|
||||
let dir = if (ins & 0x0100) == 0 { ShiftDirection::Right } else { ShiftDirection::Left };
|
||||
match get_size(ins) {
|
||||
Some(size) => {
|
||||
let reg = get_low_reg(ins);
|
||||
let rotation = get_high_reg(ins);
|
||||
let count = if (ins & 0x0020) == 0 {
|
||||
Target::Immediate(rotation as u32)
|
||||
} else {
|
||||
Target::DirectDReg(rotation)
|
||||
};
|
||||
|
||||
panic!("");
|
||||
match (ins & 0x0018) >> 3 {
|
||||
0b00 => Ok(Instruction::ASd(count, Target::DirectDReg(reg), size, dir)),
|
||||
0b01 => Ok(Instruction::LSd(count, Target::DirectDReg(reg), size, dir)),
|
||||
0b10 => Ok(Instruction::ROXd(count, Target::DirectDReg(reg), size, dir)),
|
||||
0b11 => Ok(Instruction::ROd(count, Target::DirectDReg(reg), size, dir)),
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let target = self.decode_lower_effective_address(space, 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(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_lower_effective_address(&mut self, space: &mut AddressSpace, ins: u16) -> Result<Target, Error> {
|
||||
fn decode_lower_effective_address(&mut self, space: &mut AddressSpace, ins: u16, size: Option<Size>) -> Result<Target, Error> {
|
||||
let reg = get_low_reg(ins);
|
||||
let mode = get_mode(ins);
|
||||
self.get_mode_as_target(space, mode, reg)
|
||||
let mode = get_low_mode(ins);
|
||||
self.get_mode_as_target(space, mode, reg, size)
|
||||
}
|
||||
|
||||
fn get_mode_as_target(&mut self, space: &mut AddressSpace, mode: u8, reg: u8) -> Result<Target, Error> {
|
||||
fn decode_upper_effective_address(&mut self, space: &mut AddressSpace, ins: u16, size: Option<Size>) -> Result<Target, Error> {
|
||||
let reg = get_high_reg(ins);
|
||||
let mode = get_high_mode(ins);
|
||||
self.get_mode_as_target(space, mode, reg, size)
|
||||
}
|
||||
|
||||
fn decode_brief_extension_word(&self, brief_extension: u16) -> (Target, u16, Size) {
|
||||
let data = brief_extension & 0x00FF;
|
||||
let reg = ((brief_extension & 0x7000) >> 12) as u8;
|
||||
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
|
||||
|
||||
let target = if (brief_extension & 0x8000) == 0 {
|
||||
Target::DirectDReg(reg)
|
||||
} else {
|
||||
Target::DirectAReg(reg)
|
||||
};
|
||||
|
||||
(target, data, size)
|
||||
}
|
||||
|
||||
fn get_mode_as_target(&mut self, space: &mut AddressSpace, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
|
||||
let value = match mode {
|
||||
0b000 => Target::DirectDReg(reg),
|
||||
0b001 => Target::DirectAReg(reg),
|
||||
0b010 => Target::IndirectAReg(reg),
|
||||
0b011 => Target::IndirectARegInc(reg),
|
||||
0b100 => Target::IndirectARegDec(reg),
|
||||
0b101 => {
|
||||
let d16 = self.read_instruction_word(space)?;
|
||||
Target::IndirectARegOffset(reg, d16)
|
||||
},
|
||||
0b110 => {
|
||||
let brief_extension = self.read_instruction_word(space)?;
|
||||
let (target, data, size) = self.decode_brief_extension_word(brief_extension);
|
||||
Target::IndirectARegXRegOffset(reg, Box::new(target), data, size)
|
||||
},
|
||||
0b111 => {
|
||||
match reg {
|
||||
0b000 => {
|
||||
|
@ -334,6 +736,19 @@ panic!("");
|
|||
let d16 = self.read_instruction_word(space)?;
|
||||
Target::IndirectPCOffset(d16)
|
||||
},
|
||||
0b011 => {
|
||||
let brief_extension = self.read_instruction_word(space)?;
|
||||
let (target, data, size) = self.decode_brief_extension_word(brief_extension);
|
||||
Target::IndirectPCXRegOffset(Box::new(target), data, size)
|
||||
},
|
||||
0b100 => {
|
||||
let data = match size {
|
||||
Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word(space)? as u32,
|
||||
Some(Size::Long) => self.read_instruction_long(space)?,
|
||||
None => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
};
|
||||
Target::Immediate(data)
|
||||
},
|
||||
_ => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)),
|
||||
}
|
||||
},
|
||||
|
@ -341,11 +756,12 @@ panic!("");
|
|||
};
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_high_reg(ins: u16) -> u8 {
|
||||
((ins & 0x0D00) >> 9) as u8
|
||||
((ins & 0x0E00) >> 9) as u8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -354,10 +770,49 @@ fn get_low_reg(ins: u16) -> u8 {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_mode(ins: u16) -> u8 {
|
||||
fn get_high_mode(ins: u16) -> u8 {
|
||||
((ins & 0x01C0) >> 6) as u8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_low_mode(ins: u16) -> u8 {
|
||||
((ins & 0x0038) >> 3) as u8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_size(ins: u16) -> Option<Size> {
|
||||
match (ins & 0x00C0) >> 6 {
|
||||
0b00 => Some(Size::Byte),
|
||||
0b01 => Some(Size::Word),
|
||||
0b10 => Some(Size::Long),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_condition(ins: u16) -> Condition {
|
||||
match (ins & 0x0F00) >> 8 {
|
||||
0b0000 => Condition::True,
|
||||
0b0001 => Condition::False,
|
||||
0b0010 => Condition::High,
|
||||
0b0011 => Condition::LowOrSame,
|
||||
0b0100 => Condition::CarryClear,
|
||||
0b0101 => Condition::CarrySet,
|
||||
0b0110 => Condition::NotEqual,
|
||||
0b0111 => Condition::Equal,
|
||||
0b1000 => Condition::OverflowClear,
|
||||
0b1001 => Condition::OverflowSet,
|
||||
0b1010 => Condition::Plus,
|
||||
0b1011 => Condition::Minus,
|
||||
0b1100 => Condition::GreaterThanOrEqual,
|
||||
0b1101 => Condition::LessThan,
|
||||
0b1110 => Condition::GreaterThan,
|
||||
0b1111 => Condition::LessThanOrEqual,
|
||||
|
||||
_ => Condition::True,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl Processor for MC68010 {
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ impl AddressSpace {
|
|||
return Ok(&self.segments[i]);
|
||||
}
|
||||
}
|
||||
return Err(Error::new("No segment found"));
|
||||
return Err(Error::new(&format!("No segment found at {:08x}", addr)));
|
||||
}
|
||||
|
||||
pub fn get_segment_mut(&mut self, addr: Address) -> Result<&mut Segment, Error> {
|
||||
|
@ -84,7 +84,7 @@ impl AddressSpace {
|
|||
return Ok(&mut self.segments[i]);
|
||||
}
|
||||
}
|
||||
return Err(Error::new("No segment found"));
|
||||
return Err(Error::new(&format!("No segment found at {:08x}", addr)));
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user