more chips
more docs
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
#[test]
|
||||
fn test() {
|
||||
assert!(true);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mod periph;
|
||||
mod mos6502;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
@@ -0,0 +1,18 @@
|
||||
use core::mos6502flags::Mos6502Flags;
|
||||
|
||||
#[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));
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
#[test]
|
||||
fn test_instruction_table_completeness() {
|
||||
use core::instruction_table::INSTRUCTION_TABLE; // Adjust to your actual path
|
||||
|
||||
let mut defined_count = 0;
|
||||
let mut defined_opcodes = vec![];
|
||||
|
||||
for (i, entry) in INSTRUCTION_TABLE.iter().enumerate() {
|
||||
if let Some(info) = entry {
|
||||
defined_count += 1;
|
||||
defined_opcodes.push(i);
|
||||
// Optional: sanity check
|
||||
assert!(
|
||||
info.length > 0 && info.cycles > 0,
|
||||
"Invalid OpInfo at opcode {:#04x?}",
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
println!("Defined opcodes: {}", defined_count);
|
||||
for i in 0..256 {
|
||||
if defined_opcodes.contains(&i) {
|
||||
print!("{:02x} ", i);
|
||||
}
|
||||
}
|
||||
println!("\nMissing opcodes:");
|
||||
for i in 0..256 {
|
||||
if !defined_opcodes.contains(&i) {
|
||||
print!("{:02x} ", i);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
|
||||
// The standard 6502 has 151 documented opcodes
|
||||
assert_eq!(
|
||||
defined_count, 151,
|
||||
"Expected 151 opcodes, found {}",
|
||||
defined_count
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
mod flags;
|
||||
mod instructions;
|
||||
mod instruction_table;
|
||||
@@ -0,0 +1,153 @@
|
||||
use core::constants::constants_system::*;
|
||||
use core::constants::constants_test::*;
|
||||
use core::periph::at28c256::At28C256;
|
||||
use core::traits::bus_device::BusDevice;
|
||||
use core::traits::memory_chip::MemoryChip;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checksum_binary_loads() {
|
||||
let path = format!("{}/{}", TEST_PERIPH_AT28C256_ROOT, "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.");
|
||||
}
|
||||
};
|
||||
|
||||
let mut rom = At28C256::new(0x0000, 0x3fff, bytes);
|
||||
|
||||
assert_eq!(rom.checksum(), 0x58);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_chunks_come_back_ok() {
|
||||
let test_data = (0..255).collect();
|
||||
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
|
||||
|
||||
let chunks = chip.chunks(16);
|
||||
assert_eq!(chunks.len(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_blocks_come_back_ok() {
|
||||
let test_data = (0..=3).collect();
|
||||
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
|
||||
|
||||
let chunks = chip.chunks(16);
|
||||
assert_eq!(chunks.len(), 1);
|
||||
for chunk in chunks {
|
||||
assert_eq!(chunk.len(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[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 - 1) {
|
||||
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");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn address_data_set_reads() {
|
||||
let mut x = At28C256::new(0x0000, 0x3fff, vec![0xea; SIZE_32KB]);
|
||||
|
||||
// set both...
|
||||
x.set_address_bus(0x3000);
|
||||
x.set_data_bus(0xab);
|
||||
assert_eq!(0xab, x.data_bus());
|
||||
assert_eq!(0x3000, x.address_bus());
|
||||
|
||||
// ...set address...
|
||||
x.set_address_bus(0x2000);
|
||||
assert_eq!(0x2000, x.address_bus());
|
||||
assert_eq!(0xab, x.data_bus());
|
||||
|
||||
// ...set data.
|
||||
x.set_data_bus(0xba);
|
||||
assert_eq!(0xba, x.data_bus());
|
||||
assert_eq!(0x2000, x.address_bus());
|
||||
}
|
||||
|
||||
fn programming_chip_changes_contents() {
|
||||
let mut chip = At28C256::new(0x0000, 0x3fff, vec![]);
|
||||
|
||||
assert_eq!(0x00, chip.read(&0x0000));
|
||||
|
||||
let new_data: Vec<u8> = vec![0xff, 0xff, 0xff, 0xff];
|
||||
chip.program(new_data.into());
|
||||
assert_eq!(0xff, chip.read(&0x0000));
|
||||
assert_eq!(0x00, chip.read(&0x05));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn correct_flags_required() {
|
||||
let mut chip = At28C256::new(0x0000, 0x3fff, vec![0xff]);
|
||||
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, false, true, true));
|
||||
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, true, true, false));
|
||||
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, false, true, false));
|
||||
assert_eq!(0xff, chip.signal_tick(0x0000, 0xab, true, true, true));
|
||||
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, true, false, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loaded_rom_is_readable() {
|
||||
let mut chip = At28C256::new(0x0000, 0x3fff, [0xff; SIZE_32KB].to_vec());
|
||||
|
||||
for index in 0..SIZE_32KB {
|
||||
assert_eq!(chip.data[index as usize], 0xff);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
use core::constants::constants_system::*;
|
||||
use rand::random;
|
||||
use core::traits::memory_chip::MemoryChip;
|
||||
use core::periph::hm62256::Hm62256;
|
||||
use core::traits::ram_chip::RamChip;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn written_data_comes_back() {
|
||||
let mut ram = Hm62256::default();
|
||||
|
||||
// 100,000 random read/writes to ram that all read back right
|
||||
for _ in 0..100_000 {
|
||||
let mut offset: u16 = random();
|
||||
println!("Size = {SIZE_32KB}");
|
||||
let value: u8 = random();
|
||||
println!("Wrote [{value:02x}] to [{offset:04x}]");
|
||||
ram.write(&offset, &value);
|
||||
|
||||
assert_eq!(ram.read(&offset), value)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_to_memory_read_back_works_at_0() {
|
||||
let mut ram = Hm62256::default();
|
||||
|
||||
// load the data to ram
|
||||
ram.tick(0x0000, 0xab, false, true);
|
||||
// read the data back
|
||||
let (_, new_data) = ram.tick(0x0000, 0x00, true, true);
|
||||
|
||||
assert_eq!(new_data, 0xab);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn address_space_is_round() {
|
||||
// addresses written past the last address 'loop' back to 0+(offset - MAX_SIZE)
|
||||
let max_offset = SIZE_32KB;
|
||||
let test_offset = max_offset;
|
||||
|
||||
// all zero
|
||||
let mut ram = Hm62256::default();
|
||||
// write FF to the addresss after the last
|
||||
ram.write(&(test_offset as u16), &0xff);
|
||||
|
||||
// check all the ram for anything that isn't 0x00
|
||||
|
||||
assert_eq!(ram.read(&(0x0000)), 0xff);
|
||||
for offset in 1..SIZE_32KB {
|
||||
println!("Testing offset {offset:04x} for 0x00");
|
||||
assert_eq!(ram.read(&(offset as u16)), 0x00);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
use core::periph::kim1_keypad::Kim1Keypad;
|
||||
|
||||
#[test]
|
||||
fn keys_are_pressed() {
|
||||
let mut kb = Kim1Keypad::new();
|
||||
|
||||
for index in 0..23 {
|
||||
assert!(!kb.is_pressed(index));
|
||||
kb.press_key(index);
|
||||
assert!(kb.is_pressed(index));
|
||||
|
||||
kb.release_key(index);
|
||||
assert!(!kb.is_pressed(index));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stepping_changes() {
|
||||
let mut kb = Kim1Keypad::new();
|
||||
|
||||
kb.set_stepping(false);
|
||||
|
||||
assert!(!kb.stepping);
|
||||
|
||||
kb.toggle_stepping();
|
||||
|
||||
assert!(kb.stepping);
|
||||
|
||||
kb.toggle_stepping();
|
||||
kb.toggle_stepping();
|
||||
kb.toggle_stepping();
|
||||
kb.toggle_stepping();
|
||||
kb.toggle_stepping();
|
||||
|
||||
assert!(!kb.stepping);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_range() {
|
||||
let mut kb = Kim1Keypad::new();
|
||||
|
||||
kb.press_key(24);
|
||||
assert!(kb.is_pressed(1));
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mod at28c256;
|
||||
mod mos6522;
|
||||
mod mos6520;
|
||||
mod kim1_keypad;
|
||||
mod hm62256;
|
||||
@@ -0,0 +1,56 @@
|
||||
use core::periph::mos6520::Mos6520;
|
||||
|
||||
const DDRA_OFFSET: u8 = 0x00;
|
||||
const PORTA_OFFSET: u8 = 0x01;
|
||||
const DDRB_OFFSET: u8 = 0x02;
|
||||
const PORTB_OFFSET: u8 = 0x03;
|
||||
|
||||
fn actual(base: u16, offset: u8) -> u16 {
|
||||
base + offset as u16
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ddrb_tests() {
|
||||
let mut x = Mos6520::new(0x1000);
|
||||
let params = vec![
|
||||
// Offset data outa ina ddra porta
|
||||
(DDRB_OFFSET, 0xff, 0x00, 0x00, 0xff, 0x00),
|
||||
(PORTB_OFFSET, 0xff, 0xff, 0x00, 0xff, 0xff),
|
||||
(DDRB_OFFSET, 0xaa, 0xaa, 0x55, 0xaa, 0xff),
|
||||
(DDRB_OFFSET, 0x55, 0x55, 0xaa, 0x55, 0xff),
|
||||
(PORTB_OFFSET, 0xf0, 0x50, 0xa0, 0x55, 0xf0),
|
||||
(PORTB_OFFSET, 0x0f, 0x05, 0x0a, 0x55, 0x0f),
|
||||
(DDRB_OFFSET, 0xff, 0x0f, 0x00, 0xff, 0x0f)
|
||||
];
|
||||
|
||||
for (offset, data, outb, inb, ddrb, portb) in params {
|
||||
x.tick(actual(x.offset, offset), data);
|
||||
assert_eq!(outb, x.out_b);
|
||||
assert_eq!(inb, x.in_b);
|
||||
assert_eq!(ddrb, x.ddrb);
|
||||
assert_eq!(portb, x.port_b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ddra_tests() {
|
||||
let mut x = Mos6520::new(0x1000);
|
||||
let params = vec![
|
||||
// Offset data outa ina ddra porta
|
||||
(DDRA_OFFSET, 0xff, 0x00, 0x00, 0xff, 0x00),
|
||||
(PORTA_OFFSET, 0xff, 0xff, 0x00, 0xff, 0xff),
|
||||
(DDRA_OFFSET, 0xaa, 0xaa, 0x55, 0xaa, 0xff),
|
||||
(DDRA_OFFSET, 0x55, 0x55, 0xaa, 0x55, 0xff),
|
||||
(PORTA_OFFSET, 0xf0, 0x50, 0xa0, 0x55, 0xf0),
|
||||
(PORTA_OFFSET, 0x0f, 0x05, 0x0a, 0x55, 0x0f),
|
||||
(DDRA_OFFSET, 0xff, 0x0f, 0x00, 0xff, 0x0f)
|
||||
];
|
||||
|
||||
for (offset, data, outa, ina, ddra, porta) in params {
|
||||
x.tick(actual(x.offset, offset), data);
|
||||
assert_eq!(outa, x.out_a);
|
||||
assert_eq!(ina, x.in_a);
|
||||
assert_eq!(ddra, x.ddra);
|
||||
assert_eq!(porta, x.port_a);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
use core::periph::mos6522::Mos6522;
|
||||
use core::constants::constants_via6522::*;
|
||||
|
||||
#[test]
|
||||
fn registers() {
|
||||
let mut x = Mos6522::new(0x0000);
|
||||
x.tick(VIA6522_DDRA as u16, 0b0000_0000, false, true);
|
||||
assert_eq!(x.dda, 0b0000_0000);
|
||||
x.tick(VIA6522_DDRA as u16, 0b1111_1111, false, true);
|
||||
assert_eq!(x.dda, 0b1111_1111);
|
||||
|
||||
x.tick(VIA6522_DDRB as u16, 0b0000_0000, false, true);
|
||||
assert_eq!(x.ddb, 0b0000_0000);
|
||||
x.tick(VIA6522_DDRB as u16, 0b1111_1111, false, true);
|
||||
assert_eq!(x.ddb, 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(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(0x0000);
|
||||
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(0x0000);
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user