removes sccache

updates display of ben eater pc
doesnt blow up when creating a rom chip anymore
doesnt blow up when creating a pc anymore
This commit is contained in:
Trevor Merritt 2025-06-28 12:37:01 -04:00
parent d89fc1cd2b
commit e5c2319803
14 changed files with 232 additions and 30 deletions

View File

@ -1,5 +1,2 @@
[alias] [alias]
coverage = "tarpaulin --out Html --skip-clean --output-dir coverage" coverage = "tarpaulin --out Html --skip-clean --output-dir coverage"
[build]
rustc-wrapper = "sccache"

4
Cargo.lock generated
View File

@ -75,9 +75,9 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]] [[package]]
name = "beneater" name = "beneater"

View File

@ -1,5 +1,10 @@
// This is the GUI for the BenEater PC // This is the GUI for the BenEater PC
use beneater::parts::cpu_display::CpuDisplay;
use macroquad::prelude::*; use macroquad::prelude::*;
use macroquad::telemetry::frame;
use beneater::parts::ben_eater_pc::BenEaterPC;
use beneater::parts::display_matrix::DisplayMatrix;
#[macroquad::main("Ben Eaters PC")] #[macroquad::main("Ben Eaters PC")]
async fn main() { async fn main() {
@ -7,10 +12,32 @@ async fn main() {
let computer = BenEaterPC::new(); let computer = BenEaterPC::new();
let mut dm = DisplayMatrix::new(200.0, 50.0);
let message_to_show = "Taxation is theft";
let mut message_index = 0;
dm.push_letter('T');
let mut frame_number: u32 = 0x00;
loop { loop {
clear_background(BLUE); clear_background(BLUE);
draw_text("Ben Eater", 20.0, 20.0, 30.0, BLACK); 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);
frame_number += 1;
if frame_number.is_multiple_of(60) {
dm.push_letter('X');
}
if frame_number.is_multiple_of(60 * 6) {
dm.clear_display()
}
next_frame().await next_frame().await
} }
} }

View File

@ -0,0 +1,9 @@
pub struct AddressBus {
pub address: u16
}
impl AddressBus {
pub fn new() -> Self {
AddressBus { address: 0x0000 }
}
}

View File

