Fixed many of the undocumented tests

Now it's up to 99% tests passing, 15362 are still failing, but many
of those are the unimplemented IN/OUT instructions, which the Genesis
doesn't seem to use
This commit is contained in:
transistor 2023-05-22 21:12:05 -07:00
parent 8c1a89a1fe
commit 708e7706f3
8 changed files with 2673 additions and 40 deletions

View File

@ -72,3 +72,37 @@ Signals, Etc.
- what about interrupt controller? - what about interrupt controller?
2023/05/22:
Refactoring Execution of m68k
-----------------------------
* would it be possible to construct something that behaves more like the microcode executor using steps in chained form,
with side effects and quirks and flags (and exceptions) handled as such
```
// ADD
executor.start()
.fetch_src(src)
.fetch_dest(dest)
.add()
.write_dest(dest)
.set_flags("XCNVS")
.finish()?;
// BRA
executor.start()
.branch_offset(offset)
.finish()?;
// JMP
executor.start()
.fetch_src(target)
.branch_absolute()
.finish()?;
```

View File

@ -73,5 +73,9 @@ impl Error {
msg: msg.into(), msg: msg.into(),
} }
} }
pub fn is_processor(&self, native: u32) -> bool {
self.err == ErrorType::Processor && self.native == native
}
} }

View File

