more stuff i worked on

This commit is contained in:
Trevor Merritt 2025-07-03 16:32:55 -04:00
parent e4405cc225
commit 2cfd570789
13 changed files with 564 additions and 292 deletions

View File

@ -3,13 +3,14 @@ use beneater::parts::cpu_display::CpuDisplay;
use macroquad::prelude::*;
use macroquad::telemetry::frame;
use beneater::parts::ben_eater_pc::BenEaterPC;
use beneater::parts::display_matrix::DisplayMatrix;
use beneater::parts::backplane::Backplane;
#[macroquad::main("Ben Eaters PC")]
async fn main() {
println!("Taxation is Theft");
let mut computer = BenEaterPC::new();
computer.load_rom("resources/beneater/roms/ror.bin");
let mut backplane = Backplane::new();
backplane.load_rom("resources/beneater/roms/ror.bin");
let mut dm = DisplayMatrix::new(200.0, 50.0);
let message_to_show = "Taxation is theft";
@ -23,7 +24,7 @@ async fn main() {
draw_text("Ben Eater", 20.0, 20.0, 30.0, BLACK);
dm.render(20.0, 40.0);
CpuDisplay::render(&computer.cpu, 20.0, 120.0);
// CpuDisplay::render(&computer.cpu, 20.0, 120.0);
frame_number += 1;
@ -37,6 +38,5 @@ async fn main() {
}
next_frame().await
}
}

View File

@ -0,0 +1,58 @@
use core::mos6502cpu::Mos6502Cpu;
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
use crate::parts::via6522::VIA6522;
use core::constants::constants_system::*;
use core::periph::at28c256::At28C256;
pub struct Backplane {
cpu: Mos6502Cpu,
via: VIA6522,
memory: [u8; SIZE_64KB],
rom: At28C256
}
impl Backplane {
pub fn new() -> Self {
Backplane {
cpu: Mos6502Cpu::default(),
via: VIA6522::default(),
memory: [0x00; SIZE_64KB],
rom: At28C256::default()
}
}
pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
self.rom.program(to_load);
}
pub fn tick(&mut self) {
// is the CPU in read or write state
let address = self.cpu.address_bus();
let data = self.cpu.data_bus();
match address {
/// VIA
0x6000..0x6010 => {
if self.cpu.read_signal {
self.cpu.set_data_bus(self.via.read((address - 0x6000) as u8));
} else {
self.via.write((address - 0x6000) as u8, self.cpu.data_bus());
}
}
/// RAM
0x0000..=0x3fff => {
if self.cpu.read_signal {
self.cpu.set_data_bus(self.memory[address as usize]);
} else {
self.memory[*address as usize] = data;
}
}
/// ROM
0x4000..=0x7fff => {
}
/// The ether. Scarrrrrrrryyyy......
_ => {
println!("Lost READ:?{} to {:04x}", self.cpu.read_signal, address);
}
}
}
}

View File

