more fixed stuff

This commit is contained in:
2025-07-16 15:01:16 -04:00
parent ff43a99e0c
commit 6fcf1547d1
29 changed files with 625 additions and 139 deletions
+80
View File
@@ -0,0 +1,80 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
use crate::constants::constants_test::*;
impl At28C256 {
/// checksum
///
/// calculates and returns the checksum for the loaded binary.
/// files with all zero will calculate to zero
pub fn checksum(&self) -> u8 {
At28C256::checksum_static(&self.data[..])
}
pub fn checksum_static(data: &[u8]) -> u8 {
data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b))
}
}
#[cfg(test)]
mod test {
use std::fs;
use std::path::Path;
use crate::constants::constants_system::SIZE_1KB;
use crate::periph::rom_chip::RomChip;
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn programmed_data_reads_back_same() {
let mut data = At28C256::default();
for i in 0..SIZE_32KB {
data.data[i] = 0xeau8;
}
for offset in 0..SIZE_32KB {
if offset.is_multiple_of(SIZE_1KB) {};
assert_eq!(0xea, data.read(&(offset as u16)));
}
}
#[test]
fn checksums_calculate_correctly_for_zero() {
let data1 = [0x00u8; SIZE_32KB];
assert_eq!(0x00, At28C256::checksum_static(&data1));
}
#[test]
fn checksums_calculate_for_1_byte() {
let data = [0xff; 1];
assert_eq!(0xff, At28C256::checksum_static(&data));
}
#[test]
fn checksums_calculate_for_2_bytes() {
let data = [0xff; 2];
// 0xff + 0xff = 0x1fe
assert_eq!(0xfe, At28C256::checksum_static(&data));
}
#[test]
fn checksums_calculate_for_first_80_bytes() {
println!("STARTING TEST");
let mut checksum = 0x00;
let path = format!("{}{}", TEST_PERIPH_AT28C256_ROOT, "/checksum.bin");
println!("READING [{path}]");
let data = fs::read(path);
match data {
Ok(bytes) => {
println!("Read {} bytes", bytes.len());
checksum = At28C256::checksum_static(&bytes);
println!("Checksum: 0x{:02x}", checksum);
}
Err(e) => eprintln!("Failed to read file: {}", e),
}
assert_eq!(0x58, checksum);
println!("TEST COMPLETE");
}
}
+6 -4
View File
@@ -9,10 +9,12 @@ impl Default for At28C256 {
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice
.try_into()
.expect("Failed to convert Vec to boxed array");
At28C256 { data: boxed_array,
address_bus: 0x0000,
data_bus: 0x00,
offset: 0x0000
At28C256 {
data: boxed_array,
address_bus: 0x0000,
data_bus: 0x00,
offset: 0x0000,
max_offset: 0x3fff,
}
}
}
+5 -26
View File
@@ -4,6 +4,7 @@ pub mod tick;
mod new;
mod program;
mod dump;
mod checksum;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::rom_chip::RomChip;
@@ -11,37 +12,15 @@ use std::io::Read;
/// At28C256
///
/// Represents a single At28C256 Chip
/// Represents a single At28C256 EEPROM Chip
///
/// 256kbit storage
/// 32kbyte storage
pub struct At28C256 {
data_bus: u8,
address_bus: u16,
data: Box<[u8; SIZE_32KB]>,
data: Box<[u8]>,
// where in the computer memory map do we live?
offset: u16
}
#[cfg(test)]
mod test {
use super::*;
use crate::constants::constants_system::SIZE_1KB;
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn programmed_data_reads_back_same() {
let mut data = At28C256::default();
for i in 0..SIZE_32KB {
data.data[i] = 0xea;
}
for offset in 0..SIZE_32KB {
if offset.is_multiple_of(SIZE_1KB) {};
assert_eq!(0xea, data.read(&(offset as u16)));
}
}
offset: u16,
max_offset: u16
}
+6 -3
View File
@@ -2,12 +2,15 @@ use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn new(offset: u16, data: &[u8; SIZE_32KB]) -> Self {
pub fn new(offset: u16, max_offset: u16, data: Vec<u8>) -> Self {
println!("NEW At28C256 with checksum ${:02x}", At28C256::checksum_static(&data[..]));
At28C256 {
data: (*data).into(),
data: data.into_boxed_slice(),
address_bus: 0x0000,
data_bus: 0x00,
offset
offset,
max_offset
}
}
}
+44 -18
View File
@@ -3,40 +3,66 @@ use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl At28C256 {
fn max_address(&self) -> u16 {
self.offset + SIZE_32KB as u16
fn talking_to_me(&self, address: u16) -> bool {
address >= self.offset && address < self.max_offset
}
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
if address_bus.gt(&self.offset) & address_bus.lt(&self.max_address()) {
if read_mode {
panic!("UNABLE TO WRITE TO ROM");
} else {
// has to be read mode. its a rom.
return (address_bus, data_bus)
}
println!("At28C256: Tick starting for A${address_bus:04x} D${data_bus:02x} R{read_mode}");
// we aren't being addressed
// OR
// we arent reading from the ROM...
if !self.talking_to_me(address_bus) ||
!read_mode {
// ...go away.
return (address_bus, data_bus)
}
// not for us.
(address_bus, self.data[address_bus as usize])
let effective = address_bus - self.offset;
if effective < self.max_offset {
if effective < self.data.len() as u16 {
self.data_bus = self.data[effective as usize];
} else {
self.data_bus = 0x00;
}
} else {
println!("At28C256: OUTSIDE RANGE. :(");
return (address_bus, data_bus)
}
println!("At28C256: Read... {:02x}", self.data_bus);
println!("At28C256: Done with ticking the AtC256");
(address_bus, self.data_bus)
}
}
#[cfg(test)]
mod test {
use std::fs;
use crate::periph::rom_chip::RomChip;
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn write_to_memory_read_back_works_at_0() {
let mut rom = At28C256::default();
fn checksum_binary_loads() {
let path = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin";
let bytes = match fs::read(path) {
Ok(bytes) => {
println!("Read {} bytes.", bytes.len());
bytes
},
Err(e) => {
eprintln!("FAIL to read rom.");
panic!("No rom no run.");
vec![]
}
};
rom.tick(0x0000, 0xab, false);
let (_, new_data) = rom.tick(0x0000, 0x00, true);
let mut rom = At28C256::new(0x0000, 0x3fff, bytes);
assert_eq!(new_data, 0xab);
assert_eq!(rom.checksum(), 0x58);
}
}
+9
View File
@@ -0,0 +1,9 @@
pub trait Backplane {
fn data_bus(&self) -> u8;
fn address_bus(&self) -> u16;
fn read_mode(&self) -> bool;
fn set_read_mode(&mut self, new_mode: bool);
fn set_data_bus(&mut self, new_value: u8);
fn set_address_bus(&mut self, new_value: u16);
fn tick(&mut self);
}
+1 -2
View File
@@ -7,12 +7,11 @@ impl Hm62256 {
}
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) {
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
if !(address_bus.gt( &self.offset) && address_bus.le(&self.max_address())) {
return (address_bus, data_bus);
}
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
self.address_bus = address_bus;
self.data_bus = data_bus;
let addr = address_bus.wrapping_sub(self.offset) + self.offset;
+1
View File
@@ -6,3 +6,4 @@ pub mod mos6522;
pub mod mos6530;
pub mod kim1_keypad;
mod bus_device;
pub mod backplane;
+20 -16
View File
@@ -46,6 +46,10 @@ pub struct Mos6522 {
}
impl Mos6522 {
pub fn max_offset(&self) -> u16 {
self.offset + 0x10
}
pub fn start_clocks(&mut self) {
loop {
let cycle_start = Instant::now();
@@ -66,40 +70,40 @@ mod test {
#[test]
fn registers() {
let mut x = Mos6522::new();
x.tick(0b0000_0000, VIA6522_DDRA, false, true);
x.tick(VIA6522_DDRA as u16, 0b0000_0000, false, true);
assert_eq!(x.dda, 0b0000_0000);
x.tick(0b1111_1111, VIA6522_DDRA, false, true);
x.tick(VIA6522_DDRA as u16, 0b1111_1111, false, true);
assert_eq!(x.dda, 0b1111_1111);
x.tick(0b0000_0000, VIA6522_DDRB, false, true);
x.tick(VIA6522_DDRB as u16, 0b0000_0000, false, true);
assert_eq!(x.ddb, 0b0000_0000);
x.tick(0b1111_1111, VIA6522_DDRB, false, true);
x.tick(VIA6522_DDRB as u16, 0b1111_1111, false, true);
assert_eq!(x.ddb, 0b1111_1111);
x.tick(0b0000_0000, VIA6522_ORA, false, true);
assert_eq!(x.porta, 0b0000_0000);
x.tick(0b1111_1111, VIA6522_ORA, false, true);
assert_eq!(x.porta, 0b1111_1111);
x.tick(VIA6522_ORA as u16, 0b0000_0000, false, true);
assert_eq!(x.ora, 0b0000_0000);
x.tick(VIA6522_ORA as u16, 0b1111_1111, false, true);
assert_eq!(x.ora, 0b1111_1111);
x.tick(0b0000_0000, VIA6522_ORB, false, true);
assert_eq!(x.portb, 0b0000_0000);
x.tick(0b1111_1111, VIA6522_ORB, false, true);
assert_eq!(x.portb, 0b1111_1111);
x.tick(VIA6522_ORB as u16, 0b0000_0000, false, true);
assert_eq!(x.orb, 0b0000_0000);
x.tick(VIA6522_ORB as u16, 0b1111_1111, false, true);
assert_eq!(x.orb, 0b1111_1111);
}
#[test]
fn partial_output_porta() {
let mut x = Mos6522::new();
x.tick(0b1010_1010, VIA6522_DDRA, false, true);
x.tick(0b1111_1111, VIA6522_ORA, false, true);
x.tick(VIA6522_DDRA as u16, 0b1010_1010, false, true);
x.tick(VIA6522_ORA as u16,0b1111_1111, false, true);
assert_eq!(x.porta, 0b1010_1010);
}
#[test]
fn partial_output_portb() {
let mut x = Mos6522::new();
x.tick(0b0101_0101, VIA6522_DDRB, false, true);
x.tick(0b1111_1111, VIA6522_ORB, false, true);
x.tick(VIA6522_DDRB as u16, 0b0101_0101, false, true);
x.tick(VIA6522_ORB as u16, 0b1111_1111, false, true);
assert_eq!(x.portb, 0b0101_0101);
}
}
+13 -10
View File
@@ -12,13 +12,13 @@ impl Mos6522 {
/// data_bus -> 8 bits from the data bus
/// control -> 4 bits to identify which register to control
pub fn tick(&mut self, address_bus: u16, data_bus: u8,reset: bool, rw: bool) -> (u16, u8) {
if !(address_bus.gt( &self.offset) && address_bus.le(&self.max_address())) {
if !(address_bus >= self.offset && address_bus.le(&self.max_address())) {
return (address_bus, data_bus);
}
let local_address = address_bus - self.offset;
println!("Mos6522 Tick Start -> D:0x{data_bus:02x} / A:0x{address_bus:02x} / {rw} (Actual 0x{local_address:02x}");
println!("Mos6522 Tick Start -> D:0x{data_bus:02x} / A:0x{address_bus:02x} / {rw} (Actual 0x{local_address:02x} / 0b{local_address:08b})");
if reset {
// reset process
println!("Resetting Mos6522");
@@ -35,25 +35,28 @@ impl Mos6522 {
self.data_bus = data_bus;
match local_address as u8 {
VIA6522_DDRA => {
debug!("Setting DDA to 0x{data_bus:02x}");
println!("Setting DDA to 0x{data_bus:02x}");
// setting the Data Direction for Port A
self.dda = data_bus;
},
VIA6522_DDRB => {
debug!("Setting DDB to 0x{data_bus:02x}");
// setting the data direction for port b
self.ddb = data_bus;
},
VIA6522_ORB => {
// writing data to ORB
let masked_data = data_bus & self.ddb;
debug!("Setting ORB to 0x{data_bus:02x} / masked at 0x{masked_data:02x}");
println!("Setting ORB to 0x{data_bus:02x} / masked at 0x{masked_data:02x}");
self.orb = data_bus;
self.portb = masked_data;
},
VIA6522_DDRB => {
println!("Setting DDB to 0x{data_bus:02x}");
// setting the data direction for port b
self.ddb = data_bus;
},
VIA6522_ORA => {
// writing data to ORA
let masked_data = data_bus & self.dda;
debug!("Setting ORA to 0x{data_bus:02x} / masked at 0x{masked_data:02x}");
println!("Setting ORA to 0x{data_bus:02x} / masked at 0x{masked_data:02x}");
self.ora = data_bus;
self.porta = masked_data;
},
_ => {}
+1 -2
View File
@@ -12,8 +12,6 @@ use crate::periph::mos6522::mos6522::Mos6522;
/// 64 bytes RAM
/// IO Ports (A, B)
/// Timer
///
/// SEE ALSO Mos6532
pub struct Mos6530 {
pub(crate) data: [u8; SIZE_1KB],
pub(crate) ram: [u8; 64],
@@ -30,3 +28,4 @@ pub struct Mos6530 {
pub(crate) ram_offset: u16,
pub(crate) rom_offset: u16
}