pinky/mos6502/tests/lib.rs
2016-10-23 19:50:32 +02:00

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 ) );
}
}