@ -1,13 +1,17 @@
use crate::parts::clock::Clock; use crate::parts::clock::Clock;
use core::mos6502cpu::Mos6502Cpu; use core::mos6502cpu::Mos6502Cpu;
struct BenEaterPC { pub struct BenEaterPC {
clock: Clock, clock: Clock,
cpu: Mos6502Cpu, // pub because i am rendering it.
// there should be a proper interface to get the data
// for ui out of this.
pub cpu: Mos6502Cpu,
} }
impl BenEaterPC { impl BenEaterPC {
pub fn new() -> Self { pub fn new() -> Self {
println!("New BENEATERPC");
BenEaterPC { BenEaterPC {
clock: Clock::new(), clock: Clock::new(),
cpu: Mos6502Cpu::default() cpu: Mos6502Cpu::default()

View File

@ -0,0 +1,28 @@
use macroquad::color::{BLACK, Color};
use macroquad::prelude::*;
use macroquad::text::draw_text;
use core::mos6502cpu::Mos6502Cpu;
pub struct CpuDisplay {}
impl CpuDisplay {
pub fn render(cpu: &Mos6502Cpu, x_offset: f32, y_offset: f32) {
// get the data to display...
let (pc, a, x, y, address_bus, data_bus) = cpu.dump_data();
// ...build the interface
Self::draw_square(x_offset, y_offset, x_offset + 300.0, y_offset + 85.0, BLACK);
draw_text(format!("PC: 0x{:04x} / {}", pc, pc).as_str(), x_offset + 5.0, y_offset + 18.0, 15.0, BLACK);
draw_text(format!("A: 0x{:02x} X: 0x{:02x} Y: 0x{:02x}", a, x, y).as_str(), x_offset + 5.0, y_offset + 35.0, 15.0, BLACK);
draw_text(format!("Address: {:016b} | {:04x}", address_bus, address_bus).as_str(), x_offset + 5.0, y_offset + 55.0, 15.0, BLACK);
draw_text(format!("Data: {:08b} | {:02x}", data_bus, data_bus).as_str(), x_offset + 5.0, y_offset + 75.0, 15.0, BLACK);
}
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);
}
}

View File

@ -0,0 +1,9 @@
pub struct DataBus {
pub data: u8
}
impl DataBus {
pub fn new() -> Self {
DataBus { data: 0x00 }
}
}

View File

@ -0,0 +1,79 @@
use macroquad::prelude::*;
use crate::parts::address_bus::AddressBus;
use crate::parts::data_bus::DataBus;
pub struct DisplayMatrix {
width: f32,
height: f32,
text_buffer: String,
data_bus: DataBus,
rs: bool,
rw: bool,
cursor_position: u8
}
impl DisplayMatrix {
pub fn new(width: f32, height: f32) -> DisplayMatrix {
DisplayMatrix {
width,
height,
text_buffer: String::from(""),
data_bus: DataBus::new(),
rs: false,
rw: false,
cursor_position: 0x00
}
}
/// Tick
///
/// Checks the data bus and sees what the setup is.
///
/// 0 0 0 0 0 0 0 1 -> Clear Display
/// 0 0 0 0 0 0 1 - -> Return Home
/// 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.
}
pub fn set_busses(&mut self, address_bus: &mut AddressBus, data_bus: &mut DataBus) {
}
pub fn push_letter(&mut self, letter_to_push: char) {
self.cursor_position += 1;
self.text_buffer.push(letter_to_push)
}
pub fn clear_display(&mut self) {
self.cursor_position = 0;
self.text_buffer.clear()
}
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);
}
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);
}
}

View File

@ -1,3 +1,8 @@
pub mod clock; pub mod clock;
mod ben_eater_pc; pub mod ben_eater_pc;
mod via6522; pub mod via6522;
pub mod display_matrix;
pub mod address_bus;
pub mod data_bus;
pub mod cpu_display;
mod ram_display;

View File

@ -0,0 +1,20 @@
use macroquad::prelude::*;
pub struct RamDisplay {}
impl RamDisplay {
pub fn render(ram: &Box<[u8]>, x_offset: f32, y_offset: f32) {
Self::draw_square(x_offset, y_offset, x_offset + 200.0, y_offset + 300.0, BLACK);
draw_text("RAM", x_offset + 5.0, y_offset + 5.0, 15.0, BLACK);
}
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);
}
}

View File

@ -19,12 +19,12 @@ impl Via6522 {
} }
// check for output pins and see what they say /// check for output pins and see what they say
pub fn update_pins(&mut self) { pub fn update_pins(&mut self) {
} }
// check for input mode pins and see what they say /// check for input mode pins and see what they say
pub fn read_pins(&self) { pub fn read_pins(&self) {
} }

View File

