improved matrix display stuff
This commit is contained in:
parent
1a53f1d782
commit
8509b20109
@ -23,7 +23,7 @@ impl BenEaterPC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_system(&mut self) {
|
pub fn tick_system(&mut self) {
|
||||||
let (address, data, rw) = self.cpu.tick();
|
self.cpu.tick();
|
||||||
if self.cpu.microcode_step == 0 {
|
if self.cpu.microcode_step == 0 {
|
||||||
// tick the clock.
|
// tick the clock.
|
||||||
// tick the memory
|
// tick the memory
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
use crate::parts::address_bus::AddressBus;
|
use crate::parts::address_bus::AddressBus;
|
||||||
use crate::parts::data_bus::DataBus;
|
use crate::parts::data_bus::DataBus;
|
||||||
|
use crate::parts::display_matrix::MatrixEntryMode::{Delete, DeleteShift, Insert, InsertShift};
|
||||||
|
|
||||||
|
pub enum MatrixEntryMode {
|
||||||
|
Delete,
|
||||||
|
DeleteShift,
|
||||||
|
Insert,
|
||||||
|
InsertShift,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DisplayMatrix {
|
pub struct DisplayMatrix {
|
||||||
width: f32,
|
width: f32,
|
||||||
@ -9,42 +17,138 @@ pub struct DisplayMatrix {
|
|||||||
data_bus: DataBus,
|
data_bus: DataBus,
|
||||||
rs: bool,
|
rs: bool,
|
||||||
rw: bool,
|
rw: bool,
|
||||||
cursor_position: u8
|
cursor_position: u8,
|
||||||
|
busy: bool,
|
||||||
|
entry_mode: MatrixEntryMode,
|
||||||
|
cursor: bool,
|
||||||
|
on: bool,
|
||||||
|
blink: bool,
|
||||||
|
cursor_shift: bool,
|
||||||
|
display_shift: bool,
|
||||||
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayMatrix {
|
impl DisplayMatrix {
|
||||||
|
pub fn set_bus(&mut self, rs: bool, rw: bool, bus: u8, e: bool) {
|
||||||
|
self.rs = rs;
|
||||||
|
self.rw = rw;
|
||||||
|
self.data_bus.data = bus;
|
||||||
|
self.enabled = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the Display to its 'factory boot' state
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
// 1. Display clear
|
||||||
|
self.set_bus(false, false, 0b0000_0001, true);
|
||||||
|
self.tick(false, false, true, 0b0000_0001);
|
||||||
|
// Function Set
|
||||||
|
// DL = 1; 8-bit interface data
|
||||||
|
// N = 0; 1-line display
|
||||||
|
// F = 0; 5 × 8 dot character font
|
||||||
|
self.tick(false, false, true, 0b0011_0000);;
|
||||||
|
// 3. Display on/off control:
|
||||||
|
// D = 0; Display off
|
||||||
|
// C = 0; Cursor off
|
||||||
|
// B = 0; Blinking off
|
||||||
|
self.tick(false, false, true, 0b0000_1000);
|
||||||
|
// 4. Entry mode set:
|
||||||
|
// I/D = 1; Increment by 1
|
||||||
|
// S = 0; No shift
|
||||||
|
self.tick(false, false,true, 0b0000_0110);
|
||||||
|
self.busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(width: f32, height: f32) -> DisplayMatrix {
|
pub fn new(width: f32, height: f32) -> DisplayMatrix {
|
||||||
DisplayMatrix {
|
let mut matrix = DisplayMatrix {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
text_buffer: String::from(""),
|
text_buffer: String::from(""),
|
||||||
data_bus: DataBus::new(),
|
data_bus: DataBus::new(),
|
||||||
rs: false,
|
rs: false,
|
||||||
rw: false,
|
rw: false,
|
||||||
cursor_position: 0x00
|
cursor_position: 0x00,
|
||||||
}
|
busy: false,
|
||||||
|
entry_mode: MatrixEntryMode::InsertShift,
|
||||||
|
on: false,
|
||||||
|
cursor: false,
|
||||||
|
blink: false,
|
||||||
|
cursor_shift: false,
|
||||||
|
display_shift: false,
|
||||||
|
enabled: false,
|
||||||
|
};
|
||||||
|
matrix
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tick
|
/// Tick
|
||||||
///
|
pub fn tick(&mut self, rw: bool, rs: bool, enabled: bool, data: u8) {
|
||||||
/// Checks the data bus and sees what the setup is.
|
self.enabled = enabled;
|
||||||
///
|
self.data_bus.data = data;
|
||||||
/// 0 0 0 0 0 0 0 1 -> Clear Display
|
self.rw = rw;
|
||||||
/// 0 0 0 0 0 0 1 - -> Return Home
|
self.rs = rs;
|
||||||
/// 0 0 0 0 0 0 A B -> Sets cursor move direction and shift
|
|
||||||
/// A -> 0 = Insert, 1 = Delete
|
|
||||||
/// B -> Scroll bool
|
|
||||||
/// 0 0 0 0 1 D C B -> Sets display mode
|
|
||||||
/// D -> Display On/Off
|
|
||||||
/// C -> Cursor On/Off
|
|
||||||
/// B -> Blink
|
|
||||||
pub fn tick(&mut self) {
|
|
||||||
// parse whats on the data bus.
|
// parse whats on the data bus.
|
||||||
|
match (self.rs, self.rw) {
|
||||||
}
|
(true, true) => {
|
||||||
|
// read from cg or ddram
|
||||||
pub fn set_busses(&mut self, address_bus: &mut AddressBus, data_bus: &mut DataBus) {
|
}
|
||||||
|
(true, false) => {
|
||||||
|
// write to cg or ddram
|
||||||
|
println!("WRITE TO CG/DD RAM -> {:08b} / {:02x} / {}", self.data_bus.data, self.data_bus.data, self.data_bus.data);
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
// read the busy flag.
|
||||||
|
self.data_bus.data = (self.busy as u8) << 7 | (self.cursor_position & 0x7F);
|
||||||
|
self.enabled = true;
|
||||||
|
}
|
||||||
|
(false, false) => {
|
||||||
|
match self.data_bus.data {
|
||||||
|
0b0000_0001 => {
|
||||||
|
// clear display
|
||||||
|
self.text_buffer = " ".repeat(32);
|
||||||
|
}
|
||||||
|
0b0000_0010..=0b0000_0011 => {
|
||||||
|
// return home
|
||||||
|
self.cursor_position = 0x00;
|
||||||
|
}
|
||||||
|
0b0000_0100..=0b0000_0111 => {
|
||||||
|
self.entry_mode = match self.data_bus.data {
|
||||||
|
0b01 => DeleteShift,
|
||||||
|
0b10 => Insert,
|
||||||
|
0b11 => InsertShift,
|
||||||
|
_ => {
|
||||||
|
// Default mode
|
||||||
|
Delete
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
0b0000_1000..=0b0000_1111 => {
|
||||||
|
// display control
|
||||||
|
self.on = self.data_bus.data & 0b100 == 0b100;
|
||||||
|
self.cursor = self.data_bus.data & 0b10 == 0b10;
|
||||||
|
self.blink = self.data_bus.data & 0b1 == 0b1;
|
||||||
|
}
|
||||||
|
0b0001_0000..=0b0001_1111 => {
|
||||||
|
// cursor control
|
||||||
|
self.cursor_shift = self.data_bus.data & 0b1000 == 0b1000;
|
||||||
|
self.display_shift = self.data_bus.data & 0b100 == 0b100;
|
||||||
|
}
|
||||||
|
0b0010_0000..=0b0011_1111 => {
|
||||||
|
// function set
|
||||||
|
println!("Ignoring function set. this is going to play like an 8bit 2 row");
|
||||||
|
}
|
||||||
|
0b0100_0000..=0b0111_1111 => {
|
||||||
|
// set CGRam Address
|
||||||
|
println!("Ignoring set CGRam Address. Not Changing how the characters are displayed.");
|
||||||
|
}
|
||||||
|
0b1000_0000..=0b1111_1111 => {
|
||||||
|
// set DDRam address
|
||||||
|
self.cursor_position = self.data_bus.data & 0b0111_1111;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Invalid Command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_letter(&mut self, letter_to_push: char) {
|
pub fn push_letter(&mut self, letter_to_push: char) {
|
||||||
@ -60,7 +164,7 @@ impl DisplayMatrix {
|
|||||||
pub fn render(&self, x_offset: f32, y_offset: f32) {
|
pub fn render(&self, x_offset: f32, y_offset: f32) {
|
||||||
DisplayMatrix::draw_square(x_offset,
|
DisplayMatrix::draw_square(x_offset,
|
||||||
y_offset,
|
y_offset,
|
||||||
x_offset + self.width ,
|
x_offset + self.width,
|
||||||
y_offset + self.height,
|
y_offset + self.height,
|
||||||
BLACK);
|
BLACK);
|
||||||
|
|
||||||
@ -76,4 +180,17 @@ impl DisplayMatrix {
|
|||||||
draw_line(x1, y2, x2, y2, 1.0, color);
|
draw_line(x1, y2, x2, y2, 1.0, color);
|
||||||
draw_line(x2, y1, x2, y2, 1.0, color);
|
draw_line(x2, y1, x2, y2, 1.0, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() { assert!(true); }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn device_init() {
|
||||||
|
let display = DisplayMatrix::new(100.0, 100.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,15 @@ use crate::op_info::OpInfo;
|
|||||||
use crate::operation::Operation;
|
use crate::operation::Operation;
|
||||||
use crate::operation::Operation::*;
|
use crate::operation::Operation::*;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn INSTRUCTION_CYCLES(instruction: u8) -> u8 {
|
||||||
|
INSTRUCTION_TABLE[instruction as usize].unwrap().cycles
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn INSTRUCTION_LENGTH(instruction: u8) -> u8 {
|
||||||
|
INSTRUCTION_TABLE[instruction as usize].unwrap().length
|
||||||
|
}
|
||||||
|
|
||||||
pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
||||||
let mut table: [Option<OpInfo>; 256] = [const { None }; 256];
|
let mut table: [Option<OpInfo>; 256] = [const { None }; 256];
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
use crate::address_mode::AddressMode;
|
use crate::address_mode::AddressMode;
|
||||||
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR, SIZE_64KB};
|
use crate::constants::constants_isa_op::ISA_OP_NOP;
|
||||||
use crate::instruction::Instruction;
|
use crate::instruction::Instruction;
|
||||||
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
||||||
use crate::mos6502flags::Mos6502Flag::{Carry, Decimal, Interrupt, Overflow};
|
use crate::mos6502flags::Mos6502Flag::*;
|
||||||
use crate::op_info::OpInfo;
|
use crate::op_info::OpInfo;
|
||||||
use crate::operand::Operand;
|
use crate::operand::Operand;
|
||||||
use crate::operation::Operation;
|
use crate::operation::Operation;
|
||||||
|
use crate::constants::constants_system::*;
|
||||||
|
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||||
|
|
||||||
pub struct Mos6502Cpu {
|
pub struct Mos6502Cpu {
|
||||||
// this is public for rendering quickly.
|
// this is public for rendering quickly.
|
||||||
@ -22,7 +24,9 @@ pub struct Mos6502Cpu {
|
|||||||
ir: Instruction, // Instruction Register
|
ir: Instruction, // Instruction Register
|
||||||
oi: OpInfo,
|
oi: OpInfo,
|
||||||
has_reset: bool,
|
has_reset: bool,
|
||||||
iv: u16 // Interrupt Vector
|
iv: u16, // Interrupt Vector
|
||||||
|
cycle_carry: u16, // Value to hold between microsteps
|
||||||
|
ir_bytes: Box<[u8]>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Mos6502Cpu {
|
impl Default for Mos6502Cpu {
|
||||||
@ -33,28 +37,25 @@ impl Default for Mos6502Cpu {
|
|||||||
|
|
||||||
let mut working = Mos6502Cpu {
|
let mut working = Mos6502Cpu {
|
||||||
memory: boxed_array,
|
memory: boxed_array,
|
||||||
a: 0,
|
a: 0x00,
|
||||||
x: 0,
|
x: 0x00,
|
||||||
y: 0,
|
y: 0x00,
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
pc: 0xfffd,
|
pc: 0xfffd,
|
||||||
s: 0,
|
s: 0x00,
|
||||||
microcode_step: 0,
|
microcode_step: 0x00,
|
||||||
address_bus: 0,
|
address_bus: 0x00,
|
||||||
data_bus: 0,
|
data_bus: 0x00,
|
||||||
ir: Instruction {
|
ir: Instruction {
|
||||||
op: Operation::NOP,
|
op: Operation::NOP,
|
||||||
mode: AddressMode::Implied,
|
mode: AddressMode::Implied,
|
||||||
operand: Operand::None,
|
operand: Operand::None,
|
||||||
},
|
},
|
||||||
oi: OpInfo {
|
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].unwrap(),
|
||||||
operation: Operation::NOP,
|
|
||||||
mode: AddressMode::Implied,
|
|
||||||
length: 1,
|
|
||||||
cycles: 2,
|
|
||||||
},
|
|
||||||
has_reset: false,
|
has_reset: false,
|
||||||
iv: 0xfffe
|
iv: 0xfffe,
|
||||||
|
cycle_carry: 0x0000,
|
||||||
|
ir_bytes: [].into()
|
||||||
};
|
};
|
||||||
working.reset_cpu();
|
working.reset_cpu();
|
||||||
working
|
working
|
||||||
@ -68,28 +69,8 @@ impl Mos6502Cpu {
|
|||||||
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
|
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
|
||||||
let mut working = Mos6502Cpu {
|
let mut working = Mos6502Cpu {
|
||||||
memory: boxed_array,
|
memory: boxed_array,
|
||||||
a: 0,
|
ir_bytes: [].into(),
|
||||||
x: 0,
|
..Default::default()
|
||||||
y: 0,
|
|
||||||
flags: Mos6502Flags::default(),
|
|
||||||
pc: 0,
|
|
||||||
s: 0xfd,
|
|
||||||
microcode_step: 0,
|
|
||||||
address_bus: 0x0000,
|
|
||||||
data_bus: 0x00,
|
|
||||||
ir: Instruction {
|
|
||||||
op: Operation::NOP,
|
|
||||||
mode: AddressMode::Implied,
|
|
||||||
operand: Operand::None,
|
|
||||||
},
|
|
||||||
oi: OpInfo {
|
|
||||||
operation: Operation::NOP,
|
|
||||||
mode: AddressMode::Implied,
|
|
||||||
length: 1,
|
|
||||||
cycles: 2,
|
|
||||||
},
|
|
||||||
has_reset: false,
|
|
||||||
iv: 0xfffe
|
|
||||||
};
|
};
|
||||||
working.reset_cpu();
|
working.reset_cpu();
|
||||||
working
|
working
|
||||||
@ -159,9 +140,8 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ticks the CPU
|
/// Ticks the CPU
|
||||||
/// Returns
|
pub fn tick(&mut self) {
|
||||||
/// AddressBus, DataBus, RW flag
|
|
||||||
pub fn tick(&mut self) -> (u16, u8, bool) {
|
|
||||||
println!("PREPARiNG TO TICK CPU AT PC 0x{:04x}", self.pc);
|
println!("PREPARiNG TO TICK CPU AT PC 0x{:04x}", self.pc);
|
||||||
if self.microcode_step == 0 {
|
if self.microcode_step == 0 {
|
||||||
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
||||||
@ -176,9 +156,27 @@ impl Mos6502Cpu {
|
|||||||
// set the counter to the number of steps left
|
// set the counter to the number of steps left
|
||||||
} else {
|
} else {
|
||||||
// run 1 microcode step
|
// run 1 microcode step
|
||||||
println!("Microstep {} for {:?}", self.microcode_step, self.ir.op);
|
println!("Microstep {}/{} for {:?}", self.microcode_step, self.oi.cycles, self.ir.op);
|
||||||
match self.ir.op {
|
match self.ir.op {
|
||||||
Operation::ADC => {
|
Operation::ADC => {
|
||||||
|
match self.microcode_step {
|
||||||
|
1 => {
|
||||||
|
match self.ir.mode {
|
||||||
|
AddressMode::Immediate => {}
|
||||||
|
AddressMode::ZeroPage => {}
|
||||||
|
AddressMode::ZeroPageX => {}
|
||||||
|
AddressMode::Absolute => {}
|
||||||
|
AddressMode::AbsoluteX => {}
|
||||||
|
AddressMode::AbsoluteY => {}
|
||||||
|
AddressMode::Indirect => {}
|
||||||
|
AddressMode::IndirectX => {}
|
||||||
|
AddressMode::IndirectY => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2 => {},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Operation::AND => {}
|
Operation::AND => {}
|
||||||
Operation::ASL => {}
|
Operation::ASL => {}
|
||||||
@ -207,7 +205,65 @@ impl Mos6502Cpu {
|
|||||||
Operation::CMP => {}
|
Operation::CMP => {}
|
||||||
Operation::CPX => {}
|
Operation::CPX => {}
|
||||||
Operation::CPY => {}
|
Operation::CPY => {}
|
||||||
Operation::DEC => {}
|
Operation::DEC => {
|
||||||
|
match self.microcode_step {
|
||||||
|
// DEC Step 1
|
||||||
|
1 => {
|
||||||
|
let working_value = match self.oi.mode {
|
||||||
|
AddressMode::ZeroPage => {
|
||||||
|
// read from
|
||||||
|
let offset = match self.ir.operand {
|
||||||
|
Operand::Byte(z) => {
|
||||||
|
z
|
||||||
|
}
|
||||||
|
_ => { 0x00 }
|
||||||
|
};
|
||||||
|
println!("READING FROM MEMORY AT 0x{offset:04x}");
|
||||||
|
self.memory[offset as usize]
|
||||||
|
// self.peek(offset);
|
||||||
|
}
|
||||||
|
AddressMode::ZeroPageX => {
|
||||||
|
let offset = match self.ir.operand {
|
||||||
|
Operand::Byte(z) => {
|
||||||
|
z
|
||||||
|
}
|
||||||
|
_ => { 0x00 }
|
||||||
|
};
|
||||||
|
// self.memory.peek(offset + self.x);
|
||||||
|
self.memory[offset as usize]
|
||||||
|
}
|
||||||
|
AddressMode::Absolute => {
|
||||||
|
let offset = match self.ir.operand {
|
||||||
|
Operand::Word(offset) => {
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
_ => { 0x00 }
|
||||||
|
};
|
||||||
|
// self.memory.peek(offset)
|
||||||
|
self.memory[offset as usize]
|
||||||
|
}
|
||||||
|
AddressMode::AbsoluteX => {
|
||||||
|
let offset = match self.ir.operand {
|
||||||
|
Operand::Word(offset) => {
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
_ => { 0x00 }
|
||||||
|
};
|
||||||
|
// self.memory.peek(offset + self.x);
|
||||||
|
self.memory[offset as usize]
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
0x00
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// DEC write memory
|
||||||
|
2 => {
|
||||||
|
self.a = self.cycle_carry as u8;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Operation::DEX => {
|
Operation::DEX => {
|
||||||
if self.microcode_step == 1 {
|
if self.microcode_step == 1 {
|
||||||
let (new_x, new_carry) = self.x.overflowing_sub(1);
|
let (new_x, new_carry) = self.x.overflowing_sub(1);
|
||||||
@ -264,10 +320,28 @@ impl Mos6502Cpu {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AddressMode::ZeroPageX => {}
|
AddressMode::ZeroPageX => {
|
||||||
|
match self.ir.operand {
|
||||||
|
Operand::Byte(value) => {
|
||||||
|
let x_offset = self.x;
|
||||||
|
self.a = self.memory[(value + x_offset) as usize];
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
AddressMode::ZeroPageY => {}
|
AddressMode::ZeroPageY => {}
|
||||||
AddressMode::Absolute => {}
|
AddressMode::Absolute => {
|
||||||
AddressMode::AbsoluteX => {}
|
if let Operand::Word(offset) = self.ir.operand {
|
||||||
|
println!("Loading from absolute address 0x{offset:04x}");
|
||||||
|
self.a = self.memory[offset as usize];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
AddressMode::AbsoluteX => {
|
||||||
|
if let Operand::Word(offset) = self.ir.operand {
|
||||||
|
self.a = self.memory[(offset + self.x as u16) as usize];
|
||||||
|
}
|
||||||
|
}
|
||||||
AddressMode::AbsoluteY => {}
|
AddressMode::AbsoluteY => {}
|
||||||
AddressMode::Indirect => {}
|
AddressMode::Indirect => {}
|
||||||
AddressMode::IndirectX => {}
|
AddressMode::IndirectX => {}
|
||||||
@ -385,8 +459,6 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
self.microcode_step -= 1;
|
self.microcode_step -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
(0,0,false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(&self) {
|
pub fn dump(&self) {
|
||||||
@ -398,16 +470,12 @@ impl Mos6502Cpu {
|
|||||||
(self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step)
|
(self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_microstep(&self, instruction: Instruction, step: u8) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::constants::constants_isa_op::*;
|
use crate::constants::constants_isa_op::*;
|
||||||
use crate::instruction_table::INSTRUCTION_TABLE;
|
use crate::instruction_table::{INSTRUCTION_CYCLES, INSTRUCTION_TABLE};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -445,7 +513,7 @@ mod test {
|
|||||||
cpu.memory[0x6000] = ISA_OP_CLI;
|
cpu.memory[0x6000] = ISA_OP_CLI;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLI as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLI) { cpu.tick(); }
|
||||||
|
|
||||||
assert!(!cpu.peek_flag(Interrupt));
|
assert!(!cpu.peek_flag(Interrupt));
|
||||||
|
|
||||||
@ -458,7 +526,7 @@ mod test {
|
|||||||
cpu.memory[0x6000] = ISA_OP_CLV;
|
cpu.memory[0x6000] = ISA_OP_CLV;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLV as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLV) { cpu.tick(); }
|
||||||
|
|
||||||
assert!(!cpu.peek_flag(Overflow));
|
assert!(!cpu.peek_flag(Overflow));
|
||||||
}
|
}
|
||||||
@ -470,24 +538,73 @@ mod test {
|
|||||||
cpu.memory[0x6001] = 0xab;
|
cpu.memory[0x6001] = 0xab;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_LDA_I as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_I) { cpu.tick(); }
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xab);
|
assert_eq!(cpu.a, 0xab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lda_zx() {
|
||||||
|
let mut cpu = Mos6502Cpu::default();
|
||||||
|
cpu.poke_x(1);
|
||||||
|
cpu.memory[0x6000] = ISA_OP_LDA_ZX;
|
||||||
|
cpu.memory[0x6001] = 0xab;
|
||||||
|
cpu.memory[0x00ac] = 0xbe;
|
||||||
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ZX) { cpu.tick(); };
|
||||||
|
|
||||||
|
// println!("MEMORY AT 0x00aa, ab, ac, ad, ae -> {:02x} {:02x} {:02x} {:02x} {:02x}", cpu.memory[0x00aa], cpu.memory[0x00ab], cpu.memory[0x00ac], cpu.memory[0x00ad], cpu.memory[0x00ae]);
|
||||||
|
// cpu.dump();
|
||||||
|
assert_eq!(cpu.peek_a(), 0xbe);
|
||||||
|
assert!(!cpu.peek_flag(Zero));
|
||||||
|
assert!(!cpu.peek_flag(Carry));
|
||||||
|
assert!(!cpu.peek_flag(Negative));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lda_zeropage() {
|
fn lda_zeropage() {
|
||||||
let mut cpu = Mos6502Cpu::default();
|
let mut cpu = Mos6502Cpu::default();
|
||||||
cpu.memory[0x6000] = ISA_OP_LDA_Z;
|
cpu.memory[0x6000] = ISA_OP_LDA_Z;
|
||||||
cpu.memory[0x6001] = 0xab;
|
cpu.memory[0x6001] = 0xab;
|
||||||
|
// Load ZeroPage
|
||||||
cpu.memory[0x00ab] = 0xbe;
|
cpu.memory[0x00ab] = 0xbe;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_LDA_Z as usize].unwrap().cycles + 1 { cpu.tick(); }
|
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_LDA_Z) { cpu.tick(); }
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xbe);
|
assert_eq!(cpu.a, 0xbe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lda_absolute() {
|
||||||
|
let mut cpu = Mos6502Cpu::default();
|
||||||
|
cpu.memory[0x6000] = ISA_OP_LDA_ABS;
|
||||||
|
cpu.memory[0x6001] = 0xef;
|
||||||
|
cpu.memory[0x6002] = 0xbe;
|
||||||
|
cpu.memory[0xbeef] = 0xab;
|
||||||
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) { cpu.tick(); }
|
||||||
|
|
||||||
|
assert_eq!(cpu.a, 0xab);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lda_absolutex() {
|
||||||
|
let mut cpu = Mos6502Cpu::default();
|
||||||
|
cpu.memory[0x6000] = ISA_OP_LDA_ABSX;
|
||||||
|
cpu.memory[0x6001] = 0xef;
|
||||||
|
cpu.memory[0x6002] = 0xbe;
|
||||||
|
cpu.poke_x(0x01);
|
||||||
|
cpu.memory[0xbef0] = 0xab;
|
||||||
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) { cpu.tick(); }
|
||||||
|
|
||||||
|
assert_eq!(cpu.a, 0xab);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dex_inx() {
|
fn dex_inx() {
|
||||||
let mut cpu = Mos6502Cpu::default();
|
let mut cpu = Mos6502Cpu::default();
|
||||||
@ -496,9 +613,9 @@ mod test {
|
|||||||
cpu.memory[0x6001] = ISA_OP_INX;
|
cpu.memory[0x6001] = ISA_OP_INX;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_TABLE[ISA_OP_DEX as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEX) { cpu.tick(); }
|
||||||
assert_eq!(0xaa, cpu.x);
|
assert_eq!(0xaa, cpu.x);
|
||||||
for _ in 0..=INSTRUCTION_TABLE[ISA_OP_INX as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INX) { cpu.tick(); }
|
||||||
assert_eq!(0xab, cpu.x);
|
assert_eq!(0xab, cpu.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,9 +627,9 @@ mod test {
|
|||||||
cpu.memory[0x6001] = ISA_OP_INY;
|
cpu.memory[0x6001] = ISA_OP_INY;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_TABLE[ISA_OP_DEY as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEY) { cpu.tick(); }
|
||||||
assert_eq!(0xaa, cpu.peek_y());
|
assert_eq!(0xaa, cpu.peek_y());
|
||||||
for _ in 0..=INSTRUCTION_TABLE[ISA_OP_INY as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INY) { cpu.tick(); }
|
||||||
assert_eq!(0xab, cpu.peek_y());
|
assert_eq!(0xab, cpu.peek_y());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,9 +641,9 @@ mod test {
|
|||||||
cpu.memory[0x6001] = ISA_OP_ROR_A;
|
cpu.memory[0x6001] = ISA_OP_ROR_A;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_TABLE[ISA_OP_ROL_A as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROL_A) { cpu.tick(); }
|
||||||
assert_eq!(cpu.peek_a(), 0b0101_0101);
|
assert_eq!(cpu.peek_a(), 0b0101_0101);
|
||||||
for _ in 0..=INSTRUCTION_TABLE[ISA_OP_ROR_A as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROR_A) { cpu.tick(); }
|
||||||
assert_eq!(cpu.peek_a(), 0b1010_1010);
|
assert_eq!(cpu.peek_a(), 0b1010_1010);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,117 +5,121 @@ pub enum Operation {
|
|||||||
///
|
///
|
||||||
/// Affects flags: N, V, Z, C
|
/// Affects flags: N, V, Z, C
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Immediate, ZeroPage, ZeroPageX, Absolute, AbsoluteX, AbsoluteY, IndirectX, IndirectY
|
/// Addressing Modes: Immediate (2/2), ZeroPage (2/3), ZeroPageX (2/4), Absolute (3/4),
|
||||||
|
/// AbsoluteX (3/4), AbsoluteY (3/4), IndirectX (2/6), IndirectY (2/5)
|
||||||
ADC,
|
ADC,
|
||||||
|
|
||||||
/// Logical AND with Accumulator
|
/// Logical AND with Accumulator
|
||||||
///
|
///
|
||||||
/// Affects flags: N, Z
|
/// Affects flags: N, Z
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Immediate, ZeroPage, ZeroPageX, Absolute, AbsoluteX, AbsoluteY, IndirectX, IndirectY
|
/// Addressing Modes: Immediate (2/2), ZeroPage (2/3), ZeroPageX (2/4), Absolute (3/4),
|
||||||
|
/// AbsoluteX (3/4), AbsoluteY (3/4), IndirectX (2/6), IndirectY (2/5)
|
||||||
AND,
|
AND,
|
||||||
|
|
||||||
/// Arithmetic Shift Left
|
/// Arithmetic Shift Left
|
||||||
///
|
///
|
||||||
/// Affects flags: N, Z, C
|
/// Affects flags: N, Z, C
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Accumulator, ZeroPage, ZeroPageX, Absolute, AbsoluteX
|
/// Addressing Modes: Accumulator (1/2), ZeroPage (2/5), ZeroPageX (2/6), Absolute (3/6),
|
||||||
|
/// AbsoluteX (3/7)
|
||||||
ASL,
|
ASL,
|
||||||
|
|
||||||
/// Branch if Carry Clear
|
/// Branch if Carry Clear
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BCC,
|
BCC,
|
||||||
|
|
||||||
/// Branch if Carry Set
|
/// Branch if Carry Set
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BCS,
|
BCS,
|
||||||
|
|
||||||
/// Branch if Equal (Zero Set)
|
/// Branch if Equal (Zero Set)
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BEQ,
|
BEQ,
|
||||||
|
|
||||||
/// Bit Test
|
/// Bit Test
|
||||||
///
|
///
|
||||||
/// Affects flags: N, V, Z
|
/// Affects flags: N, V, Z
|
||||||
///
|
///
|
||||||
/// Addressing Modes: ZeroPage, Absolute
|
/// Addressing Modes: ZeroPage (2/3), Absolute (3/4)
|
||||||
BIT,
|
BIT,
|
||||||
|
|
||||||
/// Branch if Minus (Negative Set)
|
/// Branch if Minus (Negative Set)
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BMI,
|
BMI,
|
||||||
|
|
||||||
/// Branch if Not Equal (Zero Clear)
|
/// Branch if Not Equal (Zero Clear)
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BNE,
|
BNE,
|
||||||
|
|
||||||
/// Branch if Positive (Negative Clear)
|
/// Branch if Positive (Negative Clear)
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BPL,
|
BPL,
|
||||||
|
|
||||||
/// Force Interrupt
|
/// Force Interrupt
|
||||||
///
|
///
|
||||||
/// Affects flags: B
|
/// Affects flags: B
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Implied
|
/// Addressing Modes: Implied (1/7)
|
||||||
BRK,
|
BRK,
|
||||||
|
|
||||||
/// Branch if Overflow Clear
|
/// Branch if Overflow Clear
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BVC,
|
BVC,
|
||||||
|
|
||||||
/// Branch if Overflow Set
|
/// Branch if Overflow Set
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Relative
|
/// Addressing Modes: Relative (2/2)
|
||||||
BVS,
|
BVS,
|
||||||
|
|
||||||
/// Clear Carry Flag
|
/// Clear Carry Flag
|
||||||
///
|
///
|
||||||
/// Affects flags: C
|
/// Affects flags: C
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Implied
|
/// Addressing Modes: Implied (1/2)
|
||||||
CLC,
|
CLC,
|
||||||
|
|
||||||
/// Clear Decimal Mode
|
/// Clear Decimal Mode
|
||||||
///
|
///
|
||||||
/// Affects flags: D
|
/// Affects flags: D
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Implied
|
/// Addressing Modes: Implied (1/2)
|
||||||
CLD,
|
CLD,
|
||||||
|
|
||||||
/// Clear Interrupt Disable
|
/// Clear Interrupt Disable
|
||||||
///
|
///
|
||||||
/// Affects flags: I
|
/// Affects flags: I
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Implied
|
/// Addressing Modes: Implied (1/2)
|
||||||
CLI,
|
CLI,
|
||||||
|
|
||||||
/// Clear Overflow Flag
|
/// Clear Overflow Flag
|
||||||
///
|
///
|
||||||
/// Affects flags: V
|
/// Affects flags: V
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Implied
|
/// Addressing Modes: Implied (2/2)
|
||||||
CLV,
|
CLV,
|
||||||
|
|
||||||
/// Compare Accumulator
|
/// Compare Accumulator
|
||||||
///
|
///
|
||||||
/// Affects flags: N, Z, C
|
/// Affects flags: N, Z, C
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Immediate, ZeroPage, ZeroPageX, Absolute, AbsoluteX, AbsoluteY, IndirectX, IndirectY
|
/// Addressing Modes: Immediate (2/2), ZeroPage (2/3), ZeroPageX (2/4), Absolute (3/4),
|
||||||
|
/// AbsoluteX (3/4), AbsoluteY (3/4), IndirectX (2/6), IndirectY (2/5)
|
||||||
CMP,
|
CMP,
|
||||||
|
|
||||||
/// Compare X Register
|
/// Compare X Register
|
||||||
///
|
///
|
||||||
/// Affects flags: N, Z, C
|
/// Affects flags: N, Z, C
|
||||||
///
|
///
|
||||||
/// Addressing Modes: Immediate, ZeroPage, Absolute
|
/// Addressing Modes: Immediate (2/2), ZeroPage (2/3), Absolute (3/4)
|
||||||
CPX,
|
CPX,
|
||||||
|
|
||||||
/// Compare Y Register
|
/// Compare Y Register
|
||||||
|
|||||||
0
core/tests/execution_tests.rs
Normal file
0
core/tests/execution_tests.rs
Normal file
Loading…
x
Reference in New Issue
Block a user