Added MOVEP and more tests to m68k and IM to z80

This commit is contained in:
transistor 2021-11-15 20:52:19 -08:00
parent 1d8065026d
commit a342ef3b86
7 changed files with 164 additions and 21 deletions

View File

@ -104,8 +104,8 @@ impl M68kDecoder {
let areg = get_low_reg(ins);
let dir = if (ins & 0x0800) == 0 { Direction::FromTarget } else { Direction::ToTarget };
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
let offset = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Ok(Instruction::MOVEP(dreg, Target::IndirectRegOffset(BaseRegister::AReg(areg), None, offset), size, dir))
let offset = self.read_instruction_word(memory)? as i16;
Ok(Instruction::MOVEP(dreg, areg, offset, size, dir))
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
let bitnum = if (ins & 0x0100) == 0x0100 {
Target::DirectDReg(get_high_reg(ins))

View File

@ -507,8 +507,32 @@ impl M68k {
Instruction::MOVEM(target, size, dir, mask) => {
self.execute_movem(target, size, dir, mask)?;
},
//Instruction::MOVEP(reg, target, size, dir) => {
//},
Instruction::MOVEP(dreg, areg, offset, size, dir) => {
match dir {
Direction::ToTarget => {
let mut shift = (size.in_bytes() as i32 * 8) - 8;
let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address;
while shift >= 0 {
let byte = (self.state.d_reg[dreg as usize] >> shift) as u8;
let data = if (addr & 0x1) == 0 { (byte as u16) << 8 } else { byte as u16 };
self.port.write_beu16(addr, data)?;
addr += 2;
shift -= 8;
}
},
Direction::FromTarget => {
let mut shift = (size.in_bytes() as i32 * 8) - 8;
let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address;
while shift >= 0 {
let data = self.port.read_beu16(addr)?;
let byte = if (addr & 0x1) == 0 { (data >> 8) as u8 } else { data as u8 };
self.state.d_reg[dreg as usize] |= (byte as u32) << shift;
addr += 2;
shift -= 8;
}
},
}
},
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;

View File

@ -154,7 +154,7 @@ pub enum Instruction {
MOVEtoCCR(Target),
MOVEC(Target, ControlRegister, Direction),
MOVEM(Target, Size, Direction, u16),
MOVEP(Register, Target, Size, Direction),
MOVEP(Register, Register, i16, Size, Direction),
MOVEQ(u8, Register),
MOVEUSP(Target, Direction),
MULW(Target, Register, Sign),
@ -406,9 +406,9 @@ 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) => match dir {
Direction::ToTarget => write!(f, "movep{}\t%d{}, {}", size, reg, target),
Direction::FromTarget => write!(f, "movep{}\t{}, %d{}", size, target, reg),
Instruction::MOVEP(dreg, areg, offset, size, dir) => match dir {
Direction::ToTarget => write!(f, "movep{}\t%d{}, ({}, %a{})", size, dreg, areg, offset),
Direction::FromTarget => write!(f, "movep{}\t({}, %a{}), %d{}", size, areg, offset, dreg),
},
Instruction::MOVEQ(value, reg) => write!(f, "moveq\t#{:02x}, %d{}", value, reg),
Instruction::MOVEUSP(target, dir) => match dir {

View File

@ -490,6 +490,22 @@ mod execute_tests {
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000004, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2717 },
},
TestCase {
name: "adda immediate",
ins: Instruction::ADDA(Target::Immediate(0xF800), 0, Size::Word),
data: &[ 0xD0FC, 0xF800 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF },
fini: TestState { pc: 0x00000004, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0xFFFFF800, a1: 0x00000000, sr: 0x27FF },
},
TestCase {
name: "adda register",
ins: Instruction::ADDA(Target::DirectDReg(0), 0, Size::Word),
data: &[ 0xD0C0 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x0000F800, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0x0000F800, d1: 0x00000000, a0: 0xFFFFF800, a1: 0x00000000, sr: 0x27FF },
},
TestCase {
name: "andi with sr",
ins: Instruction::ANDtoSR(0xF8FF),
@ -530,6 +546,30 @@ mod execute_tests {
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
},
TestCase {
name: "bchg not zero",
ins: Instruction::BCHG(Target::Immediate(7), Target::DirectDReg(1), Size::Long),
data: &[ 0x0841, 0x0007 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x000000FF, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000004, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
},
TestCase {
name: "bchg zero",
ins: Instruction::BCHG(Target::Immediate(7), Target::DirectDReg(1), Size::Long),
data: &[ 0x0841, 0x0007 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000004, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000080, a0: 0x00000000, a1: 0x00000000, sr: 0x2704 },
},
TestCase {
name: "bra 8-bit",
ins: Instruction::BRA(-32),
data: &[ 0x60E0 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0xFFFFFFE2, msp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
},
TestCase {
name: "cmpi equal",
ins: Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte),
@ -610,6 +650,38 @@ mod execute_tests {
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00040000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000004, msp: 0x00000000, usp: 0x00000000, d0: 0x007101C3, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
},
TestCase {
name: "eori",
ins: Instruction::EOR(Target::DirectDReg(1), Target::DirectDReg(0), Size::Long),
data: &[ 0xB380 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0xAAAA5555, d1: 0x55AA55AA, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0xFF0000FF, d1: 0x55AA55AA, a0: 0x00000000, a1: 0x00000000, sr: 0x2708 },
},
TestCase {
name: "exg",
ins: Instruction::EXG(Target::DirectDReg(0), Target::DirectAReg(1)),
data: &[ 0xC189 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x12345678, d1: 0x00000000, a0: 0x00000000, a1: 0x87654321, sr: 0x2700 },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0x87654321, d1: 0x00000000, a0: 0x00000000, a1: 0x12345678, sr: 0x2700 },
},
TestCase {
name: "ext",
ins: Instruction::EXT(0, Size::Byte, Size::Word),
data: &[ 0x4880 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x000000CB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0x0000FFCB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27F8 },
},
TestCase {
name: "ext",
ins: Instruction::EXT(0, Size::Word, Size::Long),
data: &[ 0x48C0 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x000000CB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0x000000CB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27F0 },
},
TestCase {
name: "muls",
ins: Instruction::MULW(Target::Immediate(0x0276), 0, Sign::Signed),
@ -618,6 +690,22 @@ mod execute_tests {
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0x00000200, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000004, msp: 0x00000000, usp: 0x00000000, d0: 0x0004ec00, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
},
TestCase {
name: "movel",
ins: Instruction::MOVE(Target::DirectDReg(0), Target::DirectDReg(1), Size::Long),
data: &[ 0x2200 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0xFEDCBA98, a0: 0x00000000, a1: 0x00000000, sr: 0x2708 },
},
TestCase {
name: "movea",
ins: Instruction::MOVEA(Target::DirectDReg(0), 0, Size::Long),
data: &[ 0x2040 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, msp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700 },
fini: TestState { pc: 0x00000002, msp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0x00000000, a0: 0xFEDCBA98, a1: 0x00000000, sr: 0x2700 },
},
TestCase {
name: "neg",
ins: Instruction::NEG(Target::DirectDReg(0), Size::Word),

View File

@ -2,7 +2,7 @@
use crate::error::Error;
use crate::devices::{Address, Addressable};
use super::state::Register;
use super::state::{Register, InterruptMode};
#[derive(Copy, Clone, Debug, PartialEq)]
@ -114,7 +114,7 @@ pub enum Instruction {
EXhlde,
EXsp(RegisterPair),
HALT,
IM(u8),
IM(InterruptMode),
INC16(RegisterPair),
INC8(Target),
IND,
@ -453,7 +453,13 @@ impl Z80Decoder {
}
},
6 => {
Ok(Instruction::IM(get_ins_y(ins)))
match get_ins_y(ins) & 0x03 {
0 => Ok(Instruction::IM(InterruptMode::Mode0)),
1 => Ok(Instruction::IM(InterruptMode::Mode01)),
2 => Ok(Instruction::IM(InterruptMode::Mode1)),
3 => Ok(Instruction::IM(InterruptMode::Mode2)),
_ => panic!("InternalError: impossible value"),
}
},
7 => {
match get_ins_y(ins) {

View File

@ -3,7 +3,7 @@ use crate::system::System;
use crate::error::{ErrorType, Error};
use crate::devices::{ClockElapsed, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16};
use super::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair, IndexRegister, IndexRegisterHalf, Size};
use super::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair, IndexRegister, SpecialRegister, IndexRegisterHalf, Size, Direction};
use super::state::{Z80, Status, Flags, Register};
@ -22,7 +22,11 @@ enum RotateType {
impl Steppable for Z80 {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
self.step_internal(system)?;
if self.reset.get() {
self.reset();
} else if !self.bus_request.get() {
self.step_internal(system)?;
}
Ok((1_000_000_000 / self.frequency as u64) * 4)
}
@ -258,8 +262,9 @@ impl Z80 {
Instruction::HALT => {
self.state.status = Status::Halted;
},
//Instruction::IM(u8) => {
//},
Instruction::IM(mode) => {
self.state.interrupt_mode = mode;
},
Instruction::INC16(regpair) => {
let value = self.get_register_pair_value(regpair);
@ -313,8 +318,17 @@ impl Z80 {
let src_value = self.get_load_target_value(src)?;
self.set_load_target_value(dest, src_value)?;
},
//Instruction::LDsr(special_reg, dir) => {
//}
Instruction::LDsr(special_reg, dir) => {
let addr = match special_reg {
SpecialRegister::I => &mut self.state.i,
SpecialRegister::R => &mut self.state.r,
};
match dir {
Direction::FromAcc => { *addr = self.state.reg[Register::A as usize]; },
Direction::ToAcc => { self.state.reg[Register::A as usize] = *addr; },
}
}
//Instruction::LDD => {
//},
//Instruction::LDDR => {
@ -642,8 +656,6 @@ impl Z80 {
let addr = self.get_register_pair_value(regpair);
self.port.read_leu16(addr as Address)?
},
//LoadTarget::DirectAltRegByte(reg),
//LoadTarget::DirectSpecialRegByte(reg),
LoadTarget::IndirectByte(addr) => {
self.port.read_u8(addr as Address)? as u16
},
@ -674,8 +686,6 @@ impl Z80 {
let addr = self.get_register_pair_value(regpair);
self.port.write_leu16(addr as Address, value)?;
},
//LoadTarget::DirectAltRegByte(reg),
//LoadTarget::DirectSpecialRegByte(reg),
LoadTarget::IndirectByte(addr) => {
self.port.write_u8(addr as Address, value as u8)?;
},

View File

@ -1,6 +1,7 @@
use crate::devices::Address;
use crate::memory::BusPort;
use crate::signals::Signal;
use super::decode::Z80Decoder;
use super::debugger::Z80Debugger;
@ -20,6 +21,14 @@ pub enum Status {
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum InterruptMode {
Mode0,
Mode01,
Mode1,
Mode2,
}
#[repr(u8)]
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq)]
@ -52,6 +61,7 @@ pub enum Register {
pub struct Z80State {
pub status: Status,
pub interrupts_enabled: bool,
pub interrupt_mode: InterruptMode,
pub pc: u16,
pub sp: u16,
@ -70,6 +80,7 @@ impl Z80State {
Self {
status: Status::Init,
interrupts_enabled: false,
interrupt_mode: InterruptMode::Mode0,
pc: 0,
sp: 0,
@ -100,6 +111,8 @@ pub struct Z80 {
pub decoder: Z80Decoder,
pub debugger: Z80Debugger,
pub port: BusPort,
pub reset: Signal<bool>,
pub bus_request: Signal<bool>,
}
impl Z80 {
@ -111,6 +124,8 @@ impl Z80 {
decoder: Z80Decoder::new(),
debugger: Z80Debugger::new(),
port: port,
reset: Signal::new(false),
bus_request: Signal::new(false),
}
}