more stuff
This commit is contained in:
parent
2cfd570789
commit
cf14804df2
@ -11,12 +11,9 @@ async fn main() {
|
||||
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";
|
||||
let mut message_index = 0;
|
||||
|
||||
dm.push_letter('T');
|
||||
// dm.push_letter('T');
|
||||
let mut frame_number: u32 = 0x00;
|
||||
|
||||
loop {
|
||||
|
||||
26
beneater/src/bin/urn.rs
Normal file
26
beneater/src/bin/urn.rs
Normal 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();
|
||||
|
||||
}
|
||||
@ -3,11 +3,13 @@ use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
||||
use crate::parts::via6522::VIA6522;
|
||||
use core::constants::constants_system::*;
|
||||
use core::periph::at28c256::At28C256;
|
||||
use core::periph::rom_chip::RomChip;
|
||||
pub struct Backplane {
|
||||
cpu: Mos6502Cpu,
|
||||
via: VIA6522,
|
||||
memory: [u8; SIZE_64KB],
|
||||
rom: At28C256
|
||||
// pub for dev
|
||||
pub cpu: Mos6502Cpu,
|
||||
pub via: VIA6522,
|
||||
pub memory: Box<[u8; SIZE_64KB]>,
|
||||
pub rom: At28C256
|
||||
}
|
||||
|
||||
impl Backplane {
|
||||
@ -15,7 +17,7 @@ impl Backplane {
|
||||
Backplane {
|
||||
cpu: Mos6502Cpu::default(),
|
||||
via: VIA6522::default(),
|
||||
memory: [0x00; SIZE_64KB],
|
||||
memory: Box::new([0x00; SIZE_64KB]),
|
||||
rom: At28C256::default()
|
||||
}
|
||||
}
|
||||
@ -28,6 +30,17 @@ impl Backplane {
|
||||
// is the CPU in read or write state
|
||||
let address = self.cpu.address_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 {
|
||||
/// VIA
|
||||
0x6000..0x6010 => {
|
||||
@ -36,23 +49,25 @@ impl Backplane {
|
||||
} else {
|
||||
self.via.write((address - 0x6000) as u8, self.cpu.data_bus());
|
||||
}
|
||||
self.via.tick();
|
||||
}
|
||||
/// 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;
|
||||
self.memory[address as usize] = data;
|
||||
}
|
||||
}
|
||||
/// ROM
|
||||
0x4000..=0x7fff => {
|
||||
|
||||
self.rom.read(&(address - 0x4000));
|
||||
}
|
||||
/// The ether. Scarrrrrrrryyyy......
|
||||
_ => {
|
||||
println!("Lost READ:?{} to {:04x}", self.cpu.read_signal, address);
|
||||
}
|
||||
}
|
||||
println!("- TICK DONE");
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ use std::io::{BufReader, Read};
|
||||
use std::path::Path;
|
||||
use crate::parts::clock::Clock;
|
||||
use core::mos6502cpu::Mos6502Cpu;
|
||||
use core::constants::constants_system::*;
|
||||
|
||||
pub struct BenEaterPC {
|
||||
clock: Clock,
|
||||
@ -49,7 +50,11 @@ impl BenEaterPC {
|
||||
buffer.truncate(bytes_read);
|
||||
chunks.push(buffer[0]);
|
||||
}
|
||||
println!("Loaded {}b of data.", chunks.len());
|
||||
self.cpu.memory = chunks.into();
|
||||
let data_size = chunks.len();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use std::time::{Duration, Instant};
|
||||
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HD44780 {
|
||||
@ -31,6 +32,36 @@ pub struct HD44780 {
|
||||
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 {
|
||||
pub fn new() -> 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) {
|
||||
if self.rw {
|
||||
return;
|
||||
@ -157,7 +182,6 @@ impl HD44780 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -171,8 +195,7 @@ mod tests {
|
||||
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);
|
||||
pulse_enable(&mut lcd);
|
||||
lcd.tick();
|
||||
assert!(lcd.ddram.iter().all(|&b| b == b' '));
|
||||
}
|
||||
@ -181,8 +204,7 @@ mod tests {
|
||||
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);
|
||||
pulse_enable(&mut lcd);
|
||||
lcd.tick();
|
||||
assert_eq!(lcd.ddram[0], b'A');
|
||||
}
|
||||
@ -191,8 +213,7 @@ mod tests {
|
||||
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);
|
||||
pulse_enable(&mut lcd);
|
||||
lcd.tick();
|
||||
assert_eq!(lcd.cursor_position, 0x40);
|
||||
}
|
||||
@ -206,4 +227,47 @@ mod tests {
|
||||
let data = lcd.read_data_bus();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
pub trait Mos6522Peripheral {
|
||||
/// Write to the data bus
|
||||
fn write(&mut self, port: u8);
|
||||
fn control(&mut self, control: u8);
|
||||
/// Read the data bus
|
||||
fn read(&mut self) -> u8;
|
||||
|
||||
/// Tick
|
||||
///
|
||||
/// Run 1 clock cycle of the peripheral
|
||||
fn tick(&mut self);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::parts::display_matrix::HD44780;
|
||||
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
||||
|
||||
use core::constants::constants_system::*;
|
||||
#[derive(Default)]
|
||||
pub struct VIA6522 {
|
||||
// Data registers
|
||||
ora: u8,
|
||||
@ -52,16 +53,17 @@ impl VIA6522 {
|
||||
t2_enabled: false,
|
||||
ifr: 0,
|
||||
ier: 0,
|
||||
lcd: Some(HD44780::new().into()),
|
||||
lcd: Some(Box::new(HD44780::new())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn read(&self, addr: u8) -> u8 {
|
||||
match addr & 0x0F {
|
||||
0x0 => self.orb,
|
||||
0x1 => self.ora,
|
||||
0x2 => self.ddrb,
|
||||
0x3 => self.ddra,
|
||||
match (addr & 0x0F) {
|
||||
VIA6522_ORB => self.orb,
|
||||
VIA6522_ORA => self.ora,
|
||||
VIA6522_DDRB => self.ddrb,
|
||||
VIA6522_DDRA => self.ddra,
|
||||
0x4 => (self.t1_counter & 0xFF) as u8,
|
||||
0x5 => (self.t1_counter >> 8) as u8,
|
||||
0x6 => (self.t1_latch & 0xFF) as u8,
|
||||
@ -75,11 +77,12 @@ impl VIA6522 {
|
||||
}
|
||||
|
||||
pub fn write(&mut self, addr: u8, value: u8) {
|
||||
println!("VIA6522 write value 0x{value:02x} to address 0x{addr:02x}");
|
||||
match addr & 0x0F {
|
||||
0x0 => self.orb = value,
|
||||
0x1 => self.ora = value,
|
||||
0x2 => self.ddrb = value,
|
||||
0x3 => self.ddra = value,
|
||||
VIA6522_ORB => self.orb = value,
|
||||
VIA6522_ORA => self.ora = value,
|
||||
VIA6522_DDRB => self.ddrb = value,
|
||||
VIA6522_DDRA => self.ddra = value,
|
||||
0x4 => {
|
||||
self.t1_latch = (self.t1_latch & 0xFF00) | value as u16;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,4 +3,10 @@ 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;
|
||||
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;
|
||||
|
||||
@ -21,7 +21,7 @@ pub struct Mos6502Cpu {
|
||||
/// cpu flags
|
||||
flags: Mos6502Flags,
|
||||
/// program counter
|
||||
pc: u16,
|
||||
pub pc: u16,
|
||||
/// stack offset
|
||||
s: 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 0xfffe 0xffff for our int 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);
|
||||
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 {
|
||||
println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
|
||||
let low = self.memory[*offset as usize];
|
||||
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 {
|
||||
@ -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());
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
(self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
mod default;
|
||||
mod rom_chip;
|
||||
|
||||
use std::io::Read;
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
use crate::periph::rom_chip::RomChip;
|
||||
|
||||
@ -15,8 +16,10 @@ pub struct At28C256 {
|
||||
}
|
||||
|
||||
impl At28C256 {
|
||||
pub fn program(&mut self, new_program: &[u8; 32768]) {
|
||||
self.data= new_program.into();
|
||||
pub fn program(&mut self, new_program: &[u8; SIZE_32KB]) {
|
||||
// panic!("FAIL. Cant program the chip.");
|
||||
// println!("PROGRAMMING {:?}", new_program);
|
||||
self.data = Box::new(*new_program);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user