@ -1,197 +1,209 @@
use macroquad::prelude::*;
use crate::parts::address_bus::AddressBus;
use crate::parts::data_bus::DataBus;
use crate::parts::display_matrix::MatrixEntryMode::{Delete, DeleteShift, Insert, InsertShift};
use std::time::{Duration, Instant};
pub enum MatrixEntryMode {
Delete,
DeleteShift,
Insert,
InsertShift,
}
pub struct DisplayMatrix {
width: f32,
height: f32,
text_buffer: [u8; 80],
cgram: [u8; 64],
data_bus: DataBus,
#[derive(Debug)]
pub struct HD44780 {
// Bus inputs
data_bus: u8,
rs: bool,
rw: bool,
enable: bool,
prev_enable: bool,
// Internal memory
ddram: [u8; 80],
cgram: [u8; 64],
// Cursor & display state
cursor_position: u8,
busy: bool,
entry_mode: MatrixEntryMode,
cursor: bool,
display_on: bool,
blink: bool,
cursor_shift: bool,
display_shift: bool,
enabled: bool,
cursor_on: bool,
blink_on: bool,
entry_increment: bool,
entry_shift: bool,
// Function set flags
data_length_8bit: bool,
two_line_mode: bool,
font_5x10: bool,
// Busy flag
busy: bool,
last_command_time: Instant,
}
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 {
let mut matrix = DisplayMatrix {
width,
height,
text_buffer: String::from(""),
data_bus: DataBus::new(),
impl HD44780 {
pub fn new() -> Self {
Self {
data_bus: 0,
rs: false,
rw: false,
cursor_position: 0x00,
busy: false,
entry_mode: MatrixEntryMode::InsertShift,
display_on: false,
cursor: false,
blink: false,
cursor_shift: false,
display_shift: false,
enabled: false,
};
matrix
}
enable: false,
prev_enable: false,
/// Tick
pub fn tick(&mut self, rw: bool, rs: bool, enabled: bool, data: u8) {
self.enabled = enabled;
self.data_bus.data = data;
self.rw = rw;
self.rs = rs;
// parse whats on the data bus.
match (self.rs, self.rw) {
(true, true) => {
// read from cg or ddram
}
(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.display_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
}
}
}
ddram: [b' '; 80],
cgram: [0; 64],
cursor_position: 0,
display_on: true,
cursor_on: false,
blink_on: false,
entry_increment: true,
entry_shift: false,
data_length_8bit: true,
two_line_mode: true,
font_5x10: false,
busy: false,
last_command_time: Instant::now(),
}
}
pub fn push_letter(&mut self, letter_to_push: char) {
self.cursor_position += 1;
self.text_buffer.push(letter_to_push)
pub fn write_control_lines(&mut self, rs: bool, rw: bool, enable: bool) {
self.rs = rs;
self.rw = rw;
// On rising edge of Enable
if enable && !self.prev_enable {
self.evaluate();
}
self.prev_enable = enable;
}
pub fn clear_display(&mut self) {
self.cursor_position = 0;
self.text_buffer.clear()
pub fn set_data_bus(&mut self, value: u8) {
self.data_bus = value;
}
pub fn render(&self, x_offset: f32, y_offset: f32) {
DisplayMatrix::draw_square(x_offset,
y_offset,
x_offset + self.width,
y_offset + self.height,
BLACK);
let mut tmp = self.text_buffer.clone();
tmp.push('#');
draw_text(&*tmp, x_offset + 5.0, y_offset + 20.0, 20.0, BLACK);
pub fn read_data_bus(&self) -> u8 {
if !self.rs && self.rw {
// Return busy flag + current address
let busy_flag = if self.busy { 0x80 } else { 0x00 };
busy_flag | (self.cursor_position & 0x7F)
} else {
// Not implemented: read from DDRAM/CGRAM
0
}
}
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
// println!("Square from {x1:2.0}x{y1:2.0} to {x2:2.0}x{y2:2.0} with {:?}", color);
draw_line(x1, y1, x2, y1, 1.0, color);
draw_line(x1, y1, x1, y2, 1.0, color);
draw_line(x1, y2, x2, y2, 1.0, color);
draw_line(x2, y1, x2, y2, 1.0, color);
pub fn tick(&mut self) {
if self.busy && self.last_command_time.elapsed() > Duration::from_micros(50) {
self.busy = false;
}
}
fn evaluate(&mut self) {
if self.rw {
return;
}
if self.rs {
self.write_data(self.data_bus);
} else {
self.execute_command(self.data_bus);
}
self.busy = true;
self.last_command_time = Instant::now();
}
fn write_data(&mut self, data: u8) {
if self.cursor_position < 0x50 {
self.ddram[self.cursor_position as usize] = data;
self.cursor_position = self.cursor_position.wrapping_add(1);
}
}
fn execute_command(&mut self, cmd: u8) {
match cmd {
0x01 => {
self.ddram.fill(b' ');
self.cursor_position = 0;
}
0x02 => {
self.cursor_position = 0;
}
0x04..=0x07 => {
self.entry_increment = (cmd & 0b10) != 0;
self.entry_shift = (cmd & 0b01) != 0;
}
0x08..=0x0F => {
self.display_on = (cmd & 0b100) != 0;
self.cursor_on = (cmd & 0b010) != 0;
self.blink_on = (cmd & 0b001) != 0;
}
0x10..=0x1F => {
// Cursor/display shift — not yet implemented
}
0x20..=0x3F => {
self.data_length_8bit = (cmd & 0b10000) != 0;
self.two_line_mode = (cmd & 0b1000) != 0;
self.font_5x10 = (cmd & 0b100) != 0;
}
0x40..=0x7F => {
// Set CGRAM address — stub
}
0x80..=0xFF => {
self.cursor_position = cmd & 0x7F;
}
_ => {}
}
}
pub fn get_display_lines(&self) -> (String, String) {
let row1: String = self.ddram[0x00..0x10].iter().map(|&b| b as char).collect();
let row2: String = self.ddram[0x40..0x50].iter().map(|&b| b as char).collect();
(row1, row2)
}
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
#[test]
fn smoke() { assert!(true); }
fn pulse_enable(lcd: &mut HD44780) {
lcd.write_control_lines(lcd.rs, lcd.rw, true);
lcd.write_control_lines(lcd.rs, lcd.rw, false);
}
#[test]
fn device_init() {
let display = DisplayMatrix::new(100.0, 100.0);
fn test_clear_display() {
let mut lcd = HD44780::new();
lcd.set_data_bus(0x01);
lcd.write_control_lines(false, false, true);
lcd.write_control_lines(false, false, false);
lcd.tick();
assert!(lcd.ddram.iter().all(|&b| b == b' '));
}
#[test]
fn test_write_data() {
let mut lcd = HD44780::new();
lcd.set_data_bus(0x41); // 'A'
lcd.write_control_lines(true, false, true);
lcd.write_control_lines(true, false, false);
lcd.tick();
assert_eq!(lcd.ddram[0], b'A');
}
#[test]
fn test_set_cursor() {
let mut lcd = HD44780::new();
lcd.set_data_bus(0x80 | 0x40);
lcd.write_control_lines(false, false, true);
lcd.write_control_lines(false, false, false);
lcd.tick();
assert_eq!(lcd.cursor_position, 0x40);
}
#[test]
fn test_read_busy_flag_and_address() {
let mut lcd = HD44780::new();
lcd.busy = true;
lcd.cursor_position = 0x15;
lcd.write_control_lines(false, true, true);
let data = lcd.read_data_bus();
assert_eq!(data, 0x80 | 0x15);
}
}

View File

@ -6,3 +6,5 @@ pub mod address_bus;
pub mod data_bus;
pub mod cpu_display;
pub mod ram_display;
pub mod mos6522_peripheral;
pub mod backplane;

View File

@ -0,0 +1,5 @@
pub trait Mos6522Peripheral {
fn write(&mut self, port: u8);
fn control(&mut self, control: u8);
fn read(&mut self) -> u8;
}

View File

@ -1,45 +1,127 @@
pub enum Via6522Port {
A(u8),
B(u8)
use crate::parts::display_matrix::HD44780;
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
pub struct VIA6522 {
// Data registers
ora: u8,
orb: u8,
// Data direction
ddra: u8,
ddrb: u8,
// Control lines (external pins)
ca1: bool,
ca2: bool,
cb1: bool,
cb2: bool,
// Timers
t1_counter: u16,
t1_latch: u16,
t1_enabled: bool,
t2_counter: u16,
t2_latch: u16,
t2_enabled: bool,
// Interrupt flags
ifr: u8,
ier: u8,
// Peripheral (e.g., LCD)
pub lcd: Option<Box<dyn Mos6522Peripheral>>,
}
#[derive(Default)]
pub struct Via6522 {
data_bus: u8,
address_bus: u16,
port_a_state: u8,
port_b_data: u8,
port_a_direction: u8,
port_b_direction: u8,
memory_offset: u16,
}
impl Via6522 {
pub fn new(offset: u16) -> Self {
Via6522 {
memory_offset: offset,
..Default::default()
impl VIA6522 {
pub fn new() -> Self {
Self {
ora: 0,
orb: 0,
ddra: 0,
ddrb: 0,
ca1: false,
ca2: false,
cb1: false,
cb2: false,
t1_counter: 0,
t1_latch: 0,
t1_enabled: false,
t2_counter: 0,
t2_latch: 0,
t2_enabled: false,
ifr: 0,
ier: 0,
lcd: Some(HD44780::new().into()),
}
}
pub fn set_port_direction(&mut self, port: Via6522Port) {
match port {
Via6522Port::A(x) => {
self.port_a_direction = x;
},
Via6522Port::B(x) => {
self.port_b_direction = x;
pub fn read(&self, addr: u8) -> u8 {
match addr & 0x0F {
0x0 => self.orb,
0x1 => self.ora,
0x2 => self.ddrb,
0x3 => self.ddra,
0x4 => (self.t1_counter & 0xFF) as u8,
0x5 => (self.t1_counter >> 8) as u8,
0x6 => (self.t1_latch & 0xFF) as u8,
0x7 => (self.t1_latch >> 8) as u8,
0x8 => (self.t2_counter & 0xFF) as u8,
0x9 => (self.t2_latch & 0xFF) as u8,
0xD => self.ifr,
0xE => self.ier | 0x80,
_ => 0,
}
}
pub fn write(&mut self, addr: u8, value: u8) {
match addr & 0x0F {
0x0 => self.orb = value,
0x1 => self.ora = value,
0x2 => self.ddrb = value,
0x3 => self.ddra = value,
0x4 => {
self.t1_latch = (self.t1_latch & 0xFF00) | value as u16;
self.t1_counter = self.t1_latch;
}
0x5 => {
self.t1_latch = (value as u16) << 8 | (self.t1_latch & 0x00FF);
self.t1_counter = self.t1_latch;
self.t1_enabled = true;
}
0x6 => self.t1_latch = (self.t1_latch & 0xFF00) | value as u16,
0x7 => self.t1_latch = (value as u16) << 8 | (self.t1_latch & 0x00FF),
0x8 => self.t2_counter = value as u16,
0x9 => self.t2_latch = value as u16,
0xD => self.ifr &= !value, // Clear interrupt flags
0xE => {
if value & 0x80 != 0 {
self.ier |= value & 0x7F;
} else {
self.ier &= !(value & 0x7F);
}
}
_ => {}
}
}
pub fn tick(&mut self) {
if self.t1_enabled {
if self.t1_counter > 0 {
self.t1_counter -= 1;
if self.t1_counter == 0 {
self.ifr |= 0x40; // Set T1 interrupt
}
}
}
if self.t2_enabled {
if self.t2_counter > 0 {
self.t2_counter -= 1;
if self.t2_counter == 0 {
self.ifr |= 0x20; // Set T2 interrupt
}
}
}
}
/// check for output pins and see what they say
pub fn update_pins(&mut self) {
}
/// check for input mode pins and see what they say
pub fn read_pins(&self) {
}
}

View File

@ -2,6 +2,5 @@ pub const SIZE_1KB: usize = 1024;
pub const SIZE_32KB: usize = SIZE_1KB * 32;
pub const SIZE_64KB: usize = SIZE_1KB * 64;
pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;

View File

@ -11,33 +11,47 @@ use crate::constants::constants_system::*;
use crate::instruction_table::INSTRUCTION_TABLE;
pub struct Mos6502Cpu {
// this is public for rendering quickly.
pub memory: Box<[u8]>,
memory: [u8; SIZE_64KB],
/// accumulator
a: u8,
/// x register
x: u8,
/// y register
y: u8,
/// cpu flags
flags: Mos6502Flags,
/// program counter
pc: u16,
/// stack offset
s: u8,
pub microcode_step: u8,
pub address_bus: u16,
pub data_bus: u8,
address_bus: u16,
data_bus: u8,
ir: Instruction, // Instruction Register
oi: OpInfo,
has_reset: bool,
iv: u16, // Interrupt Vector
cycle_carry: u16, // Value to hold between microsteps
ir_bytes: Box<[u8]>
ir_bytes: [u8; 4],
/// CPU Read signal
pub read_signal: bool
}
impl Mos6502Cpu {
/// set_data_bus
///
/// Sets data on the data bus.
/// Used when CPU is in "R" mode
pub fn set_data_bus(&mut self, to_set: u8) {
self.data_bus = to_set;
}
}
impl Default for Mos6502Cpu {
fn default() -> Self {
let vec = vec![0x00; SIZE_64KB];
let boxed_slize: Box<[u8]> = vec.into_boxed_slice();
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
let mut working = Mos6502Cpu {
memory: boxed_array,
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
@ -56,7 +70,8 @@ impl Default for Mos6502Cpu {
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [].into()
ir_bytes: [0x00; 4],
read_signal: true
};
working.reset_cpu();
working
@ -64,13 +79,19 @@ impl Default for Mos6502Cpu {
}
impl Mos6502Cpu {
pub fn address_bus(&self) -> u16 {
self.address_bus
}
pub fn data_bus(&self) -> u8 {
self.data_bus
}
pub fn new() -> Mos6502Cpu {
let vec = vec![0x00; SIZE_64KB];
let boxed_slize: Box<[u8]> = vec.into_boxed_slice();
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
let array = [0x00u8; SIZE_64KB];
let mut working = Mos6502Cpu {
memory: boxed_array,
ir_bytes: [].into(),
memory: array,
ir_bytes: [0x00; 4],
..Default::default()
};
working.reset_cpu();
@ -105,6 +126,7 @@ impl Mos6502Cpu {
}
pub fn poke(&mut self, offset: u16, value: u8) {
println!("Setting memory at {offset:04x} to {value:02x}");
self.memory[offset as usize] = value
}
@ -112,7 +134,10 @@ impl Mos6502Cpu {
self.a
}
pub fn poke_a(&mut self, new_a: u8) {
self.a = new_a;
println!("Updating register A from [{}] to [{}]", self.a, new_a);
self.a = new_a;
}
pub fn peek_x(&self) -> u8 {
@ -284,6 +309,8 @@ impl Mos6502Cpu {
let (new_x, new_carry) = self.x.overflowing_add(1);
self.poke_x(new_x);
self.poke_flag(Carry, new_carry);
self.address_bus = self.pc;
self.data_bus = 0x00;
}
}
Operation::INY => {
@ -291,11 +318,15 @@ impl Mos6502Cpu {
let (new_y, new_carry) = self.y.overflowing_add(1);
self.poke_y(new_y);
self.poke_flag(Carry, new_carry);
self.address_bus = self.pc;
self.data_bus = 0x00;
} }
Operation::JMP => {
match self.ir.operand {
Operand::Word(offset) => {
self.pc = offset;
self.address_bus = self.pc;
self.data_bus = 0x00;
}
_ => {}
}
@ -597,8 +628,8 @@ mod test {
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.memory[0x6002] = 0x0e;
cpu.memory[0x0eef] = 0xab;
cpu.pc = 0x6000;
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) { cpu.tick(); }
@ -611,9 +642,9 @@ mod test {
let mut cpu = Mos6502Cpu::default();
cpu.memory[0x6000] = ISA_OP_LDA_ABSX;
cpu.memory[0x6001] = 0xef;
cpu.memory[0x6002] = 0xbe;
cpu.memory[0x6002] = 0x0e;
cpu.poke_x(0x01);
cpu.memory[0xbef0] = 0xab;
cpu.memory[0x0ef0] = 0xab;
cpu.pc = 0x6000;
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSX) { cpu.tick(); }
@ -628,7 +659,7 @@ mod test {
cpu.memory[0x6001] = 0xef;
cpu.memory[0x6002] = 0xbe;
cpu.poke_y(0x01);
cpu.memory[0xbef0] = 0xab;
cpu.memory[0x0ef0] = 0xab;
cpu.pc = 0x6000;
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSY) { cpu.tick(); }

View File

@ -1,4 +1,12 @@
use crate::mos6502flags::Mos6502Flag::{Break, Carry, Decimal, Interrupt, Negative, Overflow, Zero};
pub const BIT_NEGATIVE: u8 = 7;
pub const BIT_OVERFLOW: u8 = 6;
pub const BIT_BREAK: u8 = 4;
pub const BIT_DECIMAL: u8 = 3;
pub const BIT_INTERRUPT: u8 = 2;
pub const BIT_ZERO: u8 = 1;
pub const BIT_CARRY: u8 = 0;
/// Represents the status flags in the 6502 processor's status register (P).
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Mos6502Flag {
@ -42,7 +50,21 @@ pub enum Mos6502Flag {
Negative,
}
#[derive(Default)]
impl Mos6502Flag {
pub fn index(&self) -> u8 {
match self {
Carry => BIT_CARRY,
Zero => BIT_ZERO,
Interrupt => BIT_INTERRUPT,
Decimal => BIT_DECIMAL,
Break => BIT_BREAK,
Overflow => BIT_OVERFLOW,
Negative => BIT_NEGATIVE
}
}
}
#[derive(Default, PartialEq, Debug)]
pub struct Mos6502Flags {
carry: bool,
zero: bool,
@ -56,78 +78,133 @@ pub struct Mos6502Flags {
impl Mos6502Flags {
pub fn dump(&self) -> String {
format!("{}{}{}{}{}{}{}",
if self.carry { 'C' } else { 'c' },
if self.zero { 'Z' } else { 'z' },
if self.interrupt { 'I' } else { 'i' },
if self.decimal { 'D' } else { 'd' },
if self.break_flag { 'B' } else { 'b' },
if self.overflow { 'O' } else { 'o' },
if self.negative { 'N' } else { 'n' }
if self.carry { 'C' } else { 'c' },
if self.zero { 'Z' } else { 'z' },
if self.interrupt { 'I' } else { 'i' },
if self.decimal { 'D' } else { 'd' },
if self.break_flag { 'B' } else { 'b' },
if self.overflow { 'O' } else { 'o' },
if self.negative { 'N' } else { 'n' }
)
}
}
impl Mos6502Flags {
pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) {
self.change_flag(flag_to_set, true);
println!("Setting {flag_to_set:?} flag");
match flag_to_set {
Carry => self.carry = true,
Zero => self.zero = true,
Interrupt => self.interrupt = true,
Decimal => self.decimal = true,
Break => self.break_flag = true,
Overflow => self.overflow = true,
Negative => self.negative = true,
}
}
pub fn clear_flag(&mut self, flag_to_clear: Mos6502Flag) {
self.change_flag(flag_to_clear, false);
}
println!("Clearing {flag_to_clear:?} flag");
match flag_to_clear {
Carry => self.carry = false,
Zero => self.zero = false,
Interrupt => self.interrupt = false,
Decimal => self.decimal = false,
Break => self.break_flag = false,
Overflow => self.overflow = false,
Negative => self.negative = false,
} }
fn change_flag(&mut self, flag_to_change: Mos6502Flag, new_value: bool) {
match flag_to_change {
Mos6502Flag::Carry => {
self.carry = new_value
}
Mos6502Flag::Zero => {
self.zero = new_value
}
Mos6502Flag::Interrupt => {
self.interrupt = new_value
}
Mos6502Flag::Decimal => {
self.decimal = new_value
}
Mos6502Flag::Break => {
self.break_flag = new_value
}
Mos6502Flag::Overflow => {
self.overflow = new_value
}
Mos6502Flag::Negative => {
self.negative = new_value
}
if new_value {
self.set_flag(flag_to_change);
} else {
self.clear_flag(flag_to_change);
}
}
pub fn flag(&self, flag_to_read: Mos6502Flag) -> bool {
match flag_to_read {
Mos6502Flag::Carry => {
self.carry
}
Mos6502Flag::Zero => {
self.zero
}
Mos6502Flag::Interrupt => {
self.interrupt
}
Mos6502Flag::Decimal => {
self.decimal
}
Mos6502Flag::Break => {
self.break_flag
}
Mos6502Flag::Overflow => {
self.overflow
}
Mos6502Flag::Negative => {
self.negative
}
Mos6502Flag::Negative => self.negative,
Mos6502Flag::Overflow => self.overflow,
// 5
Mos6502Flag::Break => self.break_flag,
Mos6502Flag::Decimal => self.decimal,
Mos6502Flag::Interrupt => self.interrupt,
Mos6502Flag::Zero => self.zero,
Mos6502Flag::Carry => self.carry,
}
}
pub fn as_byte(&self) -> u8 {
let mut working = 0x00;
if self.flag(Negative) { working += 1 << Negative.index(); }
if self.flag(Overflow) { working += 1 << Overflow.index(); }
working += 1 << 5; // Always Set
if self.flag(Break) { working += 1 << Break.index(); }
if self.flag(Decimal) { working += 1 << Decimal.index(); }
if self.flag(Interrupt) { working += 1 << Interrupt.index(); }
if self.flag(Zero) { working += 1 << Zero.index(); }
if self.flag(Carry) { working += 1 << Carry.index(); }
working
}
pub fn from_byte(src: u8) -> Self {
let mut working = Self::default();
working.change_flag(Negative, Self::bit(src, Negative.index()));
working.change_flag(Overflow, Self::bit(src, Overflow.index()));
working.change_flag(Break, Self::bit(src, Break.index()));
working.change_flag(Decimal, Self::bit(src, Decimal.index()));
working.change_flag(Interrupt, Self::bit(src, Interrupt.index()));
working.change_flag(Zero, Self::bit(src, Zero.index()));
working.change_flag(Carry, Self::bit(src, Carry.index()));
working
}
/// bit
///
/// src -> Source byte to check in
/// pos -> Which bit to check
///
/// returns bool
///
/// True if the bit is set.
/// False if the bit is not set
#[inline]
fn bit(src: u8, pos: u8) -> bool {
(src >> pos) & 1 != 0
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn sanity() {
let f = Mos6502Flags::default();
let magic_byte = 0b1110_1101;
let magic_flags = Mos6502Flags {
carry: true,
zero: false,
interrupt: true,
decimal: true,
break_flag: false,
overflow: true,
negative: true,
};
assert_eq!(magic_flags, Mos6502Flags::from_byte(magic_byte));
}
}

View File

@ -14,6 +14,12 @@ pub struct At28C256 {
data: Box<[u8; SIZE_32KB]>,
}
impl At28C256 {
pub fn program(&mut self, new_program: &[u8; 32768]) {
self.data= new_program.into();
}
}
#[cfg(test)]
mod test {
use crate::constants::constants_system::SIZE_1KB;

View File

@ -8,7 +8,7 @@ impl RomChip for At28C256 {
self.data[*offset as usize]
}
fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box<At28C256> {
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
println!("Writing new chip.");
let mut working = At28C256::default();
working.data = Box::new(*new_data);

View File

@ -29,7 +29,7 @@ impl RomChip for Hm62256 {
self.data[effective as usize]
}
fn program(_: Box<[u8; SIZE_32KB]>) -> Box<Self> {
fn program(_: &[u8; SIZE_32KB]) -> Box<Self> {
debug!("Dont program ram.");
Hm62256::default().into()
}

View File

@ -8,5 +8,5 @@ pub trait RomChip {
/// Program
///
/// Replaces all data in the ROM chip
fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box<Self>;
fn program(new_data: &[u8; SIZE_32KB]) -> Box<Self>;
}