more stuff

This commit is contained in:
Trevor Merritt 2025-07-05 11:49:04 -04:00
parent 2cfd570789
commit cf14804df2
10 changed files with 268 additions and 44 deletions

View File

@ -11,12 +11,9 @@ async fn main() {
let mut backplane = Backplane::new(); let mut backplane = Backplane::new();
backplane.load_rom("resources/beneater/roms/ror.bin"); backplane.load_rom("resources/beneater/roms/ror.bin");
let mut dm = DisplayMatrix::new(200.0, 50.0); 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'); // dm.push_letter('T');
let mut frame_number: u32 = 0x00; let mut frame_number: u32 = 0x00;
loop { loop {

26
beneater/src/bin/urn.rs Normal file
View File

@ -0,0 +1,26 @@
use std::fs;
use std::ops::Index;
use beneater::parts::backplane::Backplane;
use core::constants::constants_system::*;
use core::constants::constants_isa_op::*;
fn main() {
println!("Taxation is Theft");
let mut backplane = Backplane::new();
println!("Backplane is live.");
let mut new_program = [0x00u8; SIZE_32KB];
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize] = 0x00;
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
println!("Set offset in rom...");
println!("VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ", new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]);
// println!("{:?}", new_program);
backplane.rom.program(&new_program);
backplane.cpu.pc = 0x6000;
backplane.memory[0x6000] = ISA_OP_LDA_I;
backplane.memory[0x6001] = 0xab;
backplane.tick();
}

View File

@ -3,11 +3,13 @@ use crate::parts::mos6522_peripheral::Mos6522Peripheral;
use crate::parts::via6522::VIA6522; use crate::parts::via6522::VIA6522;
use core::constants::constants_system::*; use core::constants::constants_system::*;
use core::periph::at28c256::At28C256; use core::periph::at28c256::At28C256;
use core::periph::rom_chip::RomChip;
pub struct Backplane { pub struct Backplane {
cpu: Mos6502Cpu, // pub for dev
via: VIA6522, pub cpu: Mos6502Cpu,
memory: [u8; SIZE_64KB], pub via: VIA6522,
rom: At28C256 pub memory: Box<[u8; SIZE_64KB]>,
pub rom: At28C256
} }
impl Backplane { impl Backplane {
@ -15,7 +17,7 @@ impl Backplane {
Backplane { Backplane {
cpu: Mos6502Cpu::default(), cpu: Mos6502Cpu::default(),
via: VIA6522::default(), via: VIA6522::default(),
memory: [0x00; SIZE_64KB], memory: Box::new([0x00; SIZE_64KB]),
rom: At28C256::default() rom: At28C256::default()
} }
} }
@ -28,6 +30,17 @@ impl Backplane {
// is the CPU in read or write state // is the CPU in read or write state
let address = self.cpu.address_bus(); let address = self.cpu.address_bus();
let data = self.cpu.data_bus(); let data = self.cpu.data_bus();
let rw = self.cpu.read_signal;
println!("- TICK START:");
println!("| CPU: Address: 0b{address:016b} Data: 0b{data:08b} CPU RW: {rw}");
// via state
println!("| VIA 0b{:08b}/0b{:08b}/0b{:08b}/0b{:08b}/",
self.via.read(VIA6522_ORA),
self.via.read(VIA6522_ORA),
self.via.read(VIA6522_DDRB),
self.via.read(VIA6522_DDRA),
);
println!("| LCD");
match address { match address {
/// VIA /// VIA
0x6000..0x6010 => { 0x6000..0x6010 => {
@ -36,23 +49,25 @@ impl Backplane {
} else { } else {
self.via.write((address - 0x6000) as u8, self.cpu.data_bus()); self.via.write((address - 0x6000) as u8, self.cpu.data_bus());
} }
self.via.tick();
} }
/// RAM /// RAM
0x0000..=0x3fff => { 0x0000..=0x3fff => {
if self.cpu.read_signal { if self.cpu.read_signal {
self.cpu.set_data_bus(self.memory[address as usize]); self.cpu.set_data_bus(self.memory[address as usize]);
} else { } else {
self.memory[*address as usize] = data; self.memory[address as usize] = data;
} }
} }
/// ROM /// ROM
0x4000..=0x7fff => { 0x4000..=0x7fff => {
self.rom.read(&(address - 0x4000));
} }
/// The ether. Scarrrrrrrryyyy...... /// The ether. Scarrrrrrrryyyy......
_ => { _ => {
println!("Lost READ:?{} to {:04x}", self.cpu.read_signal, address); println!("Lost READ:?{} to {:04x}", self.cpu.read_signal, address);
} }
} }
println!("- TICK DONE");
} }
} }

View File