@ -61,7 +61,6 @@ impl Transmutable for M68k {
impl M68k { impl M68k {
pub fn step_internal(&mut self, system: &System) -> Result<ClockCycles, Error> { pub fn step_internal(&mut self, system: &System) -> Result<ClockCycles, Error> {
//self.current_clock = system.clock;
self.init_cycle(system.clock); self.init_cycle(system.clock);
match self.state.status { match self.state.status {
Status::Init => self.reset_cpu(), Status::Init => self.reset_cpu(),
@ -70,8 +69,6 @@ impl M68k {
match self.cycle_one(system) { match self.cycle_one(system) {
Ok(diff) => Ok(diff), Ok(diff) => Ok(diff),
Err(Error { err: ErrorType::Processor, native, .. }) => { Err(Error { err: ErrorType::Processor, native, .. }) => {
// TODO match arm conditional is temporary: illegal instructions generate a top level error in order to debug and fix issues with decode
//Err(Error { err: ErrorType::Processor, native, .. }) if native != Exceptions::IllegalInstruction as u32 => {
self.exception(native as u8, false)?; self.exception(native as u8, false)?;
Ok(4) Ok(4)
}, },
@ -86,6 +83,7 @@ impl M68k {
self.decoder = M68kDecoder::new(self.cputype, self.is_supervisor(), self.state.pc); self.decoder = M68kDecoder::new(self.cputype, self.is_supervisor(), self.state.pc);
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width()); self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
self.port.init_cycle(clock); self.port.init_cycle(clock);
self.timing.reset();
} }
pub fn reset_cpu(&mut self) -> Result<ClockCycles, Error> { pub fn reset_cpu(&mut self) -> Result<ClockCycles, Error> {
@ -203,8 +201,6 @@ impl M68k {
} }
pub fn decode_next(&mut self) -> Result<(), Error> { pub fn decode_next(&mut self) -> Result<(), Error> {
self.timing.reset();
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
self.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?; self.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?;

View File

@ -33,7 +33,10 @@ impl Z80Decoder {
pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> { pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
let ins = self.read_instruction_byte(memory)?; let ins = self.read_instruction_byte(memory)?;
self.decode_bare(memory, ins)
}
pub fn decode_bare(&mut self, memory: &mut dyn Addressable, ins: u8) -> Result<Instruction, Error> {
match get_ins_x(ins) { match get_ins_x(ins) {
0 => { 0 => {
match get_ins_z(ins) { match get_ins_z(ins) {
@ -380,19 +383,28 @@ impl Z80Decoder {
let data = self.read_instruction_byte(memory)?; let data = self.read_instruction_byte(memory)?;
Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data))) Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data)))
}, },
_ => Ok(Instruction::NOP), _ => self.decode_bare(memory, ins),
} }
}, },
3 => { 3 => {
let offset = self.read_instruction_byte(memory)? as i8;
match ins { match ins {
0x34 => Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset))), 0x34 => {
0x35 => Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset))), let offset = self.read_instruction_byte(memory)? as i8;
0x36 => Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), LoadTarget::ImmediateByte(self.read_instruction_byte(memory)?))), Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset)))
_ => Ok(Instruction::NOP), },
0x35 => {
let offset = self.read_instruction_byte(memory)? as i8;
Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset)))
},
0x36 => {
let offset = self.read_instruction_byte(memory)? as i8;
let immediate = self.read_instruction_byte(memory)?;
Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), LoadTarget::ImmediateByte(immediate)))
},
_ => self.decode_bare(memory, ins),
} }
}, },
_ => Ok(Instruction::NOP), _ => self.decode_bare(memory, ins),
} }
}, },
1 => { 1 => {
@ -400,7 +412,7 @@ impl Z80Decoder {
0 | 1 => { 0 | 1 => {
let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? { let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? {
Some(target) => target, Some(target) => target,
None => return Ok(Instruction::NOP), None => return self.decode_bare(memory, ins),
}; };
match (ins & 0x18) >> 3 { match (ins & 0x18) >> 3 {
@ -438,7 +450,7 @@ impl Z80Decoder {
3 => { 3 => {
if get_ins_q(ins) == 0 { if get_ins_q(ins) == 0 {
if get_ins_z(ins) == 6 { if get_ins_z(ins) == 6 {
return Ok(Instruction::NOP); return self.decode_bare(memory, ins);
} }
let src = get_register(get_ins_z(ins)); let src = get_register(get_ins_z(ins));
let offset = self.read_instruction_byte(memory)? as i8; let offset = self.read_instruction_byte(memory)? as i8;
@ -446,7 +458,7 @@ impl Z80Decoder {
} else { } else {
let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? { let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? {
Some(target) => target, Some(target) => target,
None => return Ok(Instruction::NOP), None => return self.decode_bare(memory, ins),
}; };
Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), to_load_target(target))) Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), to_load_target(target)))
@ -458,7 +470,7 @@ impl Z80Decoder {
2 => { 2 => {
let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? { let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? {
Some(target) => target, Some(target) => target,
None => return Ok(Instruction::NOP), None => return self.decode_bare(memory, ins),
}; };
@ -481,7 +493,7 @@ impl Z80Decoder {
0xE5 => Ok(Instruction::PUSH(index_reg.into())), 0xE5 => Ok(Instruction::PUSH(index_reg.into())),
0xE9 => Ok(Instruction::JPIndirect(index_reg.into())), 0xE9 => Ok(Instruction::JPIndirect(index_reg.into())),
0xF9 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::SP), LoadTarget::DirectRegWord(index_reg.into()))), 0xF9 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::SP), LoadTarget::DirectRegWord(index_reg.into()))),
_ => Ok(Instruction::NOP), _ => self.decode_bare(memory, ins),
} }
}, },
_ => panic!("InternalError: impossible value"), _ => panic!("InternalError: impossible value"),

View File

@ -479,7 +479,6 @@ impl Z80 {
fn execute_inc8(&mut self, target: Target) -> Result<(), Error> { fn execute_inc8(&mut self, target: Target) -> Result<(), Error> {
let value = self.get_target_value(target)?; let value = self.get_target_value(target)?;
let (result, _, overflow, half_carry) = add_bytes(value, 1); let (result, _, overflow, half_carry) = add_bytes(value, 1);
let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference
self.set_arithmetic_op_flags(result as u16, Size::Byte, false, carry, overflow, half_carry); self.set_arithmetic_op_flags(result as u16, Size::Byte, false, carry, overflow, half_carry);
@ -717,7 +716,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -738,7 +737,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -777,7 +776,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -798,7 +797,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -885,7 +884,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -897,7 +896,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -910,7 +909,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -922,7 +921,7 @@ impl Z80 {
self.set_logic_op_flags(result, out_bit, false); self.set_logic_op_flags(result, out_bit, false);
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
if let Some(target) = opt_copy { if let Some(target) = opt_copy {
self.set_target_value(target, value)?; self.set_target_value(target, result)?;
} }
Ok(()) Ok(())
} }
@ -1159,10 +1158,10 @@ impl Z80 {
fn set_index_register_half_value(&mut self, reg: IndexRegisterHalf, value: u8) { fn set_index_register_half_value(&mut self, reg: IndexRegisterHalf, value: u8) {
match reg { match reg {
IndexRegisterHalf::IXH => { self.state.ix |= (value as u16) << 8; }, IndexRegisterHalf::IXH => { self.state.ix = (self.state.ix & 0x00FF) | (value as u16) << 8; },
IndexRegisterHalf::IXL => { self.state.ix |= value as u16; }, IndexRegisterHalf::IXL => { self.state.ix = (self.state.ix & 0xFF00) | value as u16; },
IndexRegisterHalf::IYH => { self.state.iy |= (value as u16) << 8; }, IndexRegisterHalf::IYH => { self.state.iy = (self.state.iy & 0x00FF) | (value as u16) << 8; },
IndexRegisterHalf::IYL => { self.state.iy |= value as u16; }, IndexRegisterHalf::IYL => { self.state.iy = (self.state.iy & 0xFF00) | value as u16; },
} }
} }

View File

@ -38,11 +38,11 @@ impl Z80InstructionCycles {
Instruction::XOR(target) => { Instruction::XOR(target) => {
match target { match target {
// TODO the undocumented DD version of this instruction is actually 8 cycles // TODO the undocumented DD version of this instruction is actually 8 cycles
Target::DirectReg(_) => 4, Target::DirectReg(_) |
Target::DirectRegHalf(_) => 4,
Target::IndirectReg(_) => 7, Target::IndirectReg(_) => 7,
Target::Immediate(_) => 7, Target::Immediate(_) => 7,
Target::IndirectOffset(_, _) => 19, Target::IndirectOffset(_, _) => 19,
_ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))),
} }
}, },
@ -107,7 +107,8 @@ impl Z80InstructionCycles {
Instruction::INC8(target) => { Instruction::INC8(target) => {
// TODO the undocumented DD version of this instruction is actually 8 cycles // TODO the undocumented DD version of this instruction is actually 8 cycles
match target { match target {
Target::DirectReg(_) => 4, Target::DirectReg(_) |
Target::DirectRegHalf(_) => 4,
Target::IndirectReg(_) => 11, Target::IndirectReg(_) => 11,
Target::IndirectOffset(_, _) => 23, Target::IndirectOffset(_, _) => 23,
_ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))),
@ -182,7 +183,11 @@ impl Z80InstructionCycles {
(LoadTarget::DirectRegByte(_), LoadTarget::DirectRegByte(_)) => 4, (LoadTarget::DirectRegByte(_), LoadTarget::DirectRegByte(_)) => 4,
(LoadTarget::DirectRegByte(_), LoadTarget::ImmediateByte(_)) => 7, (LoadTarget::DirectRegHalfByte(_), LoadTarget::DirectRegByte(_)) |
(LoadTarget::DirectRegByte(_), LoadTarget::DirectRegHalfByte(_)) |
(LoadTarget::DirectRegHalfByte(_), LoadTarget::DirectRegHalfByte(_)) => 8,
(LoadTarget::DirectRegByte(_) | LoadTarget::DirectRegHalfByte(_), LoadTarget::ImmediateByte(_)) => 7,
(LoadTarget::IndirectRegByte(_), LoadTarget::ImmediateByte(_)) => 10, (LoadTarget::IndirectRegByte(_), LoadTarget::ImmediateByte(_)) => 10,
(LoadTarget::IndirectOffsetByte(_, _), _) | (LoadTarget::IndirectOffsetByte(_, _), _) |

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff