Finished implementing instructions

+ added all legal instructions
This commit is contained in:
Steins7 2022-02-21 21:17:11 +01:00
parent 012992c4ad
commit 051cfe6611
7 changed files with 517 additions and 78410 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
/target
.log

78380
output.log

File diff suppressed because one or more lines are too long

View File

@ -48,19 +48,19 @@ impl Bus {
let mut ram = Ram::<0x800>::new();
//TODO temporary for instruction tests
ram.buffer[0x01] = 0x0A;
ram.buffer[0x02] = 0x90;;
ram.buffer[0x03] = (-3 as i8) as u8;
ram.buffer[0x04] = 0x90;
ram.buffer[0x05] = (-3 as i8) as u8;
ram.buffer[0x06] = 0x0A;
ram.buffer[0x07] = 0x0A;
ram.buffer[0x08] = 0x0A;
ram.buffer[0x09] = 0x01;
ram.buffer[0x0A] = 0x3D;
ram.buffer[0x0B] = 0xFE;
ram.buffer[0x0C] = 0x01;
ram.buffer[0x0D] = 0x39;
ram.buffer[0x01] = 0xE9; //sbc
ram.buffer[0x02] = (-3 as i8) as u8;
ram.buffer[0x03] = 0x09;
ram.buffer[0x04] = 0x00;
ram.buffer[0x05] = 0xA9; //lda
ram.buffer[0x06] = 0x01;
ram.buffer[0x07] = 0x4C; //jmp
ram.buffer[0x08] = 0x00;
ram.buffer[0x09] = 0x00;
ram.buffer[0x0A] = 0x2A; //fn rol
ram.buffer[0x0B] = 0x90; //bcc
ram.buffer[0x0C] = (-3 as i8) as u8;
ram.buffer[0x0D] = 0x60; //rts
ram.buffer[0x0E] = 0xFD;
ram.buffer[0x0F] = 0x01;
ram.buffer[0x10] = 0x21;
@ -94,7 +94,15 @@ impl Bus {
// val
ram.buffer[0x01FF] = 0x01;
ram.buffer[0x0300] = 0x01; //boundary
ram.buffer[0x02FF] = 0xFF; //boundary
ram.buffer[0x0300] = 0x03;
// ptr to test
ram.buffer[0x030F] = 0xFF;
ram.buffer[0x0310] = 0x03;
// jmp test
ram.buffer[0x0400] = 0xE6;
Bus {
ram,

View File

View File

@ -8,6 +8,8 @@ use crate::{
memory::Memory,
};
use std::fmt;
//--------------------------------------------------------------------------------------------------
trait Input {
@ -27,7 +29,7 @@ trait RWInput: RInput + WInput {}
struct Accumulator {}
impl Input for Accumulator {
fn get_cycles(&self) -> u32 { 2 }
fn get_cycles(&self) -> u32 { 0 } //only used in +2 instructions
}
impl RInput for Accumulator {
@ -136,7 +138,6 @@ bitflags! {
}
}
#[derive(Debug)]
pub struct Cpu {
a: u8,
x: u8,
@ -147,6 +148,22 @@ pub struct Cpu {
bus: Bus,
}
impl fmt::Debug for Cpu {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Cpu")
.field("acc", &format_args!("0x{:0>2X}", self.a))
.field("x ", &format_args!("0x{:0>2X}", self.x))
.field("y ", &format_args!("0x{:0>2X}", self.y))
.field("prg_count", &format_args!("0x{:0>4X}", self.pc))
.field("stack_ptr", &format_args!("0x{:0>2X}", self.s))
.field("status", &self.p)
.field("bus", &self.bus)
.finish()
}
}
impl Cpu {
pub fn new() -> Self {
@ -155,8 +172,8 @@ impl Cpu {
x: 1, //TODO temporary
y: 2, //TODO temporary
pc: 0, //TODO to be verified
s: 0x34,
p: StatusReg::from_bits(0xFD).unwrap(),
s: 0xFD,
p: StatusReg::from_bits(0x35).unwrap(),
bus: Bus::new(),
}
}
@ -239,6 +256,123 @@ impl Cpu {
0xCA => dex(mode_implicit),
0x88 => dey(mode_implicit),
0x49 => eor(mode_immediate),
0x45 => eor(mode_zero_page),
0x55 => eor(mode_zero_page_x),
0x4D => eor(mode_absolute),
0x5D => eor(mode_absolute_x),
0x59 => eor(mode_absolute_y),
0x41 => eor(mode_indirect_x),
0x51 => eor(mode_indirect_y),
0xE6 => inc(mode_zero_page),
0xF6 => inc(mode_zero_page_x),
0xEE => inc(mode_absolute),
0xFE => inc(mode_absolute_x),
0xE8 => inx(mode_implicit),
0xC8 => iny(mode_implicit),
0x4C => jmp(mode_absolute),
0x6C => jmp(mode_indirect),
0x20 => jsr(mode_absolute),
0xA9 => lda(mode_immediate),
0xA5 => lda(mode_zero_page),
0xB5 => lda(mode_zero_page_x),
0xAD => lda(mode_absolute),
0xBD => lda(mode_absolute_x),
0xB9 => lda(mode_absolute_y),
0xA1 => lda(mode_indirect_x),
0xB1 => lda(mode_indirect_y),
0xA2 => ldx(mode_immediate),
0xA6 => ldx(mode_zero_page),
0xB6 => ldx(mode_zero_page_y),
0xAE => ldx(mode_absolute),
0xBE => ldx(mode_absolute_y),
0xA0 => ldy(mode_immediate),
0xA4 => ldy(mode_zero_page),
0xB4 => ldy(mode_zero_page_y),
0xAC => ldy(mode_absolute),
0xBC => ldy(mode_absolute_y),
0x4A => lsr(mode_accumulator),
0x46 => lsr(mode_zero_page),
0x56 => lsr(mode_zero_page_x),
0x4E => lsr(mode_absolute),
0x5E => lsr(mode_absolute_x),
0xEA => nop(mode_implicit),
0x09 => ora(mode_immediate),
0x05 => ora(mode_zero_page),
0x15 => ora(mode_zero_page_x),
0x0D => ora(mode_absolute),
0x1D => ora(mode_absolute_x),
0x19 => ora(mode_absolute_y),
0x01 => ora(mode_indirect_x),
0x11 => ora(mode_indirect_y),
0x48 => pha(mode_implicit),
0x08 => php(mode_implicit),
0x68 => pla(mode_implicit),
0x28 => plp(mode_implicit),
0x2A => rol(mode_accumulator),
0x26 => rol(mode_zero_page),
0x36 => rol(mode_zero_page_x),
0x2E => rol(mode_absolute),
0x3E => rol(mode_absolute_x),
0x6A => ror(mode_accumulator),
0x66 => ror(mode_zero_page),
0x76 => ror(mode_zero_page_x),
0x6E => ror(mode_absolute),
0x7E => ror(mode_absolute_x),
0x40 => rti(mode_implicit),
0x60 => rts(mode_implicit),
0xE9 => sbc(mode_immediate),
0xE5 => sbc(mode_zero_page),
0xF5 => sbc(mode_zero_page_x),
0xED => sbc(mode_absolute),
0xFD => sbc(mode_absolute_x),
0xF9 => sbc(mode_absolute_y),
0xE1 => sbc(mode_indirect_x),
0xF1 => sbc(mode_indirect_y),
0x38 => sec(mode_implicit),
0xF8 => sed(mode_implicit),
0x78 => sei(mode_implicit),
0x85 => sta(mode_zero_page),
0x95 => sta(mode_zero_page_x),
0x8D => sta(mode_absolute),
0x9D => sta(mode_absolute_x),
0x99 => sta(mode_absolute_y),
0x81 => sta(mode_indirect_x),
0x91 => sta(mode_indirect_y),
0x86 => stx(mode_zero_page),
0x96 => stx(mode_zero_page_y),
0x8E => stx(mode_absolute),
0x84 => sty(mode_zero_page),
0x94 => sty(mode_zero_page_x),
0x8C => sty(mode_absolute),
0xAA => tax(mode_implicit),
0xA8 => tay(mode_implicit),
0xBA => tsx(mode_implicit),
0x8A => txa(mode_implicit),
0x9A => txs(mode_implicit),
0x98 => tya(mode_implicit),
);
info!("0x{:X}: {} cycles", opcode, cycles);
@ -430,6 +564,20 @@ impl Cpu {
val
}
/// Write data, then decrement stack pointer. The stack is stored between 0x01FF and 0x0100
fn push_stack(&mut self, data: u8) {
self.bus.write_addr(self.s as u16 | 0x0100, data);
self.s = self.s.wrapping_sub(1);
}
/// Read data, then increment stack pointer
fn pop_stack(&mut self) -> u8 {
self.s = self.s.wrapping_add(1);
let data = self.bus.read_addr(self.s as u16 | 0x0100);
data
}
fn adc<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
@ -455,8 +603,6 @@ impl Cpu {
// truncate accumulator to 8 bits
self.a = a as u8;
// handle zero bit
input.get_cycles()
}
@ -497,7 +643,6 @@ impl Cpu {
true => {
let old_pc = self.pc;
self.pc = self.pc.wrapping_add(offset as u16);
debug!("PC: 0x{:X}", self.pc);
match old_pc & 0xFF00 == self.pc & 0xFF00 {
true => input.get_cycles() + 1,
false => input.get_cycles() + 2,
@ -545,9 +690,24 @@ 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);
//TODO
panic!("BRK not implemented");
// store status register
self.p.set(StatusReg::B, true);
self.push_stack(self.p.bits() as u8);
// load interrupt vector
let pc_lo = self.bus.read_addr(0xFFFE) as u16;
let pc_hi = self.bus.read_addr(0xFFFF) as u16;
self.pc = pc_lo | (pc_hi << 8);
// inhibit further interrupts
self.p.set(StatusReg::I, true);
7
}
fn bvc<I: RInput>(&mut self, input: I) -> u32 {
@ -633,7 +793,321 @@ impl Cpu {
2
}
fn eor<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// 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);
input.get_cycles()
}
fn inc<I:RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// compute
val = val.wrapping_add(1);
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
// store result
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn inx(&mut self, _: ()) -> u32 {
// 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);
2
}
fn iny(&mut self, _: ()) -> u32 {
// compute
self.y = self.y.wrapping_add(1);
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
2
}
fn jmp(&mut self, input: MemoryVal) -> u32 {
self.pc = input.addr;
input.get_cycles() - 1
}
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);
// load target address
self.pc = input.addr;
return input.get_cycles() + 2
}
fn lda<I: RInput>(&mut self, input: I) -> u32 {
// store value and compute flags
self.a = input.read(&self.a, &self.bus);
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
input.get_cycles()
}
fn ldx<I: RInput>(&mut self, input: I) -> u32 {
// store value and compute flags
self.x = input.read(&self.a, &self.bus);
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
input.get_cycles()
}
fn ldy<I: RInput>(&mut self, input: I) -> u32 {
// store value and compute flags
self.y = input.read(&self.a, &self.bus);
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
input.get_cycles()
}
fn lsr<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut target = input.read(&self.a, &self.bus);
// set carry bit
self.p.set(StatusReg::C, (target & 0x1) != 0);
// shift value
target = target >> 1;
// set zero and negative bits
self.p.set(StatusReg::Z, target == 0);
self.p.set(StatusReg::N, false); //bit 7 is always 0
// store value
input.write(&mut self.a, &mut self.bus, target);
input.get_cycles() + 2
}
fn nop(&self, _: ()) -> u32 {
// do nothing
2
}
fn ora<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// compute
self.a = self.a | val;
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
input.get_cycles()
}
fn pha(&mut self, _: ()) -> u32 {
self.push_stack(self.a);
3
}
fn php(&mut self, _: ()) -> u32 {
self.push_stack(self.p.bits() as u8);
3
}
fn pla(&mut self, _: ()) -> u32 {
self.a = self.pop_stack();
4
}
fn plp(&mut self, _: ()) -> u32 {
self.p = StatusReg::from_bits_truncate(self.pop_stack());
self.p.remove(StatusReg::B | StatusReg::U);
4
}
fn rol<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// store bit 7 and compute
let carry = val & (0x1 << 7) != 0;
val = val << 1;
// update bit 0 and carry bit
if self.p.contains(StatusReg::C) {
val |= 0x1 << 0;
}
self.p.set(StatusReg::C, carry);
// store value
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn ror<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// store bit 0 and compute
let carry = val & (0x1 << 0) != 0;
val = val >> 1;
// update bit 7 and carry bit
if self.p.contains(StatusReg::C) {
val |= 0x1 << 7;
}
self.p.set(StatusReg::C, carry);
// store value
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn rti(&mut self, _: ()) -> u32 {
// load status register (B is cleared and I overrided)
self.p = StatusReg::from_bits_truncate(self.pop_stack());
self.p.set(StatusReg::B, false);
// load pc
let pc_lo = self.pop_stack() as u16;
let pc_hi = self.pop_stack() as u16;
self.pc = pc_lo | (pc_hi << 8);
6
}
fn rts(&mut self, _: ()) -> u32 {
// load pc
let pc_lo = self.pop_stack() as u16;
let pc_hi = self.pop_stack() as u16;
self.pc = pc_lo | (pc_hi << 8);
6
}
fn sbc<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// sub acc and value
let prev_a = self.a as u16;
let mut a = self.a as u16;
if !self.p.contains(StatusReg::C) {
a = a.wrapping_sub(1);
}
a = a.wrapping_sub((val & 0xFF) as u16);
// handle status bits
self.p.set(StatusReg::C, a & 0xFF00 == 0);
self.p.set(StatusReg::Z, a & 0xFF == 0);
if ((prev_a & 0x80) !=0 && (val & 0x80) != 0 && (a & 0x80) == 0)
|| ((prev_a & 0x80) == 0 && (val & 0x80) == 0 && (a & 0x80) != 0) {
self.p.set(StatusReg::V, true);
} else {
self.p.set(StatusReg::V, false);
}
self.p.set(StatusReg::N, a & 0x80 != 0);
// truncate accumulator to 8 bits
self.a = a as u8;
input.get_cycles()
}
fn sec(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::C, true);
2
}
fn sed(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::D, true);
2
}
fn sei(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::I, true);
2
}
fn sta<I: RWInput>(&mut self, mut input: I) -> u32 {
let a = self.a;
input.write(&mut self.a, &mut self.bus, a);
input.get_cycles()
}
fn stx<I: RWInput>(&mut self, mut input: I) -> u32 {
let x = self.x;
input.write(&mut self.a, &mut self.bus, x);
input.get_cycles()
}
fn sty<I: RWInput>(&mut self, mut input: I) -> u32 {
let y = self.y;
input.write(&mut self.a, &mut self.bus, y);
input.get_cycles()
}
fn tax(&mut self, _: ()) -> u32 {
self.x = self.a;
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
2
}
fn tay(&mut self, _: ()) -> u32 {
self.y = self.a;
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
2
}
fn tsx(&mut self, _: ()) -> u32 {
self.x = self.s;
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
2
}
fn txa(&mut self, _: ()) -> u32 {
self.a = self.x;
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
2
}
fn txs(&mut self, _: ()) -> u32 {
self.s = self.x;
2
}
fn tya(&mut self, _: ()) -> u32 {
self.a = self.y;
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
2
}
}

