diff --git a/src/cpus/m68k/decode.rs b/src/cpus/m68k/decode.rs index 940af3d..73dbaac 100644 --- a/src/cpus/m68k/decode.rs +++ b/src/cpus/m68k/decode.rs @@ -115,7 +115,7 @@ pub enum Instruction { CMP(Target, Target, Size), CMPA(Target, u8, Size), - DBcc(Condition, i16), + DBcc(Condition, u8, i16), DIV(Target, Target, Size, Sign), EOR(Target, Target, Size), @@ -165,7 +165,7 @@ pub enum Instruction { RTS, //SBCD - //Scc + Scc(Condition, Target), STOP(u16), SUB(Target, Target, Size), SWAP(u8), @@ -252,12 +252,13 @@ impl M68kDecoder { } else { let size = get_size(ins); - let target = self.decode_lower_effective_address(space, ins, size)?; let data = match size { + Some(Size::Byte) => (self.read_instruction_word(space)? as u32 & 0xFF), + Some(Size::Word) => self.read_instruction_word(space)? as u32, Some(Size::Long) => self.read_instruction_long(space)?, - Some(_) => self.read_instruction_word(space)? as u32, None => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)), }; + let target = self.decode_lower_effective_address(space, ins, size)?; match optype { 0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())), @@ -337,8 +338,8 @@ impl M68kDecoder { if mode == 0b000 { Ok(Instruction::EXT(get_low_reg(ins), size)) } else { - let target = self.decode_lower_effective_address(space, ins, None)?; let data = self.read_instruction_word(space)?; + let target = self.decode_lower_effective_address(space, ins, None)?; let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget }; Ok(Instruction::MOVEM(target, size, dir, data)) } @@ -417,21 +418,33 @@ impl M68kDecoder { } }, OPCG_ADDQ_SUBQ => { - let size = match get_size(ins) { - Some(size) => size, - None => return Err(Error::processor(ERR_ILLEGAL_INSTRUCTION)), - }; + match get_size(ins) { + Some(size) => { + let target = self.decode_lower_effective_address(space, ins, Some(size))?; + let mut data = ((ins & 0x0E00) >> 9) as u32; + if data == 0 { + data = 8; + } - 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)) + } + }, + None => { + let mode = get_low_mode(ins); + let condition = get_condition(ins); - if (ins & 0x0100) == 0 { - Ok(Instruction::ADD(Target::Immediate(data), target, size)) - } else { - Ok(Instruction::SUB(Target::Immediate(data), target, size)) + if mode == 0b001 { + let reg = get_low_reg(ins); + let disp = self.read_instruction_word(space)? as i16; + Ok(Instruction::DBcc(condition, reg, disp)) + } else { + let target = self.decode_lower_effective_address(space, ins, Some(Size::Byte))?; + Ok(Instruction::Scc(condition, target)) + } + }, } }, OPCG_BRANCH => { diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index 20117a1..3642edb 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -8,6 +8,7 @@ use super::decode::{ Instruction, Target, Size, + Sign, Direction, Condition, ShiftDirection, @@ -140,7 +141,7 @@ impl MC68010 { } } - pub(crate) fn decode_next(&mut self, space: &mut AddressSpace) -> Result<(), Error> { + pub fn decode_next(&mut self, space: &mut AddressSpace) -> Result<(), Error> { self.check_breakpoints(); self.decoder = M68kDecoder::decode_at(space, self.state.pc)?; @@ -162,23 +163,16 @@ impl MC68010 { Ok(()) } - pub(crate) fn execute_current(&mut self, space: &mut AddressSpace) -> Result<(), Error> { + pub fn execute_current(&mut self, space: &mut AddressSpace) -> Result<(), Error> { match self.decoder.instruction { Instruction::ADD(src, dest, size) => { let value = self.get_target_value(space, src, size)?; let existing = self.get_target_value(space, dest, size)?; - let (result, overflow) = match size { - Size::Byte => { - let (result, overflow) = (existing as u8).overflowing_add(value as u8); - (result as u32, overflow) - }, - Size::Word => { - let (result, overflow) = (existing as u16).overflowing_add(value as u16); - (result as u32, overflow) - }, - Size::Long => existing.overflowing_add(value), - }; - self.set_compare_flags(result, size, overflow); + let (result, carry) = overflowing_add_sized(existing, value, size); + match dest { + Target::DirectAReg(_) => { }, + _ => self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size)), + } self.set_target_value(space, dest, result, size)?; }, Instruction::AND(src, dest, size) => { @@ -200,7 +194,7 @@ impl MC68010 { for _ in 0..count { pair = shift_operation(pair.0, size, shift_dir, true); } - self.set_compare_flags(pair.0, size, false); + self.set_logic_flags(pair.0, size); if pair.1 { self.state.sr |= FLAGS_EXTEND | FLAGS_CARRY; } @@ -256,17 +250,38 @@ impl MC68010 { Instruction::CMP(src, dest, size) => { let value = self.get_target_value(space, src, size)?; let existing = self.get_target_value(space, dest, size)?; - let result = self.subtract_sized_with_flags(existing, value, size); + let (result, carry) = overflowing_sub_sized(existing, value, size); + self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size)); }, Instruction::CMPA(src, reg, size) => { let value = self.get_target_value(space, src, size)?; let existing = sign_extend_to_long(*self.get_a_reg_mut(reg), size) as u32; - let result = self.subtract_sized_with_flags(existing, value, Size::Long); + let (result, carry) = overflowing_sub_sized(existing, value, Size::Long); + self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, Size::Long)); + }, + Instruction::DBcc(cond, reg, offset) => { + let condition_true = self.get_current_condition(cond); + if !condition_true { + let next = (get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16 - 1; + set_value_sized(&mut self.state.d_reg[reg as usize], next as u32, Size::Word); + if next != -1 { + self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32); + } + } + }, + Instruction::DIV(src, dest, size, sign) => { + if size == Size::Long { + return Err(Error::new("Unsupported multiplication size")); + } + + let value = self.get_target_value(space, src, size)?; + let existing = self.get_target_value(space, dest, Size::Long)?; + let result = match sign { + Sign::Signed => ((existing as i16 % value as i16) as u32) << 16 | (0xFFFF & (existing as i16 / value as i16) as u32), + Sign::Unsigned => ((existing as u16 % value as u16) as u32) << 16 | (0xFFFF & (existing as u16 / value as u16) as u32), + }; + self.set_target_value(space, dest, result, Size::Long)?; }, - //Instruction::DBcc(Condition, u16) => { - //}, - //Instruction::DIV(Target, Target, Size, Sign) => { - //}, Instruction::EOR(src, dest, size) => { let value = self.get_target_value(space, src, size)?; let existing = self.get_target_value(space, dest, size)?; @@ -288,7 +303,8 @@ impl MC68010 { Size::Word => ((byte as i16) as u16) as u32, Size::Long => (byte as i32) as u32, }; - self.state.d_reg[reg as usize] = result; + set_value_sized(&mut self.state.d_reg[reg as usize], result, size); + self.set_logic_flags(result, size); }, //Instruction::ILLEGAL => { //}, @@ -318,7 +334,7 @@ impl MC68010 { for _ in 0..count { pair = shift_operation(pair.0, size, shift_dir, false); } - self.set_compare_flags(pair.0, size, false); + self.set_logic_flags(pair.0, size); if pair.1 { self.state.sr |= FLAGS_EXTEND | FLAGS_CARRY; } @@ -326,13 +342,14 @@ impl MC68010 { }, Instruction::MOVE(src, dest, size) => { let value = self.get_target_value(space, src, size)?; - self.set_compare_flags(value, size, false); + self.set_logic_flags(value, size); self.set_target_value(space, dest, value, size)?; }, Instruction::MOVEA(src, reg, size) => { let value = self.get_target_value(space, src, size)?; + let value = sign_extend_to_long(value, size) as u32; let addr = self.get_a_reg_mut(reg); - *addr = sign_extend_to_long(value, size) as u32; + *addr = value; }, Instruction::MOVEfromSR(target) => { self.set_target_value(space, target, self.state.sr as u32, Size::Word)?; @@ -404,14 +421,29 @@ impl MC68010 { 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_compare_flags(value, Size::Long, false); + self.set_logic_flags(value, Size::Long); + }, + Instruction::MUL(src, dest, size, sign) => { + if size == Size::Long { + return Err(Error::new("Unsupported multiplication size")); + } + + let value = self.get_target_value(space, src, size)?; + let existing = self.get_target_value(space, dest, size)?; + let result = match sign { + Sign::Signed => (sign_extend_to_long(existing, Size::Word) * sign_extend_to_long(value, Size::Word)) as u32, + Sign::Unsigned => existing as u32 * value as u32, + }; + self.set_target_value(space, dest, result, Size::Long)?; }, - //Instruction::MUL(Target, Target, Size, Sign) => { - //}, //Instruction::NBCD(Target) => { //}, - //Instruction::NEG(Target, Size) => { - //}, + Instruction::NEG(target, size) => { + let original = self.get_target_value(space, target, size)?; + let (value, _) = (0 as u32).overflowing_sub(original); + self.set_target_value(space, target, value, size); + self.set_compare_flags(value, size, value != 0, get_overflow(0, original, value, size)); + }, //Instruction::NEGX(Target, Size) => { //}, Instruction::NOP => { }, @@ -450,12 +482,24 @@ impl MC68010 { Instruction::RTS => { self.state.pc = self.pop_long(space)?; }, + Instruction::Scc(cond, target) => { + let condition_true = self.get_current_condition(cond); + if condition_true { + self.set_target_value(space, target, 0xFF, Size::Byte); + } else { + self.set_target_value(space, target, 0x00, Size::Byte); + } + }, //Instruction::STOP(u16) => { //}, Instruction::SUB(src, dest, size) => { let value = self.get_target_value(space, src, size)?; let existing = self.get_target_value(space, dest, size)?; - let result = self.subtract_sized_with_flags(existing, value, size); + let (result, carry) = overflowing_sub_sized(existing, value, size); + match dest { + Target::DirectAReg(_) => { }, + _ => self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size)), + } self.set_target_value(space, dest, result, size)?; }, Instruction::SWAP(reg) => { @@ -466,7 +510,7 @@ impl MC68010 { //}, Instruction::TST(target, size) => { let value = self.get_target_value(space, target, size)?; - self.set_compare_flags(value, size, false); + self.set_logic_flags(value, size); }, //Instruction::TRAP(u8) => { //}, @@ -479,7 +523,7 @@ impl MC68010 { let addr = self.get_a_reg_mut(reg); *addr = new_value; }, - _ => { panic!(""); }, + _ => { panic!("Unsupported instruction"); }, } Ok(()) @@ -524,9 +568,7 @@ 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); - 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 + get_address_sized(space, (*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) as Address, size) }, Target::IndirectMemory(addr) => { get_address_sized(space, addr as Address, size) @@ -606,22 +648,6 @@ println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_a Ok(addr) } - fn subtract_sized_with_flags(&mut self, existing: u32, diff: u32, size: Size) -> u32 { - let (result, overflow) = match size { - Size::Byte => { - let (result, overflow) = (existing as u8).overflowing_sub(diff as u8); - (result as u32, overflow) - }, - Size::Word => { - let (result, overflow) = (existing as u16).overflowing_sub(diff as u16); - (result as u32, overflow) - }, - Size::Long => existing.overflowing_sub(diff), - }; - self.set_compare_flags(result, size, overflow); - result - } - fn get_control_reg_mut(&mut self, control_reg: ControlRegister) -> &mut u32 { match control_reg { ControlRegister::VBR => &mut self.state.vbr, @@ -645,7 +671,7 @@ println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_a fn get_x_reg_value(&self, rtype: RegisterType, reg: u8) -> u32 { match rtype { RegisterType::Data => self.state.d_reg[reg as usize], - RegisterType::Address => self.state.d_reg[reg as usize], + RegisterType::Address => self.state.a_reg[reg as usize], } } @@ -661,7 +687,7 @@ println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_a } } - fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool) { + fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool, overflow: bool) { let value = sign_extend_to_long(value, size); let mut flags = 0x0000; @@ -672,7 +698,10 @@ println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_a flags |= FLAGS_ZERO } if carry { - flags |= FLAGS_CARRY | FLAGS_OVERFLOW; + flags |= FLAGS_CARRY; + } + if overflow { + flags |= FLAGS_OVERFLOW; } self.state.sr = (self.state.sr & 0xFFF0) | flags; } @@ -685,7 +714,7 @@ println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_a if value == 0 { flags |= FLAGS_ZERO } - self.state.sr |= (self.state.sr & 0xFFF0) | flags; + self.state.sr = (self.state.sr & 0xFFF0) | flags; } fn set_bit_test_flags(&mut self, value: u32, bitnum: u32, size: Size) -> u32 { @@ -723,6 +752,52 @@ println!(">>> {:x} has {:x}", (*addr).wrapping_add(reg_offset as u32).wrapping_a } } + +fn overflowing_add_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) { + match size { + Size::Byte => { + let (result, carry) = (operand1 as u8).overflowing_add(operand2 as u8); + (result as u32, carry) + }, + Size::Word => { + let (result, carry) = (operand1 as u16).overflowing_add(operand2 as u16); + (result as u32, carry) + }, + Size::Long => operand1.overflowing_add(operand2), + } +} + +fn overflowing_sub_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) { + match size { + Size::Byte => { + let (result, carry) = (operand1 as u8).overflowing_sub(operand2 as u8); + (result as u32, carry) + }, + Size::Word => { + let (result, carry) = (operand1 as u16).overflowing_sub(operand2 as u16); + (result as u32, carry) + }, + Size::Long => operand1.overflowing_sub(operand2), + } +} + +fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) { + match dir { + ShiftDirection::Left => { + match size { + 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_value_sized(value: u32, size: Size) -> u32 { match size { Size::Byte => { 0x000000FF & value }, @@ -755,20 +830,12 @@ fn set_address_sized(space: &mut AddressSpace, addr: Address, value: u32, size: } } -fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) { - match dir { - ShiftDirection::Left => { - match size { - 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_overflow(operand1: u32, operand2: u32, result: u32, size: Size) -> bool { + let msb1 = get_msb(operand1, size); + let msb2 = get_msb(operand2, size); + let msb_res = get_msb(result, size); + + msb1 && msb2 && !msb_res } fn get_msb(value: u32, size: Size) -> bool { diff --git a/src/cpus/m68k/mod.rs b/src/cpus/m68k/mod.rs index e651a3c..bddb9f1 100644 --- a/src/cpus/m68k/mod.rs +++ b/src/cpus/m68k/mod.rs @@ -1,8 +1,8 @@ -mod decode; -mod execute; -mod debugger; -mod tests; +pub mod decode; +pub mod execute; +pub mod debugger; +pub mod tests; pub use self::execute::MC68010; diff --git a/src/cpus/m68k/tests.rs b/src/cpus/m68k/tests.rs index bcfb115..d9a0835 100644 --- a/src/cpus/m68k/tests.rs +++ b/src/cpus/m68k/tests.rs @@ -95,5 +95,17 @@ mod tests { cpu.execute_current(&mut space).unwrap(); assert_eq!(cpu.state.sr & 0x0F, 0x00); } + + #[test] + fn instruction_movel() { + let (mut cpu, mut space) = init_test(); + + space.write_beu16(INIT_ADDR, 0x2F49).unwrap(); + space.write_beu16(INIT_ADDR + 2, 0x0034).unwrap(); + cpu.decode_next(&mut space).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::MOVE(Target::DirectAReg(0x01), Target::IndirectARegOffset(7, 52), Size::Long)); + //cpu.execute_current(&mut space).unwrap(); + //assert_eq!(cpu.state.sr & 0x0F, 0x00); + } } diff --git a/src/main.rs b/src/main.rs index edd551a..193bcea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,13 +25,11 @@ fn main() { space.insert(0x00700000, Box::new(serial)); let mut cpu = MC68010::new(); - //cpu.add_breakpoint(0x07f8); - //cpu.add_breakpoint(0x0836); - //cpu.add_breakpoint(0x0838); - //cpu.add_breakpoint(0x0ea0); + //cpu.enable_tracing(); + + //cpu.add_breakpoint(0x0c94); + //cpu.add_breakpoint(0x0cf2); - cpu.add_breakpoint(0x0034); - cpu.enable_tracing(); while cpu.is_running() { match cpu.step(&mut space) { Ok(()) => { }, @@ -44,9 +42,9 @@ fn main() { //serial.step(); } - // TODO I need to add a way to decode and dump the assembly for a section of code, in debugger /* - cpu.state.pc = 0x07f8; + // TODO I need to add a way to decode and dump the assembly for a section of code, in debugger + cpu.state.pc = 0x0db4; while cpu.is_running() { cpu.decode_next(&mut space).unwrap(); } diff --git a/src/memory.rs b/src/memory.rs index 109d2e8..8aefe7a 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -111,6 +111,7 @@ impl AddressSpace { pub fn dump_memory(&mut self, mut addr: Address, mut count: Address) { while count > 0 { let mut line = format!("{:#010x}: ", addr); + let to = if count < 16 { count / 2 } else { 8 }; for i in 0..to { let word = self.read_beu16(addr);