@ -5,7 +5,8 @@ pub const SIZE_32KB: usize = SIZE_1KB * 32;
pub const SIZE_64KB: usize = SIZE_1KB * 64; pub const SIZE_64KB: usize = SIZE_1KB * 64;
pub struct Mos6502Cpu { pub struct Mos6502Cpu {
memory: [u8; SIZE_64KB], // this is public for rendering quickly.
pub memory: Box<[u8]>,
a: u8, a: u8,
x: u8, x: u8,
y: u8, y: u8,
@ -13,20 +14,24 @@ pub struct Mos6502Cpu {
pc: u16, pc: u16,
s: u8, s: u8,
pub microcode_step: u8, pub microcode_step: u8,
address_bus: u16, pub address_bus: u16,
data_bus: u8, pub data_bus: u8,
ir: u8 // Instruction Register ir: u8 // Instruction Register
} }
impl Default for Mos6502Cpu { impl Default for Mos6502Cpu {
fn default() -> Self { 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");
Mos6502Cpu { Mos6502Cpu {
memory: [0x00; SIZE_64KB], memory: boxed_array,
a: 0, a: 0,
x: 0, x: 0,
y: 0, y: 0,
flags: Default::default(), flags: Default::default(),
pc: 0, pc: 0xfffd,
s: 0, s: 0,
microcode_step: 0, microcode_step: 0,
address_bus: 0, address_bus: 0,
@ -38,8 +43,11 @@ impl Default for Mos6502Cpu {
impl Mos6502Cpu { impl Mos6502Cpu {
pub fn new() -> Mos6502Cpu { 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");
Mos6502Cpu { Mos6502Cpu {
memory: [0; SIZE_64KB], memory: boxed_array,
a: 0, a: 0,
x: 0, x: 0,
y: 0, y: 0,
@ -103,5 +111,7 @@ impl Mos6502Cpu {
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus); self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus);
} }
pub fn dump_data(&self) -> ( u16, u8, u8, u8, u16, u8) {
(self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus)
}
} }

View File

@ -1,4 +1,4 @@
use crate::mos6502cpu::SIZE_32KB; use crate::mos6502cpu::{SIZE_32KB, SIZE_64KB};
use crate::periph::rom_chip::RomChip; use crate::periph::rom_chip::RomChip;
/// At28C256 /// At28C256
@ -8,24 +8,37 @@ use crate::periph::rom_chip::RomChip;
/// 256kbit storage /// 256kbit storage
/// 32kbyte storage /// 32kbyte storage
pub struct At28C256 { pub struct At28C256 {
data: [u8; SIZE_32KB] data: Box<[u8; SIZE_32KB]>,
}
impl Default for At28C256 {
fn default() -> Self {
let vec = vec![0x00; SIZE_32KB];
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice.try_into().expect("Failed to convert Vec to boxed array");
At28C256 {
data: boxed_array,
}
}
} }
impl RomChip for At28C256 { impl RomChip for At28C256 {
fn read(&self, offset: &u16) -> u8 { fn read(&self, offset: &u16) -> u8 {
self.data[*offset as usize] self.data[*offset as usize]
} }
fn program(new_data: &[u8; SIZE_32KB]) -> Self { fn program(new_data: Box<[u8; 33554432]>) -> Box<At28C256> {
println!("Writing new chip."); println!("Writing new chip.");
At28C256 { let mut working = At28C256::default();
data: *new_data working.data = Box::new(*new_data);
} working.into()
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::mos6502cpu::SIZE_1KB;
use super::*; use super::*;
#[test] #[test]
@ -36,16 +49,18 @@ mod test {
#[test] #[test]
fn programmed_data_reads_back_same() { fn programmed_data_reads_back_same() {
print!("Starting test..."); print!("Starting test...");
let data_to_write = [0xea; SIZE_32KB]; let mut data = At28C256::default();
for i in 0..SIZE_32KB {
data.data[i] = 0xea;
}
print!("allocated data for rom..."); print!("allocated data for rom...");
let chip: At28C256 = At28C256::program(&data_to_write);
println!("programmed chip..."); println!("programmed chip...");
print!("testing"); print!("testing");
for offset in 0..SIZE_32KB { for offset in 0..SIZE_32KB {
if offset.is_multiple_of(1000) { if offset.is_multiple_of(SIZE_1KB) {
print!("."); print!(".");
}; };
assert_eq!(0xea, chip.read(&(offset as u16))); assert_eq!(0xea, data.read(&(offset as u16)));
} }
println!("passed!"); println!("passed!");
} }

View File

@ -8,10 +8,9 @@ pub trait RomChip {
/// Program /// Program
/// ///
/// Replaces all data in the ROM chip /// Replaces all data in the ROM chip
fn program(new_data: &[u8; SIZE_32KB]) -> Self; fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box<Self>;
} }
pub trait RamChip: RomChip { pub trait RamChip: RomChip {
fn write(&mut self, offset: &u16, value: &u8); fn write(&mut self, offset: &u16, value: &u8);
} }