You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
6.5 KiB

use crate::cpu::AddressingMode;
use crate::cpu::Mem;
use crate::cpu::CPU;
use crate::opcodes;
use std::collections::HashMap;
pub fn trace(cpu: &CPU) -> String {
let ref opscodes: HashMap<u8, &'static opcodes::OpCode> = *opcodes::OPCODES_MAP;
let code = cpu.mem_read(cpu.program_counter);
let ops = opscodes.get(&code).unwrap();
let begin = cpu.program_counter;
let mut hex_dump = vec![];
hex_dump.push(code);
let (mem_addr, stored_value) = match ops.mode {
AddressingMode::Immediate | AddressingMode::NoneAddressing => (0, 0),
_ => {
let addr = cpu.get_absolute_address(&ops.mode, begin + 1);
(addr, cpu.mem_read(addr))
}
};
let tmp = match ops.len {
1 => match ops.code {
0x0a | 0x4a | 0x2a | 0x6a => format!("A "),
_ => String::from(""),
},
2 => {
let address: u8 = cpu.mem_read(begin + 1);
// let value = cpu.mem_read(address));
hex_dump.push(address);
match ops.mode {
AddressingMode::Immediate => format!("#${:02x}", address),
AddressingMode::ZeroPage => format!("${:02x} = {:02x}", mem_addr, stored_value),
AddressingMode::ZeroPage_X => format!(
"${:02x},X @ {:02x} = {:02x}",
address, mem_addr, stored_value
),
AddressingMode::ZeroPage_Y => format!(
"${:02x},Y @ {:02x} = {:02x}",
address, mem_addr, stored_value
),
AddressingMode::Indirect_X => format!(
"(${:02x},X) @ {:02x} = {:04x} = {:02x}",
address,
(address.wrapping_add(cpu.register_x)),
mem_addr,
stored_value
),
AddressingMode::Indirect_Y => format!(
"(${:02x}),Y = {:04x} @ {:04x} = {:02x}",
address,
(mem_addr.wrapping_sub(cpu.register_y as u16)),
mem_addr,
stored_value
),
AddressingMode::NoneAddressing => {
// assuming local jumps: BNE, BVS, etc....
let address: usize =
(begin as usize + 2).wrapping_add((address as i8) as usize);
format!("${:04x}", address)
}
_ => panic!(
"unexpected addressing mode {:?} has ops-len 2. code {:02x}",
ops.mode, ops.code
),
}
}
3 => {
let address_lo = cpu.mem_read(begin + 1);
let address_hi = cpu.mem_read(begin + 2);
hex_dump.push(address_lo);
hex_dump.push(address_hi);
let address = cpu.mem_read_u16(begin + 1);
match ops.mode {
AddressingMode::NoneAddressing => {
if ops.code == 0x6c {
//jmp indirect
let jmp_addr = if address & 0x00FF == 0x00FF {
let lo = cpu.mem_read(address);
let hi = cpu.mem_read(address & 0xFF00);
(hi as u16) << 8 | (lo as u16)
} else {
cpu.mem_read_u16(address)
};
// let jmp_addr = cpu.mem_read_u16(address);
format!("(${:04x}) = {:04x}", address, jmp_addr)
} else {
format!("${:04x}", address)
}
}
AddressingMode::Absolute => format!("${:04x} = {:02x}", mem_addr, stored_value),
AddressingMode::Absolute_X => format!(
"${:04x},X @ {:04x} = {:02x}",
address, mem_addr, stored_value
),
AddressingMode::Absolute_Y => format!(
"${:04x},Y @ {:04x} = {:02x}",
address, mem_addr, stored_value
),
_ => panic!(
"unexpected addressing mode {:?} has ops-len 3. code {:02x}",
ops.mode, ops.code
),
}
}
_ => String::from(""),
};
let hex_str = hex_dump
.iter()
.map(|z| format!("{:02x}", z))
.collect::<Vec<String>>()
.join(" ");
let asm_str = format!("{:04x} {:8} {: >4} {}", begin, hex_str, ops.mnemonic, tmp)
.trim()
.to_string();
format!(
"{:47} A:{:02x} X:{:02x} Y:{:02x} P:{:02x} SP:{:02x}",
asm_str, cpu.register_a, cpu.register_x, cpu.register_y, cpu.status, cpu.stack_pointer,
)
.to_ascii_uppercase()
}
#[cfg(test)]
mod test {
use super::*;
use crate::bus::Bus;
use crate::cartridge::test::test_rom;
#[test]
fn test_format_trace() {
let mut bus = Bus::new(test_rom(vec![]));
bus.mem_write(100, 0xa2);
bus.mem_write(101, 0x01);
bus.mem_write(102, 0xca);
bus.mem_write(103, 0x88);
bus.mem_write(104, 0x00);
let mut cpu = CPU::new(bus);
cpu.program_counter = 0x64;
cpu.register_a = 1;
cpu.register_x = 2;
cpu.register_y = 3;
let mut result: Vec<String> = vec![];
cpu.run_with_callback(|cpu| {
result.push(trace(cpu));
});
assert_eq!(
"0064 A2 01 LDX #$01 A:01 X:02 Y:03 P:24 SP:FD",
result[0]
);
assert_eq!(
"0066 CA DEX A:01 X:01 Y:03 P:24 SP:FD",
result[1]
);
assert_eq!(
"0067 88 DEY A:01 X:00 Y:03 P:26 SP:FD",
result[2]
);
}
#[test]
fn test_format_mem_access() {
let mut bus = Bus::new(test_rom(vec![]));
// ORA ($33), Y
bus.mem_write(100, 0x11);
bus.mem_write(101, 0x33);
//data
bus.mem_write(0x33, 00);
bus.mem_write(0x34, 04);
//target cell
bus.mem_write(0x400, 0xAA);
let mut cpu = CPU::new(bus);
cpu.program_counter = 0x64;
cpu.register_y = 0;
let mut result: Vec<String> = vec![];
cpu.run_with_callback(|cpu| {
result.push(trace(cpu));
});
assert_eq!(
"0064 11 33 ORA ($33),Y = 0400 @ 0400 = AA A:00 X:00 Y:00 P:24 SP:FD",
result[0]
);
}
}