mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-21 19:30:52 +00:00
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:
parent
8c1a89a1fe
commit
708e7706f3
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
2021/10/21:
|
||||
|
||||
Frontend/Backend Interface
|
||||
@ -72,3 +72,37 @@ Signals, Etc.
|
||||
- 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()?;
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -73,5 +73,9 @@ impl Error {
|
||||
msg: msg.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_processor(&self, native: u32) -> bool {
|
||||
self.err == ErrorType::Processor && self.native == native
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,6 @@ impl Transmutable for M68k {
|
||||
|
||||
impl M68k {
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<ClockCycles, Error> {
|
||||
//self.current_clock = system.clock;
|
||||
self.init_cycle(system.clock);
|
||||
match self.state.status {
|
||||
Status::Init => self.reset_cpu(),
|
||||
@ -70,8 +69,6 @@ impl M68k {
|
||||
match self.cycle_one(system) {
|
||||
Ok(diff) => Ok(diff),
|
||||
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)?;
|
||||
Ok(4)
|
||||
},
|
||||
@ -86,6 +83,7 @@ impl M68k {
|
||||
self.decoder = M68kDecoder::new(self.cputype, self.is_supervisor(), self.state.pc);
|
||||
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
|
||||
self.port.init_cycle(clock);
|
||||
self.timing.reset();
|
||||
}
|
||||
|
||||
pub fn reset_cpu(&mut self) -> Result<ClockCycles, Error> {
|
||||
@ -203,8 +201,6 @@ impl M68k {
|
||||
}
|
||||
|
||||
pub fn decode_next(&mut self) -> Result<(), Error> {
|
||||
self.timing.reset();
|
||||
|
||||
let is_supervisor = self.is_supervisor();
|
||||
self.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?;
|
||||
|
||||
|
@ -33,7 +33,10 @@ impl Z80Decoder {
|
||||
|
||||
pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
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) {
|
||||
0 => {
|
||||
match get_ins_z(ins) {
|
||||
@ -380,19 +383,28 @@ impl Z80Decoder {
|
||||
let data = self.read_instruction_byte(memory)?;
|
||||
Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data)))
|
||||
},
|
||||
_ => Ok(Instruction::NOP),
|
||||
_ => self.decode_bare(memory, ins),
|
||||
}
|
||||
},
|
||||
3 => {
|
||||
let offset = self.read_instruction_byte(memory)? as i8;
|
||||
match ins {
|
||||
0x34 => Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset))),
|
||||
0x35 => Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset))),
|
||||
0x36 => Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), LoadTarget::ImmediateByte(self.read_instruction_byte(memory)?))),
|
||||
_ => Ok(Instruction::NOP),
|
||||
0x34 => {
|
||||
let offset = self.read_instruction_byte(memory)? as i8;
|
||||
Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset)))
|
||||
},
|
||||
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 => {
|
||||
@ -400,7 +412,7 @@ impl Z80Decoder {
|
||||
0 | 1 => {
|
||||
let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? {
|
||||
Some(target) => target,
|
||||
None => return Ok(Instruction::NOP),
|
||||
None => return self.decode_bare(memory, ins),
|
||||
};
|
||||
|
||||
match (ins & 0x18) >> 3 {
|
||||
@ -438,7 +450,7 @@ impl Z80Decoder {
|
||||
3 => {
|
||||
if get_ins_q(ins) == 0 {
|
||||
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 offset = self.read_instruction_byte(memory)? as i8;
|
||||
@ -446,7 +458,7 @@ impl Z80Decoder {
|
||||
} else {
|
||||
let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? {
|
||||
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)))
|
||||
@ -458,7 +470,7 @@ impl Z80Decoder {
|
||||
2 => {
|
||||
let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? {
|
||||
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())),
|
||||
0xE9 => Ok(Instruction::JPIndirect(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"),
|
||||
|
@ -479,7 +479,6 @@ impl Z80 {
|
||||
|
||||
fn execute_inc8(&mut self, target: Target) -> Result<(), Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
|
||||
let (result, _, overflow, half_carry) = add_bytes(value, 1);
|
||||
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);
|
||||
@ -717,7 +716,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -738,7 +737,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -777,7 +776,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -798,7 +797,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -885,7 +884,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -897,7 +896,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -910,7 +909,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -922,7 +921,7 @@ impl Z80 {
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
self.set_target_value(target, result)?;
|
||||
if let Some(target) = opt_copy {
|
||||
self.set_target_value(target, value)?;
|
||||
self.set_target_value(target, result)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -1159,10 +1158,10 @@ impl Z80 {
|
||||
|
||||
fn set_index_register_half_value(&mut self, reg: IndexRegisterHalf, value: u8) {
|
||||
match reg {
|
||||
IndexRegisterHalf::IXH => { self.state.ix |= (value as u16) << 8; },
|
||||
IndexRegisterHalf::IXL => { self.state.ix |= value as u16; },
|
||||
IndexRegisterHalf::IYH => { self.state.iy |= (value as u16) << 8; },
|
||||
IndexRegisterHalf::IYL => { self.state.iy |= value as u16; },
|
||||
IndexRegisterHalf::IXH => { self.state.ix = (self.state.ix & 0x00FF) | (value as u16) << 8; },
|
||||
IndexRegisterHalf::IXL => { self.state.ix = (self.state.ix & 0xFF00) | value as u16; },
|
||||
IndexRegisterHalf::IYH => { self.state.iy = (self.state.iy & 0x00FF) | (value as u16) << 8; },
|
||||
IndexRegisterHalf::IYL => { self.state.iy = (self.state.iy & 0xFF00) | value as u16; },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,11 +38,11 @@ impl Z80InstructionCycles {
|
||||
Instruction::XOR(target) => {
|
||||
match target {
|
||||
// TODO the undocumented DD version of this instruction is actually 8 cycles
|
||||
Target::DirectReg(_) => 4,
|
||||
Target::DirectReg(_) |
|
||||
Target::DirectRegHalf(_) => 4,
|
||||
Target::IndirectReg(_) => 7,
|
||||
Target::Immediate(_) => 7,
|
||||
Target::IndirectOffset(_, _) => 19,
|
||||
_ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))),
|
||||
}
|
||||
},
|
||||
|
||||
@ -107,7 +107,8 @@ impl Z80InstructionCycles {
|
||||
Instruction::INC8(target) => {
|
||||
// TODO the undocumented DD version of this instruction is actually 8 cycles
|
||||
match target {
|
||||
Target::DirectReg(_) => 4,
|
||||
Target::DirectReg(_) |
|
||||
Target::DirectRegHalf(_) => 4,
|
||||
Target::IndirectReg(_) => 11,
|
||||
Target::IndirectOffset(_, _) => 23,
|
||||
_ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))),
|
||||
@ -182,7 +183,11 @@ impl Z80InstructionCycles {
|
||||
|
||||
(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::IndirectOffsetByte(_, _), _) |
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user