diff --git a/docs/log.txt b/docs/log.txt index 06d711a..5b6bc6e 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -428,3 +428,16 @@ General Work doesn't make a heck of a lot of sense to be changing the volume level but nothing else all the time. It doesn't seem to set the initial frequencies. So it's possible that a bug in the Z80 code is making it run incorrectly and thus not producing correct register commands to the ym2612 + +2023-05-16 +- I spent a bunch of time getting the Z80 tests running and fixing bugs in the implementation. It's + generally gone well. I started with 45% of the tests passing with all checks, 60% with the + undocumented flags ignored, 83% with undocumented instructions also ignored, and timing wasn't + even checked. It's now 98% passing with undocumented instructions and timing checks, but is still + only 65% passing on all tests +- Now that I added timings to the Z80, and fixed instructions, Sonic 1 has the drums in the intro, + but there's still no bass, and it still sounds incorrect in spots. But most other games still + have no sound which is baffling +- it must be a problem with either the bus architecture in the genesis, or a probably with the + CPU/coproc interface, banking, etc + diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index bd8a94b..d31f7bb 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -6,7 +6,6 @@ use super::instructions::{ Size, Sign, Direction, - ShiftDirection, XRegister, BaseRegister, IndexRegister, @@ -583,10 +582,9 @@ impl M68kDecoder { } fn decode_group_shift(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result { - let dir = if (ins & 0x0100) == 0 { ShiftDirection::Right } else { ShiftDirection::Left }; match get_size(ins) { Some(size) => { - let reg = get_low_reg(ins); + let target = Target::DirectDReg(get_low_reg(ins)); let rotation = get_high_reg(ins); let count = if (ins & 0x0020) == 0 { Target::Immediate(if rotation != 0 { rotation as u32 } else { 8 }) @@ -594,24 +592,46 @@ impl M68kDecoder { Target::DirectDReg(rotation) }; - 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)), - _ => Err(Error::processor(Exceptions::IllegalInstruction as u32)), + if (ins & 0x0100) == 0 { + match (ins & 0x0018) >> 3 { + 0b00 => Ok(Instruction::ASR(count, target, size)), + 0b01 => Ok(Instruction::LSR(count, target, size)), + 0b10 => Ok(Instruction::ROXR(count, target, size)), + 0b11 => Ok(Instruction::ROR(count, target, size)), + _ => Err(Error::processor(Exceptions::IllegalInstruction as u32)), + } + } else { + match (ins & 0x0018) >> 3 { + 0b00 => Ok(Instruction::ASL(count, target, size)), + 0b01 => Ok(Instruction::LSL(count, target, size)), + 0b10 => Ok(Instruction::ROXL(count, target, size)), + 0b11 => Ok(Instruction::ROL(count, target, size)), + _ => Err(Error::processor(Exceptions::IllegalInstruction as u32)), + } } }, None => { if (ins & 0x800) == 0 { let target = self.decode_lower_effective_address(memory, 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)), - _ => Err(Error::processor(Exceptions::IllegalInstruction as u32)), + let size = Size::Word; + + if (ins & 0x0100) == 0 { + match (ins & 0x0600) >> 9 { + 0b00 => Ok(Instruction::ASR(count, target, size)), + 0b01 => Ok(Instruction::LSR(count, target, size)), + 0b10 => Ok(Instruction::ROXR(count, target, size)), + 0b11 => Ok(Instruction::ROR(count, target, size)), + _ => Err(Error::processor(Exceptions::IllegalInstruction as u32)), + } + } else { + match (ins & 0x0600) >> 9 { + 0b00 => Ok(Instruction::ASL(count, target, size)), + 0b01 => Ok(Instruction::LSL(count, target, size)), + 0b10 => Ok(Instruction::ROXL(count, target, size)), + 0b11 => Ok(Instruction::ROL(count, target, size)), + _ => Err(Error::processor(Exceptions::IllegalInstruction as u32)), + } } } else if self.cputype > M68kType::MC68020 { // Bitfield instructions (MC68020+) diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index 358c71a..2f92a8c 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -8,7 +8,6 @@ use crate::instructions::{ Size, Sign, Direction, - ShiftDirection, XRegister, BaseRegister, IndexRegister, @@ -222,7 +221,8 @@ impl M68k { Instruction::AND(src, dest, size) => self.execute_and(src, dest, size), Instruction::ANDtoCCR(value) => self.execute_and_to_ccr(value), Instruction::ANDtoSR(value) => self.execute_and_to_sr(value), - Instruction::ASd(count, target, size, shift_dir) => self.execute_asd(count, target, size, shift_dir), + Instruction::ASL(count, target, size) => self.execute_asl(count, target, size), + Instruction::ASR(count, target, size) => self.execute_asr(count, target, size), Instruction::Bcc(cond, offset) => self.execute_bcc(cond, offset), Instruction::BRA(offset) => self.execute_bra(offset), Instruction::BSR(offset) => self.execute_bsr(offset), @@ -256,7 +256,8 @@ impl M68k { Instruction::JSR(target) => self.execute_jsr(target), Instruction::LEA(target, reg) => self.execute_lea(target, reg), Instruction::LINK(reg, offset) => self.execute_link(reg, offset), - Instruction::LSd(count, target, size, shift_dir) => self.execute_lsd(count, target, size, shift_dir), + Instruction::LSL(count, target, size) => self.execute_lsl(count, target, size), + Instruction::LSR(count, target, size) => self.execute_lsr(count, target, size), Instruction::MOVE(src, dest, size) => self.execute_move(src, dest, size), Instruction::MOVEA(src, reg, size) => self.execute_movea(src, reg, size), Instruction::MOVEfromSR(target) => self.execute_move_from_sr(target), @@ -279,8 +280,10 @@ impl M68k { Instruction::ORtoSR(value) => self.execute_or_to_sr(value), Instruction::PEA(target) => self.execute_pea(target), Instruction::RESET => self.execute_reset(), - Instruction::ROd(count, target, size, shift_dir) => self.execute_rod(count, target, size, shift_dir), - Instruction::ROXd(count, target, size, shift_dir) => self.execute_roxd(count, target, size, shift_dir), + Instruction::ROL(count, target, size) => self.execute_rol(count, target, size), + Instruction::ROR(count, target, size) => self.execute_rol(count, target, size), + Instruction::ROXL(count, target, size) => self.execute_roxl(count, target, size), + Instruction::ROXR(count, target, size) => self.execute_roxr(count, target, size), Instruction::RTE => self.execute_rte(), Instruction::RTR => self.execute_rtr(), Instruction::RTS => self.execute_rts(), @@ -389,7 +392,7 @@ impl M68k { Ok(()) } - fn execute_asd(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> { + fn execute_asl(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { let count = self.get_target_value(count, size, Used::Once)? % 64; let value = self.get_target_value(target, size, Used::Twice)?; @@ -397,7 +400,7 @@ impl M68k { let mut pair = (value, false); let mut previous_msb = get_msb(pair.0, size); for _ in 0..count { - pair = shift_operation(pair.0, size, shift_dir, true); + pair = shift_left(pair.0, size, true); if get_msb(pair.0, size) != previous_msb { overflow = true; } @@ -405,21 +408,40 @@ impl M68k { } self.set_target_value(target, pair.0, size, Used::Twice)?; - let carry = match shift_dir { - ShiftDirection::Left => pair.1, - ShiftDirection::Right => if count < size.in_bits() { pair.1 } else { false } - }; + self.set_arithmetic_shift_flags(pair.0, count, pair.1, overflow, size); + Ok(()) + } - // Adjust flags - self.set_logic_flags(pair.0, size); + fn execute_asr(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { + let count = self.get_target_value(count, size, Used::Once)? % 64; + let value = self.get_target_value(target, size, Used::Twice)?; + + let mut overflow = false; + let mut pair = (value, false); + let mut previous_msb = get_msb(pair.0, size); + for _ in 0..count { + pair = shift_right(pair.0, size, true); + if get_msb(pair.0, size) != previous_msb { + overflow = true; + } + previous_msb = get_msb(pair.0, size); + } + self.set_target_value(target, pair.0, size, Used::Twice)?; + + let last_bit = if count < size.in_bits() { pair.1 } else { false }; + self.set_arithmetic_shift_flags(pair.0, count, last_bit, overflow, size); + Ok(()) + } + + fn set_arithmetic_shift_flags(&mut self, result: u32, count: u32, last_bit_out: bool, overflow: bool, size: Size) { + self.set_logic_flags(result, size); self.set_flag(Flags::Overflow, overflow); if count != 0 { - self.set_flag(Flags::Extend, carry); - self.set_flag(Flags::Carry, carry); + self.set_flag(Flags::Extend, last_bit_out); + self.set_flag(Flags::Carry, last_bit_out); } else { self.set_flag(Flags::Carry, false); } - Ok(()) } fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), Error> { @@ -772,24 +794,39 @@ impl M68k { Ok(()) } - fn execute_lsd(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> { + fn execute_lsl(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { - pair = shift_operation(pair.0, size, shift_dir, false); + pair = shift_left(pair.0, size, false); } self.set_target_value(target, pair.0, size, Used::Twice)?; - // Adjust flags - self.set_logic_flags(pair.0, size); + self.set_shift_flags(pair.0, count, pair.1, size); + Ok(()) + } + + fn execute_lsr(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { + let count = self.get_target_value(count, size, Used::Once)? % 64; + let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); + for _ in 0..count { + pair = shift_right(pair.0, size, false); + } + self.set_target_value(target, pair.0, size, Used::Twice)?; + + self.set_shift_flags(pair.0, count, pair.1, size); + Ok(()) + } + + fn set_shift_flags(&mut self, result: u32, count: u32, last_bit_out: bool, size: Size) { + self.set_logic_flags(result, size); self.set_flag(Flags::Overflow, false); if count != 0 { - self.set_flag(Flags::Extend, pair.1); - self.set_flag(Flags::Carry, pair.1); + self.set_flag(Flags::Extend, last_bit_out); + self.set_flag(Flags::Carry, last_bit_out); } else { self.set_flag(Flags::Carry, false); } - Ok(()) } fn execute_move(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> { @@ -1094,37 +1131,57 @@ impl M68k { Ok(()) } - fn execute_rod(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> { + fn execute_rol(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { - pair = rotate_operation(pair.0, size, shift_dir, None); + pair = rotate_left(pair.0, size, None); } self.set_target_value(target, pair.0, size, Used::Twice)?; - - // Adjust flags - self.set_logic_flags(pair.0, size); - if pair.1 { - self.set_flag(Flags::Carry, true); - } + self.set_rotate_flags(pair.0, pair.1, size); Ok(()) } - fn execute_roxd(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> { + fn execute_ror(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { - pair = rotate_operation(pair.0, size, shift_dir, Some(self.get_flag(Flags::Extend))); + pair = rotate_right(pair.0, size, None); + } + self.set_target_value(target, pair.0, size, Used::Twice)?; + self.set_rotate_flags(pair.0, pair.1, size); + Ok(()) + } + + fn execute_roxl(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { + let count = self.get_target_value(count, size, Used::Once)? % 64; + let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); + for _ in 0..count { + pair = rotate_left(pair.0, size, Some(self.get_flag(Flags::Extend))); self.set_flag(Flags::Extend, pair.1); } self.set_target_value(target, pair.0, size, Used::Twice)?; + self.set_rotate_flags(pair.0, pair.1, size); + Ok(()) + } - // Adjust flags - self.set_logic_flags(pair.0, size); - if pair.1 { + fn execute_roxr(&mut self, count: Target, target: Target, size: Size) -> Result<(), Error> { + let count = self.get_target_value(count, size, Used::Once)? % 64; + let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); + for _ in 0..count { + pair = rotate_right(pair.0, size, Some(self.get_flag(Flags::Extend))); + self.set_flag(Flags::Extend, pair.1); + } + self.set_target_value(target, pair.0, size, Used::Twice)?; + self.set_rotate_flags(pair.0, pair.1, size); + Ok(()) + } + + fn set_rotate_flags(&mut self, result: u32, last_bit_out: bool, size: Size) { + self.set_logic_flags(result, size); + if last_bit_out { self.set_flag(Flags::Carry, true); } - Ok(()) } fn execute_rte(&mut self) -> Result<(), Error> { @@ -1747,42 +1804,36 @@ fn overflowing_sub_signed_sized(operand1: u32, operand2: u32, size: Size) -> (u3 } } -fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) { - match dir { - ShiftDirection::Left => { - let bit = get_msb(value, size); - match size { - Size::Byte => (((value as u8) << 1) as u32, bit), - Size::Word => (((value as u16) << 1) as u32, bit), - Size::Long => (value << 1, bit), - } - }, - ShiftDirection::Right => { - let mask = if arithmetic { get_msb_mask(value, size) } else { 0 }; - ((value >> 1) | mask, (value & 0x1) != 0) - }, +fn shift_left(value: u32, size: Size, arithmetic: bool) -> (u32, bool) { + let bit = get_msb(value, size); + match size { + Size::Byte => (((value as u8) << 1) as u32, bit), + Size::Word => (((value as u16) << 1) as u32, bit), + Size::Long => (value << 1, bit), } } -fn rotate_operation(value: u32, size: Size, dir: ShiftDirection, use_extend: Option) -> (u32, bool) { - match dir { - ShiftDirection::Left => { - let bit = get_msb(value, size); - let mask = if use_extend.unwrap_or(bit) { 0x01 } else { 0x00 }; - match size { - Size::Byte => (mask | ((value as u8) << 1) as u32, bit), - Size::Word => (mask | ((value as u16) << 1) as u32, bit), - Size::Long => (mask | value << 1, bit), - } - }, - ShiftDirection::Right => { - let bit = (value & 0x01) != 0; - let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 }; - ((value >> 1) | mask, bit) - }, +fn shift_right(value: u32, size: Size, arithmetic: bool) -> (u32, bool) { + let mask = if arithmetic { get_msb_mask(value, size) } else { 0 }; + ((value >> 1) | mask, (value & 0x1) != 0) +} + +fn rotate_left(value: u32, size: Size, use_extend: Option) -> (u32, bool) { + let bit = get_msb(value, size); + let mask = if use_extend.unwrap_or(bit) { 0x01 } else { 0x00 }; + match size { + Size::Byte => (mask | ((value as u8) << 1) as u32, bit), + Size::Word => (mask | ((value as u16) << 1) as u32, bit), + Size::Long => (mask | value << 1, bit), } } +fn rotate_right(value: u32, size: Size, use_extend: Option) -> (u32, bool) { + let bit = (value & 0x01) != 0; + let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 }; + ((value >> 1) | mask, bit) +} + fn get_nibbles_from_byte(value: u32) -> (u32, u32) { (value & 0xF0, value & 0x0F) } diff --git a/emulator/cpus/m68k/src/instructions.rs b/emulator/cpus/m68k/src/instructions.rs index 202bd70..68b2b7f 100644 --- a/emulator/cpus/m68k/src/instructions.rs +++ b/emulator/cpus/m68k/src/instructions.rs @@ -23,12 +23,6 @@ pub enum Direction { ToTarget, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ShiftDirection { - Right, - Left, -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum XRegister { DReg(u8), @@ -103,7 +97,8 @@ pub enum Instruction { AND(Target, Target, Size), ANDtoCCR(u8), ANDtoSR(u16), - ASd(Target, Target, Size, ShiftDirection), + ASL(Target, Target, Size), + ASR(Target, Target, Size), Bcc(Condition, i32), BRA(i32), @@ -144,7 +139,8 @@ pub enum Instruction { LEA(Target, Register), LINK(Register, i32), - LSd(Target, Target, Size, ShiftDirection), + LSL(Target, Target, Size), + LSR(Target, Target, Size), MOVE(Target, Target, Size), MOVEA(Target, Register, Size), @@ -174,8 +170,10 @@ pub enum Instruction { PEA(Target), RESET, - ROd(Target, Target, Size, ShiftDirection), - ROXd(Target, Target, Size, ShiftDirection), + ROL(Target, Target, Size), + ROR(Target, Target, Size), + ROXL(Target, Target, Size), + ROXR(Target, Target, Size), RTE, RTR, RTS, @@ -235,15 +233,6 @@ impl fmt::Display for Sign { } } -impl fmt::Display for ShiftDirection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ShiftDirection::Right => write!(f, "r"), - ShiftDirection::Left => write!(f, "l"), - } - } -} - impl fmt::Display for Size { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -405,7 +394,8 @@ impl fmt::Display for Instruction { Instruction::AND(src, dest, size) => write!(f, "and{}\t{}, {}", size, src, dest), Instruction::ANDtoCCR(value) => write!(f, "andib\t#{:#02x}, %ccr", value), Instruction::ANDtoSR(value) => write!(f, "andiw\t#{:#04x}, %sr", value), - Instruction::ASd(src, dest, size, dir) => write!(f, "as{}{}\t{}, {}", dir, size, src, dest), + Instruction::ASL(src, dest, size) => write!(f, "asl{}\t{}, {}", size, src, dest), + Instruction::ASR(src, dest, size) => write!(f, "asr{}\t{}, {}", size, src, dest), Instruction::Bcc(cond, offset) => write!(f, "b{}\t{}", cond, offset), Instruction::BRA(offset) => write!(f, "bra\t{}", offset), @@ -451,7 +441,8 @@ impl fmt::Display for Instruction { Instruction::LEA(target, reg) => write!(f, "lea\t{}, %a{}", target, reg), Instruction::LINK(reg, offset) => write!(f, "link\t%a{}, {}", reg, offset), - Instruction::LSd(src, dest, size, dir) => write!(f, "ls{}{}\t{}, {}", dir, size, src, dest), + Instruction::LSL(src, dest, size) => write!(f, "lsl{}\t{}, {}", size, src, dest), + Instruction::LSR(src, dest, size) => write!(f, "lsr{}\t{}, {}", size, src, dest), Instruction::MOVE(src, dest, size) => write!(f, "move{}\t{}, {}", size, src, dest), Instruction::MOVEA(target, reg, size) => write!(f, "movea{}\t{}, %a{}", size, target, reg), @@ -497,8 +488,10 @@ impl fmt::Display for Instruction { Instruction::PEA(target) => write!(f, "pea\t{}", target), Instruction::RESET => write!(f, "reset"), - Instruction::ROd(src, dest, size, dir) => write!(f, "ro{}{}\t{}, {}", dir, size, src, dest), - Instruction::ROXd(src, dest, size, dir) => write!(f, "rox{}{}\t{}, {}", dir, size, src, dest), + Instruction::ROL(src, dest, size) => write!(f, "rol{}\t{}, {}", size, src, dest), + Instruction::ROR(src, dest, size) => write!(f, "ror{}\t{}, {}", size, src, dest), + Instruction::ROXL(src, dest, size) => write!(f, "roxl{}\t{}, {}", size, src, dest), + Instruction::ROXR(src, dest, size) => write!(f, "roxr{}\t{}, {}", size, src, dest), Instruction::RTE => write!(f, "rte"), Instruction::RTR => write!(f, "rtr"), Instruction::RTS => write!(f, "rts"), diff --git a/emulator/cpus/m68k/src/timing.rs b/emulator/cpus/m68k/src/timing.rs index 336ee0f..f1ec942 100644 --- a/emulator/cpus/m68k/src/timing.rs +++ b/emulator/cpus/m68k/src/timing.rs @@ -204,7 +204,8 @@ impl M68kInstructionTiming { Instruction::ANDtoCCR(_) => self.add_internal(20), Instruction::ANDtoSR(_) => self.add_internal(20), - Instruction::ASd(_, target, size, _) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::ASL(_, target, size) | + Instruction::ASR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), Instruction::Bcc(_, _) => self.add_internal(8).add_on_branch(2), Instruction::BRA(_) => self.add_internal(10), @@ -255,7 +256,8 @@ impl M68kInstructionTiming { Instruction::LEA(target, _) => self.add_indirect_set(target, 4, 8, 12, 8, 12), Instruction::LINK(_, _) => self.add_internal(16), - Instruction::LSd(_, target, size, _) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::LSL(_, target, size) | + Instruction::LSR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), Instruction::MOVE(src, dest, size) => self.add_internal(4).add_two_targets(*size, src, dest), Instruction::MOVEA(target, _, size) => self.add_internal(4).add_target(*size, target), @@ -287,8 +289,10 @@ impl M68kInstructionTiming { Instruction::RESET => self.add_internal(132), - Instruction::ROd(_, target, size, _) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), - Instruction::ROXd(_, target, size, _) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::ROL(_, target, size) | + Instruction::ROR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::ROXL(_, target, size) | + Instruction::ROXR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), Instruction::RTE => self.add_internal(20), Instruction::RTR => self.add_internal(20), diff --git a/emulator/frontends/common/src/cpal.rs b/emulator/frontends/common/src/cpal.rs index 958a2e5..46c1355 100644 --- a/emulator/frontends/common/src/cpal.rs +++ b/emulator/frontends/common/src/cpal.rs @@ -1,7 +1,7 @@ use cpal::{Stream, SampleRate, SampleFormat, StreamConfig, StreamInstant, OutputCallbackInfo, traits::{DeviceTrait, HostTrait, StreamTrait}}; -use moa_core::{warn, error}; +use moa_core::{debug, error}; use crate::audio::{AudioOutput, SAMPLE_RATE}; @@ -41,7 +41,7 @@ impl CpalAudioOutput { output.put_back(clock, frame); } } else { - warn!("missed an audio frame"); + debug!("missed an audio frame"); break; } } diff --git a/emulator/systems/genesis/src/peripherals/ym7101.rs b/emulator/systems/genesis/src/peripherals/ym7101.rs index 06e88bd..93f27cb 100644 --- a/emulator/systems/genesis/src/peripherals/ym7101.rs +++ b/emulator/systems/genesis/src/peripherals/ym7101.rs @@ -4,62 +4,77 @@ use moa_core::{System, Error, EdgeSignal, ClockTime, ClockDuration, Frequency, S use moa_core::host::{self, Host, Pixel, PixelEncoding, Frame, FrameSender}; -const REG_MODE_SET_1: usize = 0x00; -const REG_MODE_SET_2: usize = 0x01; -const REG_SCROLL_A_ADDR: usize = 0x02; -const REG_WINDOW_ADDR: usize = 0x03; -const REG_SCROLL_B_ADDR: usize = 0x04; -const REG_SPRITES_ADDR: usize = 0x05; -// Register 0x06 Unused -const REG_BACKGROUND: usize = 0x07; -// Register 0x08 Unused -// Register 0x09 Unused -const REG_H_INTERRUPT: usize = 0x0A; -const REG_MODE_SET_3: usize = 0x0B; -const REG_MODE_SET_4: usize = 0x0C; -const REG_HSCROLL_ADDR: usize = 0x0D; -// Register 0x0E Unused -const REG_AUTO_INCREMENT: usize = 0x0F; -const REG_SCROLL_SIZE: usize = 0x10; -const REG_WINDOW_H_POS: usize = 0x11; -const REG_WINDOW_V_POS: usize = 0x12; -const REG_DMA_COUNTER_LOW: usize = 0x13; -const REG_DMA_COUNTER_HIGH: usize = 0x14; -const REG_DMA_ADDR_LOW: usize = 0x15; -const REG_DMA_ADDR_MID: usize = 0x16; -const REG_DMA_ADDR_HIGH: usize = 0x17; - - -//const STATUS_PAL_MODE: u16 = 0x0001; -const STATUS_DMA_BUSY: u16 = 0x0002; -const STATUS_IN_HBLANK: u16 = 0x0004; -const STATUS_IN_VBLANK: u16 = 0x0008; -//const STATUS_ODD_FRAME: u16 = 0x0010; -//const STATUS_SPRITE_COLLISION: u16 = 0x0020; -//const STATUS_SPRITE_OVERFLOW: u16 = 0x0040; -//const STATUS_V_INTERRUPT: u16 = 0x0080; -//const STATUS_FIFO_FULL: u16 = 0x0100; -const STATUS_FIFO_EMPTY: u16 = 0x0200; - -const MODE1_BF_DISABLE_DISPLAY: u8 = 0x01; -//const MODE1_BF_ENABLE_HV_COUNTER: u8 = 0x02; -const MODE1_BF_HSYNC_INTERRUPT: u8 = 0x10; - -const MODE2_BF_V_CELL_MODE: u8 = 0x08; -const MODE2_BF_DMA_ENABLED: u8 = 0x10; -const MODE2_BF_VSYNC_INTERRUPT: u8 = 0x20; - -const MODE3_BF_EXTERNAL_INTERRUPT: u8 = 0x08; -const MODE3_BF_V_SCROLL_MODE: u8 = 0x04; -const MODE3_BF_H_SCROLL_MODE: u8 = 0x03; - -const MODE4_BF_H_CELL_MODE: u8 = 0x01; -const MODE4_BF_SHADOW_HIGHLIGHT: u8 = 0x08; - - - const DEV_NAME: &str = "ym7101"; +#[rustfmt::skip] +mod reg { + pub(super) const MODE_SET_1: usize = 0x00; + pub(super) const MODE_SET_2: usize = 0x01; + pub(super) const SCROLL_A_ADDR: usize = 0x02; + pub(super) const WINDOW_ADDR: usize = 0x03; + pub(super) const SCROLL_B_ADDR: usize = 0x04; + pub(super) const SPRITES_ADDR: usize = 0x05; + // Register 0x06 Unused + pub(super) const BACKGROUND: usize = 0x07; + // Register 0x08 Unused + // Register 0x09 Unused + pub(super) const H_INTERRUPT: usize = 0x0A; + pub(super) const MODE_SET_3: usize = 0x0B; + pub(super) const MODE_SET_4: usize = 0x0C; + pub(super) const HSCROLL_ADDR: usize = 0x0D; + // Register 0x0E Unused + pub(super) const AUTO_INCREMENT: usize = 0x0F; + pub(super) const SCROLL_SIZE: usize = 0x10; + pub(super) const WINDOW_H_POS: usize = 0x11; + pub(super) const WINDOW_V_POS: usize = 0x12; + pub(super) const DMA_COUNTER_LOW: usize = 0x13; + pub(super) const DMA_COUNTER_HIGH: usize = 0x14; + pub(super) const DMA_ADDR_LOW: usize = 0x15; + pub(super) const DMA_ADDR_MID: usize = 0x16; + pub(super) const DMA_ADDR_HIGH: usize = 0x17; +} + +#[rustfmt::skip] +mod status { + //pub(super) const PAL_MODE: u16 = 0x0001; + pub(super) const DMA_BUSY: u16 = 0x0002; + pub(super) const IN_HBLANK: u16 = 0x0004; + pub(super) const IN_VBLANK: u16 = 0x0008; + //pub(super) const ODD_FRAME: u16 = 0x0010; + //pub(super) const SPRITE_COLLISION: u16 = 0x0020; + //pub(super) const SPRITE_OVERFLOW: u16 = 0x0040; + //pub(super) const V_INTERRUPT: u16 = 0x0080; + //pub(super) const FIFO_FULL: u16 = 0x0100; + pub(super) const FIFO_EMPTY: u16 = 0x0200; +} + +#[rustfmt::skip] +mod mode1 { + pub(super) const BF_DISABLE_DISPLAY: u8 = 0x01; + //const BF_ENABLE_HV_COUNTER: u8 = 0x02; + pub(super) const BF_HSYNC_INTERRUPT: u8 = 0x10; +} + +#[rustfmt::skip] +mod mode2 { + pub(super) const BF_V_CELL_MODE: u8 = 0x08; + pub(super) const BF_DMA_ENABLED: u8 = 0x10; + pub(super) const BF_VSYNC_INTERRUPT: u8 = 0x20; +} + +#[rustfmt::skip] +mod mode3 { + pub(super) const BF_EXTERNAL_INTERRUPT: u8 = 0x08; + pub(super) const BF_V_SCROLL_MODE: u8 = 0x04; + pub(super) const BF_H_SCROLL_MODE: u8 = 0x03; +} + +#[rustfmt::skip] +mod mode4 { + pub(super) const BF_H_CELL_MODE: u8 = 0x01; + pub(super) const BF_SHADOW_HIGHLIGHT: u8 = 0x08; +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum DmaType { @@ -134,12 +149,12 @@ impl Ym7101Memory { fn set_dma_mode(&mut self, mode: DmaType) { match mode { DmaType::None => { - //self.status &= !STATUS_DMA_BUSY; + //self.status &= !status::DMA_BUSY; self.transfer_dma_busy = false; self.transfer_run = DmaType::None; }, _ => { - //self.status |= STATUS_DMA_BUSY; + //self.status |= status::DMA_BUSY; self.transfer_dma_busy = true; self.transfer_run = mode; }, @@ -328,7 +343,7 @@ struct Ym7101State { impl Default for Ym7101State { fn default() -> Self { Self { - status: 0x3400 | STATUS_FIFO_EMPTY, + status: 0x3400 | status::FIFO_EMPTY, memory: Ym7101Memory::default(), mode_1: 0, @@ -365,22 +380,22 @@ impl Default for Ym7101State { impl Ym7101State { #[inline(always)] fn hsync_int_enabled(&self) -> bool { - (self.mode_1 & MODE1_BF_HSYNC_INTERRUPT) != 0 + (self.mode_1 & mode1::BF_HSYNC_INTERRUPT) != 0 } #[inline(always)] fn vsync_int_enabled(&self) -> bool { - (self.mode_2 & MODE2_BF_VSYNC_INTERRUPT) != 0 + (self.mode_2 & mode2::BF_VSYNC_INTERRUPT) != 0 } #[inline(always)] fn external_int_enabled(&self) -> bool { - (self.mode_3 & MODE3_BF_EXTERNAL_INTERRUPT) != 0 + (self.mode_3 & mode3::BF_EXTERNAL_INTERRUPT) != 0 } fn update_screen_size(&mut self) { - let h_cells = if (self.mode_4 & MODE4_BF_H_CELL_MODE) == 0 { 32 } else { 40 }; - let v_cells = if (self.mode_2 & MODE2_BF_V_CELL_MODE) == 0 { 28 } else { 30 }; + let h_cells = if (self.mode_4 & mode4::BF_H_CELL_MODE) == 0 { 32 } else { 40 }; + let v_cells = if (self.mode_2 & mode2::BF_V_CELL_MODE) == 0 { 28 } else { 30 }; self.screen_size = (h_cells, v_cells); } @@ -404,7 +419,7 @@ impl Ym7101State { } fn get_palette_colour(&self, palette: u8, colour: u8, mode: ColourMode, encoding: PixelEncoding) -> u32 { - let shift_enabled = (self.mode_4 & MODE4_BF_SHADOW_HIGHLIGHT) != 0; + let shift_enabled = (self.mode_4 & mode4::BF_SHADOW_HIGHLIGHT) != 0; let rgb = self.memory.read_beu16(Memory::Cram, (((palette * 16) + colour) * 2) as usize); if !shift_enabled || mode == ColourMode::Normal { Pixel::Rgb(((rgb & 0x00F) << 4) as u8, (rgb & 0x0F0) as u8, ((rgb & 0xF00) >> 4) as u8).encode(encoding) @@ -415,7 +430,7 @@ impl Ym7101State { } fn get_hscroll(&self, hcell: usize, line: usize) -> (usize, usize) { - let scroll_addr = match self.mode_3 & MODE3_BF_H_SCROLL_MODE { + let scroll_addr = match self.mode_3 & mode3::BF_H_SCROLL_MODE { 0 => self.hscroll_addr, 2 => self.hscroll_addr + (hcell << 5), 3 => self.hscroll_addr + (hcell << 5) + (line * 2 * 2), @@ -428,7 +443,7 @@ impl Ym7101State { } fn get_vscroll(&self, vcell: usize) -> (usize, usize) { - let scroll_addr = if (self.mode_3 & MODE3_BF_V_SCROLL_MODE) == 0 { + let scroll_addr = if (self.mode_3 & mode3::BF_V_SCROLL_MODE) == 0 { 0 } else { vcell >> 1 @@ -505,19 +520,29 @@ impl Ym7101State { for x in 0..(self.screen_size.0 * 8) { let (vscrolling_a, vscrolling_b) = self.get_vscroll(x / 8); - let pixel_b_x = (x - hscrolling_b) % (self.scroll_size.0 * 8); - let pixel_b_y = (y + vscrolling_b) % (self.scroll_size.1 * 8); - let pattern_b_addr = self.get_pattern_addr(self.scroll_b_addr, pixel_b_x / 8, pixel_b_y / 8); - let pattern_b_word = self.memory.read_beu16(Memory::Vram, pattern_b_addr); - let priority_b = (pattern_b_word & 0x8000) != 0; - let pixel_b = self.get_pattern_pixel(pattern_b_word, pixel_b_x % 8, pixel_b_y % 8); + let (priority_b, pixel_b) = if self.scroll_size != (0, 0) { + let pixel_b_x = (x - hscrolling_b) % (self.scroll_size.0 * 8); + let pixel_b_y = (y + vscrolling_b) % (self.scroll_size.1 * 8); + let pattern_b_addr = self.get_pattern_addr(self.scroll_b_addr, pixel_b_x / 8, pixel_b_y / 8); + let pattern_b_word = self.memory.read_beu16(Memory::Vram, pattern_b_addr); + let priority_b = (pattern_b_word & 0x8000) != 0; + let pixel_b = self.get_pattern_pixel(pattern_b_word, pixel_b_x % 8, pixel_b_y % 8); + (priority_b, pixel_b) + } else { + (false, (0, 0)) + }; - let pixel_a_x = (x - hscrolling_a) % (self.scroll_size.0 * 8); - let pixel_a_y = (y + vscrolling_a) % (self.scroll_size.1 * 8); - let pattern_a_addr = self.get_pattern_addr(self.scroll_a_addr, pixel_a_x / 8, pixel_a_y / 8); - let pattern_a_word = self.memory.read_beu16(Memory::Vram, pattern_a_addr); - let mut priority_a = (pattern_a_word & 0x8000) != 0; - let mut pixel_a = self.get_pattern_pixel(pattern_a_word, pixel_a_x % 8, pixel_a_y % 8); + let (mut priority_a, mut pixel_a) = if self.scroll_size != (0, 0) { + let pixel_a_x = (x - hscrolling_a) % (self.scroll_size.0 * 8); + let pixel_a_y = (y + vscrolling_a) % (self.scroll_size.1 * 8); + let pattern_a_addr = self.get_pattern_addr(self.scroll_a_addr, pixel_a_x / 8, pixel_a_y / 8); + let pattern_a_word = self.memory.read_beu16(Memory::Vram, pattern_a_addr); + let priority_a = (pattern_a_word & 0x8000) != 0; + let pixel_a = self.get_pattern_pixel(pattern_a_word, pixel_a_x % 8, pixel_a_y % 8); + (priority_a, pixel_a) + } else { + (false, (0, 0)) + }; if self.window_addr != 0 && self.is_inside_window(x, y) { let pixel_win_x = x - self.window_pos.0.0 * 8; @@ -548,6 +573,7 @@ impl Ym7101State { } } + #[rustfmt::skip] let pixels = match (priority_sprite, priority_a, priority_b) { (false, false, true) => [ pixel_b, pixel_sprite, pixel_a, bg_colour ], (true, false, true) => [ pixel_sprite, pixel_b, pixel_a, bg_colour ], @@ -628,12 +654,12 @@ impl Steppable for Ym7101 { } self.state.h_clock += diff; - if (self.state.status & STATUS_IN_HBLANK) != 0 && self.state.h_clock >= 2_340 && self.state.h_clock <= 61_160 { - self.state.status &= !STATUS_IN_HBLANK; + if (self.state.status & status::IN_HBLANK) != 0 && self.state.h_clock >= 2_340 && self.state.h_clock <= 61_160 { + self.state.status &= !status::IN_HBLANK; self.state.current_x = 0; } - if (self.state.status & STATUS_IN_HBLANK) == 0 && self.state.h_clock >= 61_160 { - self.state.status |= STATUS_IN_HBLANK; + if (self.state.status & status::IN_HBLANK) == 0 && self.state.h_clock >= 61_160 { + self.state.status |= status::IN_HBLANK; self.state.current_y += 1; self.state.h_scanlines = self.state.h_scanlines.wrapping_sub(1); @@ -647,18 +673,18 @@ impl Steppable for Ym7101 { } self.state.v_clock += diff; - if (self.state.status & STATUS_IN_VBLANK) != 0 && self.state.v_clock >= 1_205_992 && self.state.v_clock <= 15_424_008 { - self.state.status &= !STATUS_IN_VBLANK; + if (self.state.status & status::IN_VBLANK) != 0 && self.state.v_clock >= 1_205_992 && self.state.v_clock <= 15_424_008 { + self.state.status &= !status::IN_VBLANK; self.state.current_y = 0; } - if (self.state.status & STATUS_IN_VBLANK) == 0 && self.state.v_clock >= 15_424_008 { - self.state.status |= STATUS_IN_VBLANK; + if (self.state.status & status::IN_VBLANK) == 0 && self.state.v_clock >= 15_424_008 { + self.state.status |= status::IN_VBLANK; if self.state.vsync_int_enabled() { system.get_interrupt_controller().set(true, 6, 30)?; } - if (self.state.mode_1 & MODE1_BF_DISABLE_DISPLAY) == 0 { + if (self.state.mode_1 & mode1::BF_DISABLE_DISPLAY) == 0 && self.state.screen_size != (0, 0) { let mut frame = Frame::new(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8, self.sender.encoding()); self.state.draw_frame(&mut frame); self.sender.add(system.clock, frame); @@ -670,9 +696,9 @@ impl Steppable for Ym7101 { self.state.v_clock -= 16_630_000; } - if (self.state.mode_2 & MODE2_BF_DMA_ENABLED) != 0 { + if (self.state.mode_2 & mode2::BF_DMA_ENABLED) != 0 { self.state.memory.step_dma(system)?; - self.state.status = (self.state.status & !STATUS_DMA_BUSY) | (if self.state.memory.transfer_dma_busy { STATUS_DMA_BUSY } else { 0 }); + self.state.status = (self.state.status & !status::DMA_BUSY) | (if self.state.memory.transfer_dma_busy { status::DMA_BUSY } else { 0 }); } Ok(Frequency::from_hz(13_423_294).period_duration() * 4) @@ -712,52 +738,52 @@ impl Ym7101 { fn update_register_value(&mut self, reg: usize, data: u8) { match reg { - REG_MODE_SET_1 => { self.state.mode_1 = data; }, - REG_MODE_SET_2 => { + reg::MODE_SET_1 => { self.state.mode_1 = data; }, + reg::MODE_SET_2 => { self.state.mode_2 = data; self.state.update_screen_size(); }, - REG_SCROLL_A_ADDR => { self.state.scroll_a_addr = (data as usize) << 10; }, - REG_WINDOW_ADDR => { self.state.window_addr = (data as usize) << 10; }, - REG_SCROLL_B_ADDR => { self.state.scroll_b_addr = (data as usize) << 13; }, - REG_SPRITES_ADDR => { self.state.sprites_addr = (data as usize) << 9; }, - REG_BACKGROUND => { self.state.background = data; }, - REG_H_INTERRUPT => { self.state.h_int_lines = data; }, - REG_MODE_SET_3 => { self.state.mode_3 = data; }, - REG_MODE_SET_4 => { + reg::SCROLL_A_ADDR => { self.state.scroll_a_addr = (data as usize) << 10; }, + reg::WINDOW_ADDR => { self.state.window_addr = (data as usize) << 10; }, + reg::SCROLL_B_ADDR => { self.state.scroll_b_addr = (data as usize) << 13; }, + reg::SPRITES_ADDR => { self.state.sprites_addr = (data as usize) << 9; }, + reg::BACKGROUND => { self.state.background = data; }, + reg::H_INTERRUPT => { self.state.h_int_lines = data; }, + reg::MODE_SET_3 => { self.state.mode_3 = data; }, + reg::MODE_SET_4 => { self.state.mode_4 = data; self.state.update_screen_size(); }, - REG_HSCROLL_ADDR => { self.state.hscroll_addr = (data as usize) << 10; }, - REG_AUTO_INCREMENT => { self.state.memory.transfer_auto_inc = data as u32; }, - REG_SCROLL_SIZE => { + reg::HSCROLL_ADDR => { self.state.hscroll_addr = (data as usize) << 10; }, + reg::AUTO_INCREMENT => { self.state.memory.transfer_auto_inc = data as u32; }, + reg::SCROLL_SIZE => { let h = decode_scroll_size(data & 0x03); let v = decode_scroll_size((data >> 4) & 0x03); self.state.scroll_size = (h, v); }, - REG_WINDOW_H_POS => { + reg::WINDOW_H_POS => { self.state.window_values.0 = data; self.state.update_window_position(); }, - REG_WINDOW_V_POS => { + reg::WINDOW_V_POS => { self.state.window_values.1 = data; self.state.update_window_position(); }, - REG_DMA_COUNTER_LOW => { + reg::DMA_COUNTER_LOW => { self.state.memory.transfer_count = (self.state.memory.transfer_count & 0xFF00) | data as u32; self.state.memory.transfer_remain = self.state.memory.transfer_count; }, - REG_DMA_COUNTER_HIGH => { + reg::DMA_COUNTER_HIGH => { self.state.memory.transfer_count = (self.state.memory.transfer_count & 0x00FF) | ((data as u32) << 8); self.state.memory.transfer_remain = self.state.memory.transfer_count; }, - REG_DMA_ADDR_LOW => { + reg::DMA_ADDR_LOW => { self.state.memory.transfer_src_addr = (self.state.memory.transfer_src_addr & 0xFFFE00) | ((data as u32) << 1); }, - REG_DMA_ADDR_MID => { + reg::DMA_ADDR_MID => { self.state.memory.transfer_src_addr = (self.state.memory.transfer_src_addr & 0xFE01FF) | ((data as u32) << 9); }, - REG_DMA_ADDR_HIGH => { + reg::DMA_ADDR_HIGH => { let mask = if (data & 0x80) == 0 { 0x7F } else { 0x3F }; self.state.memory.transfer_bits = data & 0xC0; self.state.memory.transfer_src_addr = (self.state.memory.transfer_src_addr & 0x01FFFF) | (((data & mask) as u32) << 17); @@ -834,7 +860,7 @@ impl Addressable for Ym7101 { } } else { self.state.memory.write_control_port(data)?; - self.state.status = (self.state.status & !STATUS_DMA_BUSY) | (if self.state.memory.transfer_dma_busy { STATUS_DMA_BUSY } else { 0 }); + self.state.status = (self.state.status & !status::DMA_BUSY) | (if self.state.memory.transfer_dma_busy { status::DMA_BUSY } else { 0 }); } }, diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index dde13b4..ed5e3ee 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -2,7 +2,7 @@ const DEFAULT_HARTE_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/"; use std::io::prelude::*; -use std::fmt::Debug; +use std::fmt::{Debug, UpperHex}; use std::path::PathBuf; use std::time::SystemTime; use std::fs::{self, File}; @@ -157,11 +157,14 @@ fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, Syst Ok((cpu, system)) } -fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> { +fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> +where + T: PartialEq + Debug + UpperHex +{ if actual == expected { Ok(()) } else { - Err(Error::assertion(&format!("{:?} != {:?}, {}", actual, expected, message))) + Err(Error::assertion(&format!("{:#X} != {:#X}, {}", actual, expected, message))) } } diff --git a/tests/rad_tests/progress/2023-05-15-without-undoc-but-timings-checked.txt b/tests/rad_tests/progress/2023-05-15-without-undoc-but-timings-checked.txt new file mode 100644 index 0000000..9021420 --- /dev/null +++ b/tests/rad_tests/progress/2023-05-15-without-undoc-but-timings-checked.txt @@ -0,0 +1,647 @@ +Last run on 2023-05-15 at commit f205e231b62d62c72186c1d9f5277e2bce693380 + +00.json completed, all passed! +01.json completed, all passed! +02.json completed, all passed! +03.json completed, all passed! +04.json completed, all passed! +05.json completed, all passed! +06.json completed, all passed! +07.json completed, all passed! +08.json completed, all passed! +09.json completed, all passed! +0a.json completed, all passed! +0b.json completed, all passed! +0c.json completed, all passed! +0d.json completed, all passed! +0e.json completed, all passed! +0f.json completed, all passed! +10.json completed, all passed! +100.json completed, all passed! +101.json completed, all passed! +11.json completed, all passed! +12.json completed, all passed! +13.json completed, all passed! +14.json completed, all passed! +15.json completed, all passed! +16.json completed, all passed! +17.json completed, all passed! +18.json completed, all passed! +19.json completed, all passed! +1a.json completed, all passed! +1b.json completed, all passed! +1c.json completed, all passed! +1d.json completed, all passed! +1e.json completed, all passed! +1f.json completed, all passed! +20.json completed, all passed! +21.json completed, all passed! +22.json completed, all passed! +23.json completed, all passed! +24.json completed, all passed! +25.json completed, all passed! +26.json completed, all passed! +27.json completed: 547 passed, 453 FAILED +28.json completed, all passed! +29.json completed, all passed! +2a.json completed, all passed! +2b.json completed, all passed! +2c.json completed, all passed! +2d.json completed, all passed! +2e.json completed, all passed! +2f.json completed, all passed! +30.json completed, all passed! +31.json completed, all passed! +32.json completed, all passed! +33.json completed, all passed! +34.json completed, all passed! +35.json completed, all passed! +36.json completed, all passed! +37.json completed, all passed! +38.json completed, all passed! +39.json completed, all passed! +3a.json completed, all passed! +3b.json completed, all passed! +3c.json completed, all passed! +3d.json completed, all passed! +3e.json completed, all passed! +3f.json completed, all passed! +40.json completed, all passed! +41.json completed, all passed! +42.json completed, all passed! +43.json completed, all passed! +44.json completed, all passed! +45.json completed, all passed! +46.json completed, all passed! +47.json completed, all passed! +48.json completed, all passed! +49.json completed, all passed! +4a.json completed, all passed! +4b.json completed, all passed! +4c.json completed, all passed! +4d.json completed, all passed! +4e.json completed, all passed! +4f.json completed, all passed! +50.json completed, all passed! +51.json completed, all passed! +52.json completed, all passed! +53.json completed, all passed! +54.json completed, all passed! +55.json completed, all passed! +56.json completed, all passed! +57.json completed, all passed! +58.json completed, all passed! +59.json completed, all passed! +5a.json completed, all passed! +5b.json completed, all passed! +5c.json completed, all passed! +5d.json completed, all passed! +5e.json completed, all passed! +5f.json completed, all passed! +60.json completed, all passed! +61.json completed, all passed! +62.json completed, all passed! +63.json completed, all passed! +64.json completed, all passed! +65.json completed, all passed! +66.json completed, all passed! +67.json completed, all passed! +68.json completed, all passed! +69.json completed, all passed! +6a.json completed, all passed! +6b.json completed, all passed! +6c.json completed, all passed! +6d.json completed, all passed! +6e.json completed, all passed! +6f.json completed, all passed! +70.json completed, all passed! +71.json completed, all passed! +72.json completed, all passed! +73.json completed, all passed! +74.json completed, all passed! +75.json completed, all passed! +76.json completed, all passed! +77.json completed, all passed! +78.json completed, all passed! +79.json completed, all passed! +7a.json completed, all passed! +7b.json completed, all passed! +7c.json completed, all passed! +7d.json completed, all passed! +7e.json completed, all passed! +7f.json completed, all passed! +80.json completed, all passed! +81.json completed, all passed! +82.json completed, all passed! +83.json completed, all passed! +84.json completed, all passed! +85.json completed, all passed! +86.json completed, all passed! +87.json completed, all passed! +88.json completed, all passed! +89.json completed, all passed! +8a.json completed, all passed! +8b.json completed, all passed! +8c.json completed, all passed! +8d.json completed, all passed! +8e.json completed, all passed! +8f.json completed, all passed! +90.json completed, all passed! +91.json completed, all passed! +92.json completed, all passed! +93.json completed, all passed! +94.json completed, all passed! +95.json completed, all passed! +96.json completed, all passed! +97.json completed, all passed! +98.json completed, all passed! +99.json completed, all passed! +9a.json completed, all passed! +9b.json completed, all passed! +9c.json completed, all passed! +9d.json completed, all passed! +9e.json completed, all passed! +9f.json completed, all passed! +a0.json completed, all passed! +a1.json completed, all passed! +a2.json completed, all passed! +a3.json completed, all passed! +a4.json completed, all passed! +a5.json completed, all passed! +a6.json completed, all passed! +a7.json completed, all passed! +a8.json completed, all passed! +a9.json completed, all passed! +aa.json completed, all passed! +ab.json completed, all passed! +ac.json completed, all passed! +ad.json completed, all passed! +ae.json completed, all passed! +af.json completed, all passed! +b0.json completed, all passed! +b1.json completed, all passed! +b2.json completed, all passed! +b3.json completed, all passed! +b4.json completed, all passed! +b5.json completed, all passed! +b6.json completed, all passed! +b7.json completed, all passed! +b8.json completed, all passed! +b9.json completed, all passed! +ba.json completed, all passed! +bb.json completed, all passed! +bc.json completed, all passed! +bd.json completed, all passed! +be.json completed, all passed! +bf.json completed, all passed! +c0.json completed, all passed! +c1.json completed, all passed! +c2.json completed, all passed! +c3.json completed, all passed! +c4.json completed, all passed! +c5.json completed, all passed! +c6.json completed, all passed! +c7.json completed, all passed! +c8.json completed, all passed! +c9.json completed, all passed! +ca.json completed, all passed! +cb 00.json completed, all passed! +cb 01.json completed, all passed! +cb 02.json completed, all passed! +cb 03.json completed, all passed! +cb 04.json completed, all passed! +cb 05.json completed, all passed! +cb 06.json completed, all passed! +cb 07.json completed, all passed! +cb 08.json completed, all passed! +cb 09.json completed, all passed! +cb 0a.json completed, all passed! +cb 0b.json completed, all passed! +cb 0c.json completed, all passed! +cb 0d.json completed, all passed! +cb 0e.json completed, all passed! +cb 0f.json completed, all passed! +cb 10.json completed, all passed! +cb 11.json completed, all passed! +cb 12.json completed, all passed! +cb 13.json completed, all passed! +cb 14.json completed, all passed! +cb 15.json completed, all passed! +cb 16.json completed, all passed! +cb 17.json completed, all passed! +cb 18.json completed, all passed! +cb 19.json completed, all passed! +cb 1a.json completed, all passed! +cb 1b.json completed, all passed! +cb 1c.json completed, all passed! +cb 1d.json completed, all passed! +cb 1e.json completed, all passed! +cb 1f.json completed, all passed! +cb 20.json completed, all passed! +cb 21.json completed, all passed! +cb 22.json completed, all passed! +cb 23.json completed, all passed! +cb 24.json completed, all passed! +cb 25.json completed, all passed! +cb 26.json completed, all passed! +cb 27.json completed, all passed! +cb 28.json completed, all passed! +cb 29.json completed, all passed! +cb 2a.json completed, all passed! +cb 2b.json completed, all passed! +cb 2c.json completed, all passed! +cb 2d.json completed, all passed! +cb 2e.json completed, all passed! +cb 2f.json completed, all passed! +cb 38.json completed, all passed! +cb 39.json completed, all passed! +cb 3a.json completed, all passed! +cb 3b.json completed, all passed! +cb 3c.json completed, all passed! +cb 3d.json completed, all passed! +cb 3e.json completed, all passed! +cb 3f.json completed, all passed! +cb 40.json completed, all passed! +cb 41.json completed, all passed! +cb 42.json completed, all passed! +cb 43.json completed, all passed! +cb 44.json completed, all passed! +cb 45.json completed, all passed! +cb 46.json completed, all passed! +cb 47.json completed, all passed! +cb 48.json completed, all passed! +cb 49.json completed, all passed! +cb 4a.json completed, all passed! +cb 4b.json completed, all passed! +cb 4c.json completed, all passed! +cb 4d.json completed, all passed! +cb 4e.json completed, all passed! +cb 4f.json completed, all passed! +cb 50.json completed, all passed! +cb 51.json completed, all passed! +cb 52.json completed, all passed! +cb 53.json completed, all passed! +cb 54.json completed, all passed! +cb 55.json completed, all passed! +cb 56.json completed, all passed! +cb 57.json completed, all passed! +cb 58.json completed, all passed! +cb 59.json completed, all passed! +cb 5a.json completed, all passed! +cb 5b.json completed, all passed! +cb 5c.json completed, all passed! +cb 5d.json completed, all passed! +cb 5e.json completed, all passed! +cb 5f.json completed, all passed! +cb 60.json completed, all passed! +cb 61.json completed, all passed! +cb 62.json completed, all passed! +cb 63.json completed, all passed! +cb 64.json completed, all passed! +cb 65.json completed, all passed! +cb 66.json completed, all passed! +cb 67.json completed, all passed! +cb 68.json completed, all passed! +cb 69.json completed, all passed! +cb 6a.json completed, all passed! +cb 6b.json completed, all passed! +cb 6c.json completed, all passed! +cb 6d.json completed, all passed! +cb 6e.json completed, all passed! +cb 6f.json completed, all passed! +cb 70.json completed, all passed! +cb 71.json completed, all passed! +cb 72.json completed, all passed! +cb 73.json completed, all passed! +cb 74.json completed, all passed! +cb 75.json completed, all passed! +cb 76.json completed, all passed! +cb 77.json completed, all passed! +cb 78.json completed, all passed! +cb 79.json completed, all passed! +cb 7a.json completed, all passed! +cb 7b.json completed, all passed! +cb 7c.json completed, all passed! +cb 7d.json completed, all passed! +cb 7e.json completed, all passed! +cb 7f.json completed, all passed! +cb 80.json completed, all passed! +cb 81.json completed, all passed! +cb 82.json completed, all passed! +cb 83.json completed, all passed! +cb 84.json completed, all passed! +cb 85.json completed, all passed! +cb 86.json completed, all passed! +cb 87.json completed, all passed! +cb 88.json completed, all passed! +cb 89.json completed, all passed! +cb 8a.json completed, all passed! +cb 8b.json completed, all passed! +cb 8c.json completed, all passed! +cb 8d.json completed, all passed! +cb 8e.json completed, all passed! +cb 8f.json completed, all passed! +cb 90.json completed, all passed! +cb 91.json completed, all passed! +cb 92.json completed, all passed! +cb 93.json completed, all passed! +cb 94.json completed, all passed! +cb 95.json completed, all passed! +cb 96.json completed, all passed! +cb 97.json completed, all passed! +cb 98.json completed, all passed! +cb 99.json completed, all passed! +cb 9a.json completed, all passed! +cb 9b.json completed, all passed! +cb 9c.json completed, all passed! +cb 9d.json completed, all passed! +cb 9e.json completed, all passed! +cb 9f.json completed, all passed! +cb a0.json completed, all passed! +cb a1.json completed, all passed! +cb a2.json completed, all passed! +cb a3.json completed, all passed! +cb a4.json completed, all passed! +cb a5.json completed, all passed! +cb a6.json completed, all passed! +cb a7.json completed, all passed! +cb a8.json completed, all passed! +cb a9.json completed, all passed! +cb aa.json completed, all passed! +cb ab.json completed, all passed! +cb ac.json completed, all passed! +cb ad.json completed, all passed! +cb ae.json completed, all passed! +cb af.json completed, all passed! +cb b0.json completed, all passed! +cb b1.json completed, all passed! +cb b2.json completed, all passed! +cb b3.json completed, all passed! +cb b4.json completed, all passed! +cb b5.json completed, all passed! +cb b6.json completed, all passed! +cb b7.json completed, all passed! +cb b8.json completed, all passed! +cb b9.json completed, all passed! +cb ba.json completed, all passed! +cb bb.json completed, all passed! +cb bc.json completed, all passed! +cb bd.json completed, all passed! +cb be.json completed, all passed! +cb bf.json completed, all passed! +cb c0.json completed, all passed! +cb c1.json completed, all passed! +cb c2.json completed, all passed! +cb c3.json completed, all passed! +cb c4.json completed, all passed! +cb c5.json completed, all passed! +cb c6.json completed, all passed! +cb c7.json completed, all passed! +cb c8.json completed, all passed! +cb c9.json completed, all passed! +cb ca.json completed, all passed! +cb cb.json completed, all passed! +cb cc.json completed, all passed! +cb cd.json completed, all passed! +cb ce.json completed, all passed! +cb cf.json completed, all passed! +cb d0.json completed, all passed! +cb d1.json completed, all passed! +cb d2.json completed, all passed! +cb d3.json completed, all passed! +cb d4.json completed, all passed! +cb d5.json completed, all passed! +cb d6.json completed, all passed! +cb d7.json completed, all passed! +cb d8.json completed, all passed! +cb d9.json completed, all passed! +cb da.json completed, all passed! +cb db.json completed, all passed! +cb dc.json completed, all passed! +cb dd.json completed, all passed! +cb de.json completed, all passed! +cb df.json completed, all passed! +cb e0.json completed, all passed! +cb e1.json completed, all passed! +cb e2.json completed, all passed! +cb e3.json completed, all passed! +cb e4.json completed, all passed! +cb e5.json completed, all passed! +cb e6.json completed, all passed! +cb e7.json completed, all passed! +cb e8.json completed, all passed! +cb e9.json completed, all passed! +cb ea.json completed, all passed! +cb eb.json completed, all passed! +cb ec.json completed, all passed! +cb ed.json completed, all passed! +cb ee.json completed, all passed! +cb ef.json completed, all passed! +cb f0.json completed, all passed! +cb f1.json completed, all passed! +cb f2.json completed, all passed! +cb f3.json completed, all passed! +cb f4.json completed, all passed! +cb f5.json completed, all passed! +cb f6.json completed, all passed! +cb f7.json completed, all passed! +cb f8.json completed, all passed! +cb f9.json completed, all passed! +cb fa.json completed, all passed! +cb fb.json completed, all passed! +cb fc.json completed, all passed! +cb fd.json completed, all passed! +cb fe.json completed, all passed! +cb ff.json completed, all passed! +cc.json completed, all passed! +cd.json completed, all passed! +ce.json completed, all passed! +cf.json completed, all passed! +d0.json completed, all passed! +d1.json completed, all passed! +d2.json completed, all passed! +d3.json completed, all passed! +d4.json completed, all passed! +d5.json completed, all passed! +d6.json completed, all passed! +d7.json completed, all passed! +d8.json completed, all passed! +d9.json completed, all passed! +da.json completed, all passed! +db.json completed, all passed! +dc.json completed, all passed! +dd 09.json completed, all passed! +dd 19.json completed, all passed! +dd 29.json completed, all passed! +dd 36.json completed, all passed! +dd 39.json completed, all passed! +dd 46.json completed, all passed! +dd 4e.json completed, all passed! +dd 56.json completed, all passed! +dd 5e.json completed, all passed! +dd 66.json completed, all passed! +dd 6e.json completed, all passed! +dd 70.json completed, all passed! +dd 71.json completed, all passed! +dd 72.json completed, all passed! +dd 73.json completed, all passed! +dd 74.json completed, all passed! +dd 75.json completed, all passed! +dd 77.json completed, all passed! +dd 7e.json completed, all passed! +dd 86.json completed, all passed! +dd 8e.json completed, all passed! +dd 96.json completed, all passed! +dd 9e.json completed, all passed! +dd a6.json completed, all passed! +dd ae.json completed, all passed! +dd b6.json completed, all passed! +dd be.json completed, all passed! +dd e1.json completed, all passed! +dd e3.json completed, all passed! +dd e5.json completed, all passed! +dd e9.json completed, all passed! +dd f9.json completed, all passed! +de.json completed, all passed! +df.json completed, all passed! +e0.json completed, all passed! +e1.json completed, all passed! +e2.json completed, all passed! +e3.json completed, all passed! +e4.json completed, all passed! +e5.json completed, all passed! +e6.json completed, all passed! +e7.json completed, all passed! +e8.json completed, all passed! +e9.json completed, all passed! +ea.json completed, all passed! +eb.json completed, all passed! +ec.json completed, all passed! +ed 40.json completed, all passed! +ed 41.json completed, all passed! +ed 42.json completed, all passed! +ed 43.json completed, all passed! +ed 44.json completed, all passed! +ed 45.json completed, all passed! +ed 46.json completed, all passed! +ed 47.json completed, all passed! +ed 48.json completed, all passed! +ed 49.json completed, all passed! +ed 4a.json completed, all passed! +ed 4b.json completed, all passed! +ed 4c.json completed, all passed! +ed 4d.json completed, all passed! +ed 4e.json completed, all passed! +ed 4f.json completed, all passed! +ed 50.json completed, all passed! +ed 51.json completed, all passed! +ed 52.json completed, all passed! +ed 53.json completed, all passed! +ed 54.json completed, all passed! +ed 55.json completed, all passed! +ed 56.json completed, all passed! +ed 57.json completed, all passed! +ed 58.json completed, all passed! +ed 59.json completed, all passed! +ed 5a.json completed, all passed! +ed 5b.json completed, all passed! +ed 5c.json completed, all passed! +ed 5d.json completed, all passed! +ed 5e.json completed, all passed! +ed 5f.json completed, all passed! +ed 60.json completed, all passed! +ed 61.json completed, all passed! +ed 62.json completed, all passed! +ed 64.json completed, all passed! +ed 65.json completed, all passed! +ed 66.json completed, all passed! +ed 67.json completed, all passed! +ed 68.json completed, all passed! +ed 69.json completed, all passed! +ed 6a.json completed, all passed! +ed 6c.json completed, all passed! +ed 6d.json completed, all passed! +ed 6e.json completed, all passed! +ed 6f.json completed, all passed! +ed 72.json completed, all passed! +ed 73.json completed, all passed! +ed 74.json completed, all passed! +ed 75.json completed, all passed! +ed 76.json completed, all passed! +ed 77.json completed: 0 passed, 1000 FAILED +ed 78.json completed, all passed! +ed 79.json completed, all passed! +ed 7a.json completed, all passed! +ed 7b.json completed, all passed! +ed 7c.json completed, all passed! +ed 7d.json completed, all passed! +ed 7e.json completed, all passed! +ed 7f.json completed: 0 passed, 1000 FAILED +ed a0.json completed, all passed! +ed a1.json completed: 0 passed, 1000 FAILED +ed a2.json completed: 13 passed, 987 FAILED +ed a3.json completed: 0 passed, 1000 FAILED +ed a8.json completed, all passed! +ed a9.json completed: 0 passed, 1000 FAILED +ed aa.json completed: 0 passed, 1000 FAILED +ed ab.json completed: 0 passed, 1000 FAILED +ed b0.json completed, all passed! +ed b1.json completed: 0 passed, 1000 FAILED +ed b2.json completed: 0 passed, 1000 FAILED +ed b3.json completed: 0 passed, 1000 FAILED +ed b8.json completed, all passed! +ed b9.json completed: 0 passed, 1000 FAILED +ed ba.json completed: 0 passed, 1000 FAILED +ed bb.json completed: 0 passed, 1000 FAILED +ee.json completed, all passed! +ef.json completed, all passed! +f0.json completed, all passed! +f1.json completed, all passed! +f2.json completed, all passed! +f3.json completed, all passed! +f4.json completed, all passed! +f5.json completed, all passed! +f6.json completed, all passed! +f7.json completed, all passed! +f8.json completed, all passed! +f9.json completed, all passed! +fa.json completed, all passed! +fb.json completed, all passed! +fc.json completed, all passed! +fd 09.json completed, all passed! +fd 19.json completed, all passed! +fd 29.json completed, all passed! +fd 36.json completed, all passed! +fd 39.json completed, all passed! +fd 46.json completed, all passed! +fd 4e.json completed, all passed! +fd 56.json completed, all passed! +fd 5e.json completed, all passed! +fd 66.json completed, all passed! +fd 6e.json completed, all passed! +fd 70.json completed, all passed! +fd 71.json completed, all passed! +fd 72.json completed, all passed! +fd 73.json completed, all passed! +fd 74.json completed, all passed! +fd 75.json completed, all passed! +fd 77.json completed, all passed! +fd 7e.json completed, all passed! +fd 86.json completed, all passed! +fd 8e.json completed, all passed! +fd 96.json completed, all passed! +fd 9e.json completed, all passed! +fd a6.json completed, all passed! +fd ae.json completed, all passed! +fd b6.json completed, all passed! +fd be.json completed, all passed! +fd e1.json completed, all passed! +fd e3.json completed, all passed! +fd e5.json completed, all passed! +fd e9.json completed, all passed! +fd f9.json completed, all passed! +fe.json completed, all passed! +ff.json completed, all passed! + +passed: 627560, failed: 14440, total 98% +completed in 0m 35s diff --git a/todo.txt b/todo.txt index ccd6718..2f20555 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,8 @@ +* the way you're doing debugging is so bad, and something's broken with the Z80 +* debugger should return a breakpoint error to the frontend, so that the frontend still runs, instead of suspending the current execution +* can you make the debugger workable in the web ui in some way? So you can have a debug window open while playing the game or something + * I like making address adapters like this (below) * you could have busport take a closure or something which translates the address, and returns an error that will be passed up if it occurs in order to implement the correct behaviour for address exceptions in 68k, transparently @@ -12,6 +16,8 @@ * should you make Address a newtype and add From impls for each type of numeric, and add utils to wrap address at certain boundaries and such * should you make a means of storing different kinds of buses? * should you make buses hide their RcRefCell? +* make functions for creating a processor instance from the cpu type (M68k::from_type()), ie. initialize the busport internally with the correct + bitwidths, but it would still be possible to initialize the CPU manually to create one that never existed as such * address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used