View File

@ -15,6 +15,7 @@ fn main() -> Result<(), &'static str> {
dpi::LogicalSize,
};
use mini_gl_fb::config;
use std::fmt::Write;
// setup
setup_logger().map_err(|_| "Failed to setup logger")?;
@ -29,15 +30,19 @@ fn main() -> Result<(), &'static str> {
let mut buffer = PixelBuffer::new(800, 600);
let mut renderer = FontRenderer::new(20.0, [0u8, 0, 0]);
// first image
let mut cpu = Cpu::new();
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);
let mut cpu = Cpu::new();
// event loop
fb.glutin_handle_basic_input(&mut event_loop, |fb, input| {
use winit::event::VirtualKeyCode;
use std::fmt::Write;
// wait for input before updating
input.wait = true;
@ -47,9 +52,9 @@ fn main() -> Result<(), &'static str> {
return false
}
// execute next cpu instruction
// execute next cpu instruction (step mode)
if input.key_pressed(VirtualKeyCode::S) {
cpu.tick();
cpu.tick();
let mut debug_str = String::new();
write!(debug_str, "{:#?}", cpu).unwrap();

View File

@ -60,7 +60,6 @@ impl From<&Pixel> for [u8; 4] {
pub struct PixelBuffer {
buffer: Vec<Pixel>,
h: usize,
w: usize,
}
impl PixelBuffer {
@ -69,7 +68,6 @@ impl PixelBuffer {
PixelBuffer {
buffer: vec![Pixel::rgba(255u8, 255u8, 255u8, 255); h * w],
h,
w,
}
}