mirror of
https://github.com/koute/pinky.git
synced 2025-04-02 10:31:50 -04:00
163 lines
4.7 KiB
Rust
163 lines
4.7 KiB
Rust
extern crate mos6502;
|
|
extern crate emumisc;
|
|
|
|
use emumisc::copy_memory;
|
|
use mos6502::{Interface, State, Context, Address, EmulationStatus};
|
|
|
|
static ROM_BCD_VERIFY: &'static [u8] = include_bytes!( "../roms/bcd_verify.bin" );
|
|
static ROM_6502_FUNCTIONAL_TEST: &'static [u8] = include_bytes!( "../roms/6502_functional_test.bin" );
|
|
static ROM_TTL6502: &'static [u8] = include_bytes!( "../roms/TTL6502.bin" );
|
|
|
|
struct DummyHost {
|
|
ram: [u8; 0xFFFF + 1],
|
|
cycle: usize,
|
|
cpu_state: State
|
|
}
|
|
|
|
impl DummyHost {
|
|
pub fn new() -> DummyHost {
|
|
DummyHost {
|
|
ram: [0; 0xFFFF + 1],
|
|
cycle: 0,
|
|
cpu_state: State::new()
|
|
}
|
|
}
|
|
|
|
pub fn load_binary( &mut self, addr: Address, data: &[u8] ) {
|
|
assert!( addr as usize + data.len() <= self.ram.len() );
|
|
copy_memory( data, &mut self.ram[ addr as usize.. ] );
|
|
}
|
|
}
|
|
|
|
impl Context for DummyHost {
|
|
#[inline(always)]
|
|
fn state_mut( &mut self ) -> &mut State {
|
|
&mut self.cpu_state
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn state( &self ) -> &State {
|
|
&self.cpu_state
|
|
}
|
|
|
|
fn peek( &mut self, addr: u16 ) -> u8 {
|
|
self.cycle += 1;
|
|
self.ram[ addr as usize ]
|
|
}
|
|
|
|
fn poke( &mut self, addr: u16, value: u8 ) {
|
|
self.cycle += 1;
|
|
self.ram[ addr as usize ] = value;
|
|
}
|
|
|
|
fn bcd_mode_supported() -> bool {
|
|
true
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_sample_bcd_verify() {
|
|
let mut context = DummyHost::new();
|
|
context.load_binary( 0xE000, ROM_BCD_VERIFY );
|
|
context.reset();
|
|
|
|
loop {
|
|
let status = context.execute();
|
|
match status {
|
|
Ok( EmulationStatus::Normal ) => continue,
|
|
Ok( EmulationStatus::InfiniteLoop( pc ) ) => {
|
|
assert_eq!( pc, 0xF100 );
|
|
break;
|
|
},
|
|
Err(_) => assert!( false, format!( "{:?}", status ) )
|
|
}
|
|
}
|
|
|
|
let result = context.ram[ 0xE004 ];
|
|
if result != 0 {
|
|
let culprit = context.ram[ 0xE011 ];
|
|
let culprit_2 = context.ram[ 0xE012 ];
|
|
let num_1 = context.ram[ 0xE007 ];
|
|
let num_2 = context.ram[ 0xE00A ];
|
|
let expected = context.ram[ 0xE000 ];
|
|
let got = context.ram[ 0xE002 ];
|
|
let got_flags = context.ram[ 0xE003 ];
|
|
let expected_n = context.ram[ 0xE00C ];
|
|
let expected_v = context.ram[ 0xE00D ];
|
|
let expected_z = context.ram[ 0xE00E ];
|
|
let expected_c = context.ram[ 0xE001 ];
|
|
|
|
println!( "Broken BCD handling:" );
|
|
print!( " Instruction: " );
|
|
|
|
match culprit {
|
|
0x50 => println!( "ADC" ),
|
|
0x51 => println!( "SBC" ),
|
|
_ => println!( "WTF: {}", culprit )
|
|
}
|
|
|
|
print!( " Culprit: " );
|
|
match culprit_2 {
|
|
0x60 => println!( "result" ),
|
|
0x61 => println!( "N flag" ),
|
|
0x62 => println!( "V flag" ),
|
|
0x63 => println!( "Z flag" ),
|
|
0x64 => println!( "C flag" ),
|
|
_ => println!( "WTF: {}", culprit_2 )
|
|
}
|
|
|
|
println!( " Number #1: 0x{:02X}", num_1 );
|
|
println!( " Number #2: 0x{:02X}", num_2 );
|
|
println!( " Expected: 0x{:02X}, got 0x{:02X}", expected, got );
|
|
println!( " Flags:" );
|
|
println!( " NV----ZC" );
|
|
println!( " Got: {:08b}", got_flags );
|
|
println!( " Expected: {:}{}----{}{}",
|
|
((expected_n & (1 << 7)) != 0) as u8,
|
|
((expected_v & (1 << 6)) != 0) as u8,
|
|
((expected_z & (1 << 1)) != 0) as u8,
|
|
((expected_c & (1 << 0)) != 0) as u8
|
|
);
|
|
println!( " Cycle count: {}", context.cycle );
|
|
panic!();
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_sample_6502_functional_test() {
|
|
let mut context = DummyHost::new();
|
|
context.load_binary( 0x0000, ROM_6502_FUNCTIONAL_TEST );
|
|
context.set_pc( 0x400 );
|
|
|
|
loop {
|
|
let status = context.execute();
|
|
match status {
|
|
Ok( EmulationStatus::Normal ) => continue,
|
|
Ok( EmulationStatus::InfiniteLoop( pc ) ) => {
|
|
assert_eq!( pc, 0x3399 ); // Infinite loop at this address means success.
|
|
break;
|
|
},
|
|
Err(_) => assert!( false, format!( "{:?}", status ) )
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_sample_ttl6502() {
|
|
let mut context = DummyHost::new();
|
|
context.load_binary( 0xE000, ROM_TTL6502 );
|
|
context.reset();
|
|
|
|
loop {
|
|
/*
|
|
This is where TTL6502 starts to test the BCD mode which has different behavior
|
|
from the one which we emulate.
|
|
*/
|
|
if context.pc() == 0xF5B6 {
|
|
break;
|
|
}
|
|
|
|
let status = context.execute();
|
|
assert_eq!( status, Ok( EmulationStatus::Normal ) );
|
|
}
|
|
}
|