@ -4,6 +4,7 @@ use std::io::{BufReader, Read};
use std::path::Path; use std::path::Path;
use crate::parts::clock::Clock; use crate::parts::clock::Clock;
use core::mos6502cpu::Mos6502Cpu; use core::mos6502cpu::Mos6502Cpu;
use core::constants::constants_system::*;
pub struct BenEaterPC { pub struct BenEaterPC {
clock: Clock, clock: Clock,
@ -49,7 +50,11 @@ impl BenEaterPC {
buffer.truncate(bytes_read); buffer.truncate(bytes_read);
chunks.push(buffer[0]); chunks.push(buffer[0]);
} }
println!("Loaded {}b of data.", chunks.len()); let data_size = chunks.len();
self.cpu.memory = chunks.into(); print!("Loaded {}b of data. Poking into memory...", data_size);
for i in 0..SIZE_32KB {
self.cpu.poke(i as u16, chunks[i]);
}
println!("poke complete. Poked {}b of data.", data_size);
} }
} }

View File

@ -1,4 +1,5 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
#[derive(Debug)] #[derive(Debug)]
pub struct HD44780 { pub struct HD44780 {
@ -31,6 +32,36 @@ pub struct HD44780 {
last_command_time: Instant, last_command_time: Instant,
} }
impl Mos6522Peripheral for HD44780 {
fn write(&mut self, port: u8) {
println!("Writing {port:08b}/{port:02x} to HD44780");
self.set_data_bus(port);
}
/// Control
///
/// Takes a u8 with the bottom 3 bits representing
/// X X X X X rs rw en
fn control(&mut self, control: u8) {
self.write_control_lines(
control & 1 << 2 == 0,
control & 1 << 1 == 0,
control & 1 == 0
);
}
fn read(&mut self) -> u8 {
self.data_bus
}
fn tick(&mut self) {
println!("TICK OF HD44780");
if self.busy && self.last_command_time.elapsed() > Duration::from_micros(50) {
self.busy = false;
}
}
}
impl HD44780 { impl HD44780 {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -86,12 +117,6 @@ impl HD44780 {
} }
} }
pub fn tick(&mut self) {
if self.busy && self.last_command_time.elapsed() > Duration::from_micros(50) {
self.busy = false;
}
}
fn evaluate(&mut self) { fn evaluate(&mut self) {
if self.rw { if self.rw {
return; return;
@ -157,7 +182,6 @@ impl HD44780 {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -171,8 +195,7 @@ mod tests {
fn test_clear_display() { fn test_clear_display() {
let mut lcd = HD44780::new(); let mut lcd = HD44780::new();
lcd.set_data_bus(0x01); lcd.set_data_bus(0x01);
lcd.write_control_lines(false, false, true); pulse_enable(&mut lcd);
lcd.write_control_lines(false, false, false);
lcd.tick(); lcd.tick();
assert!(lcd.ddram.iter().all(|&b| b == b' ')); assert!(lcd.ddram.iter().all(|&b| b == b' '));
} }
@ -181,8 +204,7 @@ mod tests {
fn test_write_data() { fn test_write_data() {
let mut lcd = HD44780::new(); let mut lcd = HD44780::new();
lcd.set_data_bus(0x41); // 'A' lcd.set_data_bus(0x41); // 'A'
lcd.write_control_lines(true, false, true); pulse_enable(&mut lcd);
lcd.write_control_lines(true, false, false);
lcd.tick(); lcd.tick();
assert_eq!(lcd.ddram[0], b'A'); assert_eq!(lcd.ddram[0], b'A');
} }
@ -191,8 +213,7 @@ mod tests {
fn test_set_cursor() { fn test_set_cursor() {
let mut lcd = HD44780::new(); let mut lcd = HD44780::new();
lcd.set_data_bus(0x80 | 0x40); lcd.set_data_bus(0x80 | 0x40);
lcd.write_control_lines(false, false, true); pulse_enable(&mut lcd);
lcd.write_control_lines(false, false, false);
lcd.tick(); lcd.tick();
assert_eq!(lcd.cursor_position, 0x40); assert_eq!(lcd.cursor_position, 0x40);
} }
@ -206,4 +227,47 @@ mod tests {
let data = lcd.read_data_bus(); let data = lcd.read_data_bus();
assert_eq!(data, 0x80 | 0x15); assert_eq!(data, 0x80 | 0x15);
} }
#[test]
fn hello_world_display() {
let mut lcd = HD44780::new();
let setup_instructions = [
0b0000_0000, // cls
0b0011_1000, // display mode
0b0000_1110, // display on
0b0000_0110, // entry mode
];
for instruction in setup_instructions {
lcd.write_control_lines(false, false, true);
lcd.set_data_bus(instruction);
pulse_enable(&mut lcd);
lcd.tick();
}
let letter_instructions = [
0b0100_1000, // H
0b0100_0101, // E
0b0100_1100, // L
0b0100_1100, // L
0b0100_1111, // O
0b0100_0000, // _
0b0101_0111, // W
0b0100_1111, // O
0b0101_0010, // R
0b0100_1100, // L
0b0100_0100, // D
];
// move cursor to start of next line.
lcd.write_control_lines(true, false, true);
lcd.set_data_bus(0b1100_0000);
pulse_enable(&mut lcd);
lcd.tick();
let (line1, line2) = lcd.get_display_lines();
println!("LINE1 -> [{}]", line1);
println!("LINE2 -> [{}]", line2);
}
} }

View File

@ -1,5 +1,12 @@
pub trait Mos6522Peripheral { pub trait Mos6522Peripheral {
/// Write to the data bus
fn write(&mut self, port: u8); fn write(&mut self, port: u8);
fn control(&mut self, control: u8); fn control(&mut self, control: u8);
/// Read the data bus
fn read(&mut self) -> u8; fn read(&mut self) -> u8;
/// Tick
///
/// Run 1 clock cycle of the peripheral
fn tick(&mut self);
} }

View File

@ -1,6 +1,7 @@
use crate::parts::display_matrix::HD44780; use crate::parts::display_matrix::HD44780;
use crate::parts::mos6522_peripheral::Mos6522Peripheral; use crate::parts::mos6522_peripheral::Mos6522Peripheral;
use core::constants::constants_system::*;
#[derive(Default)]
pub struct VIA6522 { pub struct VIA6522 {
// Data registers // Data registers
ora: u8, ora: u8,
@ -52,16 +53,17 @@ impl VIA6522 {
t2_enabled: false, t2_enabled: false,
ifr: 0, ifr: 0,
ier: 0, ier: 0,
lcd: Some(HD44780::new().into()), lcd: Some(Box::new(HD44780::new())),
} }
} }
pub fn read(&self, addr: u8) -> u8 { pub fn read(&self, addr: u8) -> u8 {
match addr & 0x0F { match (addr & 0x0F) {
0x0 => self.orb, VIA6522_ORB => self.orb,
0x1 => self.ora, VIA6522_ORA => self.ora,
0x2 => self.ddrb, VIA6522_DDRB => self.ddrb,
0x3 => self.ddra, VIA6522_DDRA => self.ddra,
0x4 => (self.t1_counter & 0xFF) as u8, 0x4 => (self.t1_counter & 0xFF) as u8,
0x5 => (self.t1_counter >> 8) as u8, 0x5 => (self.t1_counter >> 8) as u8,
0x6 => (self.t1_latch & 0xFF) as u8, 0x6 => (self.t1_latch & 0xFF) as u8,
@ -75,11 +77,12 @@ impl VIA6522 {
} }
pub fn write(&mut self, addr: u8, value: u8) { pub fn write(&mut self, addr: u8, value: u8) {
println!("VIA6522 write value 0x{value:02x} to address 0x{addr:02x}");
match addr & 0x0F { match addr & 0x0F {
0x0 => self.orb = value, VIA6522_ORB => self.orb = value,
0x1 => self.ora = value, VIA6522_ORA => self.ora = value,
0x2 => self.ddrb = value, VIA6522_DDRB => self.ddrb = value,
0x3 => self.ddra = value, VIA6522_DDRA => self.ddra = value,
0x4 => { 0x4 => {
self.t1_latch = (self.t1_latch & 0xFF00) | value as u16; self.t1_latch = (self.t1_latch & 0xFF00) | value as u16;
self.t1_counter = self.t1_latch; self.t1_counter = self.t1_latch;
@ -125,3 +128,89 @@ impl VIA6522 {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_initialization() {
let via = VIA6522::new();
assert_eq!(via.ora, 0);
assert_eq!(via.orb, 0);
assert_eq!(via.ddra, 0);
assert_eq!(via.ddrb, 0);
assert_eq!(via.t1_counter, 0);
assert_eq!(via.t2_counter, 0);
assert!(via.lcd.is_some());
}
#[test]
fn test_read_write_registers() {
let mut via = VIA6522::new();
via.write(0x0, 0xAA);
assert_eq!(via.read(0x0), 0xAA);
via.write(0x1, 0xBB);
assert_eq!(via.read(0x1), 0xBB);
via.write(0x2, 0xCC);
assert_eq!(via.read(0x2), 0xCC);
via.write(0x3, 0xDD);
assert_eq!(via.read(0x3), 0xDD);
}
#[test]
fn test_timer1_write_and_tick() {
let mut via = VIA6522::new();
via.write(0x4, 0x34); // Low byte
via.write(0x5, 0x12); // High byte, also enables timer
assert_eq!(via.t1_latch, 0x1234);
assert_eq!(via.t1_counter, 0x1234);
assert!(via.t1_enabled);
for _ in 0..0x1234 {
via.tick();
}
assert_eq!(via.t1_counter, 0);
assert_eq!(via.ifr & 0x40, 0x40); // T1 interrupt flag set
}
#[test]
fn test_timer2_write_and_tick() {
let mut via = VIA6522::new();
via.t2_enabled = true;
via.write(0x8, 0x05); // Counter
for _ in 0..5 {
via.tick();
}
assert_eq!(via.t2_counter, 0);
assert_eq!(via.ifr & 0x20, 0x20); // T2 interrupt flag set
}
#[test]
fn test_interrupt_enable_disable() {
let mut via = VIA6522::new();
via.write(0xE, 0x82); // Enable bit 0x02
assert_eq!(via.ier & 0x02, 0x02);
via.write(0xE, 0x02); // Disable bit 0x02
assert_eq!(via.ier & 0x02, 0x00);
}
#[test]
fn test_clear_interrupt_flags() {
let mut via = VIA6522::new();
via.ifr = 0xFF;
via.write(0xD, 0x40); // Clear T1 interrupt
assert_eq!(via.ifr & 0x40, 0x00);
}
}

View File

@ -4,3 +4,9 @@ pub const SIZE_64KB: usize = SIZE_1KB * 64;
pub const OFFSET_RESET_VECTOR: u16 = 0xfffc; pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
pub const OFFSET_INT_VECTOR: u16 = 0xfffe; pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
pub const VIA6522_ORB: u8 = 0;
pub const VIA6522_ORA: u8 = 1;
pub const VIA6522_DDRB: u8 = 2;
pub const VIA6522_DDRA: u8 = 3;

View File

@ -21,7 +21,7 @@ pub struct Mos6502Cpu {
/// cpu flags /// cpu flags
flags: Mos6502Flags, flags: Mos6502Flags,
/// program counter /// program counter
pc: u16, pub pc: u16,
/// stack offset /// stack offset
s: u8, s: u8,
pub microcode_step: u8, pub microcode_step: u8,
@ -104,14 +104,22 @@ impl Mos6502Cpu {
// read the value at 0xfffc 0xfffd for our reset vector. // read the value at 0xfffc 0xfffd for our reset vector.
// read the value at 0xfffe 0xffff for our int vector // read the value at 0xfffe 0xffff for our int vector
self.pc = self.read_word(&OFFSET_RESET_VECTOR); self.pc = self.read_word(&OFFSET_RESET_VECTOR);
println!("READ FROM {OFFSET_RESET_VECTOR} AND GOT {}", self.pc);
self.iv = self.read_word(&OFFSET_INT_VECTOR); self.iv = self.read_word(&OFFSET_INT_VECTOR);
println!("PC and IV are now set from ROM addresses"); self.address_bus = self.pc;
self.read_signal = true;
println!("PC and IV are now set from ROM addresses / AB = {:016b}", self.address_bus);
} }
fn read_word(&self, offset: &u16) -> u16 { fn read_word(&self, offset: &u16) -> u16 {
println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
let low = self.memory[*offset as usize]; let low = self.memory[*offset as usize];
let high = self.memory[*offset as usize + 1]; let high = self.memory[*offset as usize + 1];
(high as u16) << 8 | low as u16 println!("LOW = 0x{low:02x} HIGH = 0x{high:02x}");
let result = (high as u16) << 8 | low as u16;
// println!("MEMORY: {:?}", self.memory);
println!("READ {result:04x}");
result
} }
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool { pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
@ -513,6 +521,10 @@ impl Mos6502Cpu {
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step, self.flags.dump()); self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step, self.flags.dump());
} }
/// dump_data
///
/// returns
/// PC, A, X, Y, Address_Bus, Data_Bus, Microcode_Step
pub fn dump_data(&self) -> ( u16, u8, u8, u8, u16, u8, u8) { pub fn dump_data(&self) -> ( u16, u8, u8, u8, u16, u8, u8) {
(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)
} }

View File

@ -1,6 +1,7 @@
mod default; mod default;
mod rom_chip; mod rom_chip;
use std::io::Read;
use crate::constants::constants_system::SIZE_32KB; use crate::constants::constants_system::SIZE_32KB;
use crate::periph::rom_chip::RomChip; use crate::periph::rom_chip::RomChip;
@ -15,8 +16,10 @@ pub struct At28C256 {
} }
impl At28C256 { impl At28C256 {
pub fn program(&mut self, new_program: &[u8; 32768]) { pub fn program(&mut self, new_program: &[u8; SIZE_32KB]) {
self.data= new_program.into(); // panic!("FAIL. Cant program the chip.");
// println!("PROGRAMMING {:?}", new_program);
self.data = Box::new(*new_program);
} }
} }