Tested and fixed all instructions
! something might still be bugged since the test program is failing, although not in an obvious manner
This commit is contained in:
parent
051cfe6611
commit
1b9c73c432
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
/target
|
||||
.log
|
||||
*.log
|
||||
*.bin
|
||||
*.bin.*
|
||||
|
||||
|
||||
|
||||
36
src/bus.rs
36
src/bus.rs
@ -112,3 +112,39 @@ impl Bus {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// special Bus only used for testing the emulator
|
||||
pub struct FileBus {
|
||||
mem: Ram<0x10000>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileBus {
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Bus")
|
||||
.field("mem", &self.mem)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Memory for FileBus {
|
||||
|
||||
fn read_addr(&self, addr: u16) -> u8 {
|
||||
self.mem.read_addr(addr) //RAM is mirrored 3 times
|
||||
}
|
||||
|
||||
fn write_addr(&mut self, addr: u16, data: u8) {
|
||||
self.mem.write_addr(addr % 0x0800, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBus {
|
||||
|
||||
pub fn new() -> Self {
|
||||
FileBus {
|
||||
mem: Ram::from_file("6502_functional_test.bin"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
105
src/cpu.rs
105
src/cpu.rs
@ -4,7 +4,7 @@ use log::{debug, error, info, trace, warn};
|
||||
use bitflags::bitflags;
|
||||
|
||||
use crate::{
|
||||
bus::Bus,
|
||||
bus::FileBus,
|
||||
memory::Memory,
|
||||
};
|
||||
|
||||
@ -17,11 +17,11 @@ trait Input {
|
||||
}
|
||||
|
||||
trait RInput: Input {
|
||||
fn read(&self, acc: &u8, bus: &Bus) -> u8;
|
||||
fn read<M: Memory>(&self, acc: &u8, bus: &M) -> u8;
|
||||
}
|
||||
|
||||
trait WInput: Input {
|
||||
fn write(&mut self, acc: &mut u8, bus: &mut Bus, data: u8);
|
||||
fn write<M: Memory>(&mut self, acc: &mut u8, bus: &mut M, data: u8);
|
||||
}
|
||||
|
||||
trait RWInput: RInput + WInput {}
|
||||
@ -33,11 +33,11 @@ impl Input for Accumulator {
|
||||
}
|
||||
|
||||
impl RInput for Accumulator {
|
||||
fn read(&self, acc: &u8, _bus: &Bus) -> u8 { *acc }
|
||||
fn read<M: Memory>(&self, acc: &u8, _bus: &M) -> u8 { *acc }
|
||||
}
|
||||
|
||||
impl WInput for Accumulator {
|
||||
fn write(&mut self, acc: &mut u8, _bus: &mut Bus, data: u8) { *acc = data }
|
||||
fn write<M: Memory>(&mut self, acc: &mut u8, _bus: &mut M, data: u8) { *acc = data }
|
||||
}
|
||||
|
||||
impl RWInput for Accumulator {}
|
||||
@ -51,7 +51,7 @@ impl Input for Data {
|
||||
}
|
||||
|
||||
impl RInput for Data {
|
||||
fn read(&self, _acc: &u8, _bus: &Bus) -> u8 { self.data }
|
||||
fn read<M: Memory>(&self, _acc: &u8, _bus: &M) -> u8 { self.data }
|
||||
}
|
||||
|
||||
struct MemoryVal {
|
||||
@ -64,13 +64,13 @@ impl Input for MemoryVal {
|
||||
}
|
||||
|
||||
impl RInput for MemoryVal {
|
||||
fn read(&self, _acc: &u8, bus: &Bus) -> u8 {
|
||||
fn read<M: Memory>(&self, _acc: &u8, bus: &M) -> u8 {
|
||||
bus.read_addr(self.addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl WInput for MemoryVal {
|
||||
fn write(&mut self, _acc: &mut u8, bus: &mut Bus, data: u8) {
|
||||
fn write<M: Memory>(&mut self, _acc: &mut u8, bus: &mut M, data: u8) {
|
||||
bus.write_addr(self.addr, data);
|
||||
}
|
||||
}
|
||||
@ -93,13 +93,13 @@ impl Input for MemoryValExtra {
|
||||
}
|
||||
|
||||
impl RInput for MemoryValExtra {
|
||||
fn read(&self, _acc: &u8, bus: &Bus) -> u8 {
|
||||
fn read<M: Memory>(&self, _acc: &u8, bus: &M) -> u8 {
|
||||
bus.read_addr(self.addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl WInput for MemoryValExtra {
|
||||
fn write(&mut self, _acc: &mut u8, bus: &mut Bus, data: u8) {
|
||||
fn write<M: Memory>(&mut self, _acc: &mut u8, bus: &mut M, data: u8) {
|
||||
bus.write_addr(self.addr, data);
|
||||
|
||||
self.extra_cycle = true;
|
||||
@ -145,7 +145,7 @@ pub struct Cpu {
|
||||
pc: u16,
|
||||
s: u8,
|
||||
p: StatusReg,
|
||||
bus: Bus,
|
||||
bus: FileBus,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Cpu {
|
||||
@ -167,14 +167,20 @@ impl fmt::Debug for Cpu {
|
||||
impl Cpu {
|
||||
|
||||
pub fn new() -> Self {
|
||||
|
||||
// read initial PC value from reset vector
|
||||
let bus = FileBus::new();
|
||||
let pc_lo = bus.read_addr(0xFFFC) as u16;
|
||||
let pc_hi = bus.read_addr(0xFFFD) as u16;
|
||||
|
||||
Cpu {
|
||||
a: 1,
|
||||
x: 1, //TODO temporary
|
||||
y: 2, //TODO temporary
|
||||
pc: 0, //TODO to be verified
|
||||
a: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
pc: (pc_lo | (pc_hi << 8)) + 3,
|
||||
s: 0xFD,
|
||||
p: StatusReg::from_bits(0x35).unwrap(),
|
||||
bus: Bus::new(),
|
||||
p: StatusReg::from_bits(0x34).unwrap(),
|
||||
bus,
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,6 +192,13 @@ impl Cpu {
|
||||
fn execute(&mut self) {
|
||||
|
||||
let opcode = self.read_pc_addr();
|
||||
// if self.pc-1 > 0x36D0 && self.pc-1 < 0x36D8 {
|
||||
// println!("{:#?}", self);
|
||||
// }
|
||||
// if (self.pc-1) != 0x36D8 {
|
||||
// println!("0x{:0>4X}: {:0>2X}", self.pc-1, opcode);
|
||||
// }
|
||||
|
||||
let cycles = parse_opcode!(self, opcode,
|
||||
0x69 => adc(mode_immediate),
|
||||
0x65 => adc(mode_zero_page),
|
||||
@ -296,9 +309,9 @@ impl Cpu {
|
||||
|
||||
0xA0 => ldy(mode_immediate),
|
||||
0xA4 => ldy(mode_zero_page),
|
||||
0xB4 => ldy(mode_zero_page_y),
|
||||
0xB4 => ldy(mode_zero_page_x),
|
||||
0xAC => ldy(mode_absolute),
|
||||
0xBC => ldy(mode_absolute_y),
|
||||
0xBC => ldy(mode_absolute_x),
|
||||
|
||||
0x4A => lsr(mode_accumulator),
|
||||
0x46 => lsr(mode_zero_page),
|
||||
@ -372,10 +385,7 @@ impl Cpu {
|
||||
0x8A => txa(mode_implicit),
|
||||
0x9A => txs(mode_implicit),
|
||||
0x98 => tya(mode_implicit),
|
||||
|
||||
);
|
||||
|
||||
info!("0x{:X}: {} cycles", opcode, cycles);
|
||||
}
|
||||
|
||||
/// Implicit mode
|
||||
@ -411,7 +421,7 @@ impl Cpu {
|
||||
/// val = PEEK((arg + X) & 0xFF)
|
||||
fn mode_zero_page_x(&mut self) -> MemoryVal {
|
||||
MemoryVal {
|
||||
addr: (self.read_pc_addr() + self.x) as u16 & 0x00FF,
|
||||
addr: (self.read_pc_addr().wrapping_add(self.x)) as u16 & 0x00FF,
|
||||
cycles: 4,
|
||||
}
|
||||
}
|
||||
@ -421,7 +431,7 @@ impl Cpu {
|
||||
/// val = PEEK((arg + Y) & 0xFF)
|
||||
fn mode_zero_page_y(&mut self) -> MemoryVal {
|
||||
MemoryVal {
|
||||
addr: (self.read_pc_addr() + self.y) as u16 & 0x00FF,
|
||||
addr: (self.read_pc_addr().wrapping_add(self.y)) as u16 & 0x00FF,
|
||||
cycles: 4,
|
||||
}
|
||||
}
|
||||
@ -558,8 +568,8 @@ impl Cpu {
|
||||
/// Increment PC, then read corresponding value in memory
|
||||
fn read_pc_addr(&mut self) -> u8 {
|
||||
|
||||
self.pc += 1;
|
||||
let val = self.bus.read_addr(self.pc);
|
||||
self.pc += 1;
|
||||
|
||||
val
|
||||
}
|
||||
@ -692,11 +702,12 @@ impl Cpu {
|
||||
fn brk(&mut self, _: ()) -> u32 {
|
||||
|
||||
// store PC on stack
|
||||
self.push_stack((self.pc >> 8) as u8);
|
||||
self.push_stack(self.pc as u8);
|
||||
let pc = self.pc.wrapping_add(1);
|
||||
self.push_stack((pc >> 8) as u8);
|
||||
self.push_stack(pc as u8);
|
||||
|
||||
// store status register
|
||||
self.p.set(StatusReg::B, true);
|
||||
self.p.set(StatusReg::B | StatusReg::U, true);
|
||||
self.push_stack(self.p.bits() as u8);
|
||||
|
||||
// load interrupt vector
|
||||
@ -743,7 +754,7 @@ impl Cpu {
|
||||
|
||||
self.p.set(StatusReg::C, reg >= val);
|
||||
self.p.set(StatusReg::Z, reg == val);
|
||||
self.p.set(StatusReg::N, ((reg - val) & (0x1 << 7)) != 0);
|
||||
self.p.set(StatusReg::N, ((reg.wrapping_sub(val)) & (0x1 << 7)) != 0);
|
||||
|
||||
input.get_cycles()
|
||||
}
|
||||
@ -798,8 +809,8 @@ impl Cpu {
|
||||
|
||||
// compute
|
||||
self.a = (!self.a & val) | (self.a & !val);
|
||||
self.p.set(StatusReg::Z, self.y == 0);
|
||||
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
|
||||
self.p.set(StatusReg::Z, self.a == 0);
|
||||
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
|
||||
|
||||
input.get_cycles()
|
||||
}
|
||||
@ -809,8 +820,8 @@ impl Cpu {
|
||||
|
||||
// compute
|
||||
val = val.wrapping_add(1);
|
||||
self.p.set(StatusReg::Z, self.y == 0);
|
||||
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
|
||||
self.p.set(StatusReg::Z, val == 0);
|
||||
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
|
||||
|
||||
// store result
|
||||
input.write(&mut self.a, &mut self.bus, val);
|
||||
@ -821,8 +832,8 @@ impl Cpu {
|
||||
|
||||
// compute
|
||||
self.x = self.x.wrapping_add(1);
|
||||
self.p.set(StatusReg::Z, self.y == 0);
|
||||
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
|
||||
self.p.set(StatusReg::Z, self.x == 0);
|
||||
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
|
||||
|
||||
2
|
||||
}
|
||||
@ -845,8 +856,9 @@ impl Cpu {
|
||||
fn jsr(&mut self, input: MemoryVal) -> u32 {
|
||||
|
||||
// store return point
|
||||
self.push_stack((self.pc >> 8) as u8);
|
||||
self.push_stack(self.pc as u8);
|
||||
let pc = self.pc.wrapping_sub(1);
|
||||
self.push_stack((pc >> 8) as u8);
|
||||
self.push_stack(pc as u8);
|
||||
|
||||
// load target address
|
||||
self.pc = input.addr;
|
||||
@ -924,12 +936,18 @@ impl Cpu {
|
||||
}
|
||||
|
||||
fn php(&mut self, _: ()) -> u32 {
|
||||
self.push_stack(self.p.bits() as u8);
|
||||
let mut p = self.p;
|
||||
p.set(StatusReg::B | StatusReg::U, true);
|
||||
self.push_stack(p.bits() as u8);
|
||||
3
|
||||
}
|
||||
|
||||
fn pla(&mut self, _: ()) -> u32 {
|
||||
|
||||
self.a = self.pop_stack();
|
||||
self.p.set(StatusReg::Z, self.a == 0);
|
||||
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
|
||||
|
||||
4
|
||||
}
|
||||
|
||||
@ -952,6 +970,10 @@ impl Cpu {
|
||||
}
|
||||
self.p.set(StatusReg::C, carry);
|
||||
|
||||
// update status bits
|
||||
self.p.set(StatusReg::Z, val == 0);
|
||||
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
|
||||
|
||||
// store value
|
||||
input.write(&mut self.a, &mut self.bus, val);
|
||||
input.get_cycles() + 2
|
||||
@ -970,6 +992,10 @@ impl Cpu {
|
||||
}
|
||||
self.p.set(StatusReg::C, carry);
|
||||
|
||||
// update status bits
|
||||
self.p.set(StatusReg::Z, val == 0);
|
||||
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
|
||||
|
||||
// store value
|
||||
input.write(&mut self.a, &mut self.bus, val);
|
||||
input.get_cycles() + 2
|
||||
@ -979,7 +1005,7 @@ impl Cpu {
|
||||
|
||||
// load status register (B is cleared and I overrided)
|
||||
self.p = StatusReg::from_bits_truncate(self.pop_stack());
|
||||
self.p.set(StatusReg::B, false);
|
||||
self.p.set(StatusReg::B | StatusReg::U, false);
|
||||
|
||||
// load pc
|
||||
let pc_lo = self.pop_stack() as u16;
|
||||
@ -995,6 +1021,7 @@ impl Cpu {
|
||||
let pc_lo = self.pop_stack() as u16;
|
||||
let pc_hi = self.pop_stack() as u16;
|
||||
self.pc = pc_lo | (pc_hi << 8);
|
||||
self.pc = self.pc.wrapping_add(1);
|
||||
|
||||
6
|
||||
}
|
||||
|
||||
34
src/main.rs
34
src/main.rs
@ -39,13 +39,15 @@ fn main() -> Result<(), &'static str> {
|
||||
|
||||
let vec: Vec<[u8; 4]> = (&buffer).into();
|
||||
fb.update_buffer(&vec);
|
||||
let mut update = false;
|
||||
let mut refresh = true;
|
||||
let mut frame_counter = 0;
|
||||
|
||||
// event loop
|
||||
fb.glutin_handle_basic_input(&mut event_loop, |fb, input| {
|
||||
use winit::event::VirtualKeyCode;
|
||||
|
||||
// wait for input before updating
|
||||
input.wait = true;
|
||||
|
||||
// close if escape is pressed
|
||||
if input.key_pressed(VirtualKeyCode::Escape) {
|
||||
@ -55,15 +57,43 @@ fn main() -> Result<(), &'static str> {
|
||||
// execute next cpu instruction (step mode)
|
||||
if input.key_pressed(VirtualKeyCode::S) {
|
||||
cpu.tick();
|
||||
refresh = true;
|
||||
}
|
||||
|
||||
if input.key_pressed(VirtualKeyCode::R) {
|
||||
update = true;
|
||||
}
|
||||
|
||||
if input.key_pressed(VirtualKeyCode::C) {
|
||||
update = false;
|
||||
refresh = true;
|
||||
}
|
||||
|
||||
if update {
|
||||
cpu.tick();
|
||||
|
||||
frame_counter += 1;
|
||||
if frame_counter > 1000 {
|
||||
frame_counter = 0;
|
||||
refresh = true;
|
||||
}
|
||||
|
||||
input.wait = false;
|
||||
} else {
|
||||
input.wait = true;
|
||||
}
|
||||
|
||||
if refresh {
|
||||
refresh = false;
|
||||
|
||||
let mut debug_str = String::new();
|
||||
write!(debug_str, "{:#?}", cpu).unwrap();
|
||||
buffer.fill([20, 20], [760, 560], Pixel::rgba(255, 255, 255, 255));
|
||||
renderer.draw(&mut buffer, &debug_str, [20, 20], [760, 560]);
|
||||
}
|
||||
|
||||
let vec: Vec<[u8; 4]> = (&buffer).into();
|
||||
fb.update_buffer(&vec);
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
@ -16,17 +16,12 @@ pub struct Ram<const SIZE: usize> {
|
||||
impl<const SIZE: usize> fmt::Debug for Ram<SIZE> {
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.buffer.iter().enumerate()
|
||||
.try_for_each(|(i, elem)| {
|
||||
if i <= 0xFF {
|
||||
for i in 0x100..=0x1FF {
|
||||
if i%0x10 == 0 {
|
||||
f.write_fmt(format_args!("\n {:0>4X}", i))?;
|
||||
}
|
||||
f.write_fmt(format_args!(" {:0>2X}", elem))
|
||||
} else {
|
||||
Ok(())
|
||||
f.write_fmt(format_args!(" {:0>2X}", self.buffer[i]))?
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -51,4 +46,19 @@ impl<const SIZE: usize> Ram<SIZE> {
|
||||
buffer: [0u8; SIZE],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_file(file: &str) -> Self {
|
||||
use std::{
|
||||
fs::File,
|
||||
io::Read,
|
||||
};
|
||||
|
||||
let mut f = File::open(file).unwrap();
|
||||
let mut buffer = [0u8; SIZE];
|
||||
f.read_exact(&mut buffer).unwrap();
|
||||
|
||||
Ram {
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user