writes bins better now
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
/// BenEater computer represents the 'Ben Eater' 6502 breadboard computer.
|
||||
/// This was built along watching the video series where Ben builds a
|
||||
/// 6502 on a breadboard and explains each step.
|
||||
///
|
||||
pub struct BenEater {}
|
||||
|
||||
@@ -3,7 +3,9 @@ use crate::periph::hm62256::Hm62256;
|
||||
use crate::periph::rom_chip::RomChip;
|
||||
|
||||
pub struct Backplane {
|
||||
rom: Hm62256
|
||||
rom: Hm62256,
|
||||
data_bus: u8,
|
||||
address_bus: u16
|
||||
}
|
||||
|
||||
impl Backplane {
|
||||
@@ -13,7 +15,9 @@ impl Backplane {
|
||||
|
||||
pub fn program(rom: &[u8; SIZE_32KB]) -> Backplane {
|
||||
Backplane {
|
||||
rom: *Hm62256::program(rom)
|
||||
rom: *Hm62256::program(rom),
|
||||
address_bus: 0x0000,
|
||||
data_bus: 0x00
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,3 @@ pub const SIZE_64KB: usize = SIZE_1KB * 64;
|
||||
pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
|
||||
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;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
pub const VIA6522_ORB: u8 = 0b0000;
|
||||
pub const VIA6522_ORA: u8 = 0b0001;
|
||||
pub const VIA6522_DDRB: u8 = 0b0010;
|
||||
pub const VIA6522_DDRA: u8 = 0b0011;
|
||||
|
||||
/// Timer 1 Write Latch
|
||||
pub const VIA6522_T1WL: u8 = 0b0100;
|
||||
/// Timer 1 Read Counter High
|
||||
pub const VIA6522_T1CL: u8 = 0b0101;
|
||||
pub const VIA6522_T1CH: u8 = 0b0110;
|
||||
pub const VIA6522_T1LL: u8 = 0b0111;
|
||||
pub const VIA6522_T1LH: u8 = 0b1000;
|
||||
pub const VIA6522_T2LL: u8 = 0b1001;
|
||||
pub const VIA6522_T2CH: u8 = 0b1010;
|
||||
pub const VIA6522_SR: u8 = 0b1011;
|
||||
pub const VIA6522_ACR: u8 = 0b1100;
|
||||
pub const VIA6522_PCR: u8 = 0b1101;
|
||||
pub const VIA6522_IFR: u8 = 0b1110;
|
||||
pub const VIA6522_IER: u8 = 0b1111;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod constants_isa_op;
|
||||
pub mod constants_isa_stub;
|
||||
pub mod constants_system;
|
||||
pub mod constants_via6522;
|
||||
|
||||
@@ -31,11 +31,11 @@ use crate::op_info::OpInfo;
|
||||
use crate::operation::Operation;
|
||||
use crate::operation::Operation::*;
|
||||
|
||||
pub fn INSTRUCTION_CYCLES(instruction: u8) -> u8 {
|
||||
pub fn instruction_cycles(instruction: u8) -> u8 {
|
||||
INSTRUCTION_TABLE[instruction as usize].unwrap().cycles
|
||||
}
|
||||
|
||||
pub fn INSTRUCTION_LENGTH(instruction: u8) -> u8 {
|
||||
pub fn instruction_length(instruction: u8) -> u8 {
|
||||
INSTRUCTION_TABLE[instruction as usize].unwrap().length
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -483,7 +483,7 @@ impl Mos6502Cpu {
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::constants::constants_isa_op::*;
|
||||
use crate::instruction_table::{INSTRUCTION_CYCLES, INSTRUCTION_TABLE};
|
||||
use crate::instruction_table::{instruction_cycles, INSTRUCTION_TABLE};
|
||||
|
||||
#[test]
|
||||
fn clc() {
|
||||
@@ -496,7 +496,7 @@ mod test {
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
// Tick the CPU through the instruction
|
||||
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_CLC) {
|
||||
for _ in 0..instruction_cycles(ISA_OP_CLC) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ mod test {
|
||||
cpu.memory[0x6000] = ISA_OP_CLD;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_CLD) {
|
||||
for _ in 0..instruction_cycles(ISA_OP_CLD) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ mod test {
|
||||
cpu.memory[0x6000] = ISA_OP_CLI;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLI) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_CLI) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ mod test {
|
||||
cpu.memory[0x6000] = ISA_OP_CLV;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLV) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_CLV) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ mod test {
|
||||
cpu.memory[0x6001] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_I) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_LDA_I) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ mod test {
|
||||
cpu.memory[0x00ac] = 0xbe;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ZX) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_LDA_ZX) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ mod test {
|
||||
cpu.memory[0x00ab] = 0xbe;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_LDA_Z) {
|
||||
for _ in 0..instruction_cycles(ISA_OP_LDA_Z) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -605,7 +605,7 @@ mod test {
|
||||
cpu.memory[0x0eef] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_LDA_ABS) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -622,7 +622,7 @@ mod test {
|
||||
cpu.memory[0x0ef0] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSX) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_LDA_ABSX) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ mod test {
|
||||
cpu.memory[0x0ef0] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSY) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_LDA_ABSY) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
@@ -654,11 +654,11 @@ mod test {
|
||||
cpu.memory[0x6001] = ISA_OP_INX;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEX) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_DEX) {
|
||||
cpu.tick();
|
||||
}
|
||||
assert_eq!(0xaa, cpu.x);
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INX) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_INX) {
|
||||
cpu.tick();
|
||||
}
|
||||
assert_eq!(0xab, cpu.x);
|
||||
@@ -672,11 +672,11 @@ mod test {
|
||||
cpu.memory[0x6001] = ISA_OP_INY;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEY) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_DEY) {
|
||||
cpu.tick();
|
||||
}
|
||||
assert_eq!(0xaa, cpu.peek_y());
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INY) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_INY) {
|
||||
cpu.tick();
|
||||
}
|
||||
assert_eq!(0xab, cpu.peek_y());
|
||||
@@ -690,11 +690,11 @@ mod test {
|
||||
cpu.memory[0x6001] = ISA_OP_ROR_A;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROL_A) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_ROL_A) {
|
||||
cpu.tick();
|
||||
}
|
||||
assert_eq!(cpu.peek_a(), 0b0101_0101);
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROR_A) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_ROR_A) {
|
||||
cpu.tick();
|
||||
}
|
||||
assert_eq!(cpu.peek_a(), 0b1010_1010);
|
||||
@@ -708,7 +708,7 @@ mod test {
|
||||
cpu.memory[0x6001] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROL_ZP) {
|
||||
for _ in 0..=instruction_cycles(ISA_OP_ROL_ZP) {
|
||||
cpu.tick();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod default;
|
||||
pub mod rom_chip;
|
||||
pub mod tick;
|
||||
mod new;
|
||||
mod program;
|
||||
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
use crate::periph::rom_chip::RomChip;
|
||||
@@ -16,14 +18,6 @@ pub struct At28C256 {
|
||||
data: Box<[u8; SIZE_32KB]>,
|
||||
}
|
||||
|
||||
impl At28C256 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
use crate::periph::at28c256::At28C256;
|
||||
|
||||
impl At28C256 {
|
||||
pub fn new(data: &[u8; SIZE_32KB]) -> Self {
|
||||
At28C256 {
|
||||
data: (*data).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
use crate::periph::at28c256::At28C256;
|
||||
|
||||
impl At28C256 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,10 @@ use crate::periph::hm62256::Hm62256;
|
||||
|
||||
impl At28C256 {
|
||||
fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
|
||||
if !read_mode {
|
||||
// has to be read mode. its a rom.
|
||||
if read_mode {
|
||||
panic!("UNABLE TO WRITE TO ROM");
|
||||
} else {
|
||||
// has to be read mode. its a rom.
|
||||
return (address_bus, data_bus)
|
||||
}
|
||||
(address_bus, self.data[address_bus as usize])
|
||||
|
||||
@@ -25,7 +25,9 @@ mod 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);
|
||||
// read the data back
|
||||
let (_, new_data) = ram.tick(0x0000, 0x00, true);
|
||||
|
||||
assert_eq!(new_data, 0xab);
|
||||
|
||||
@@ -3,3 +3,4 @@ pub mod rom_chip;
|
||||
pub mod at28c256;
|
||||
pub mod hm62256;
|
||||
pub mod ram_chip;
|
||||
pub mod mos6522;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod mos6522;
|
||||
mod registers;
|
||||
@@ -0,0 +1,165 @@
|
||||
use std::time::Instant;
|
||||
use log::debug;
|
||||
use crate::constants::constants_via6522::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Mos6522 {
|
||||
/// data direction
|
||||
dda: u8,
|
||||
ddb: u8,
|
||||
|
||||
/// bottom 4 address bits
|
||||
rs0: u8,
|
||||
rs1: u8,
|
||||
rs2: u8,
|
||||
rs3: u8,
|
||||
|
||||
/// external data bus
|
||||
data_bus: u8,
|
||||
|
||||
cs1: bool,
|
||||
cs2: bool,
|
||||
rw: bool,
|
||||
|
||||
/// reset circuit - true when reset inited
|
||||
reset: bool,
|
||||
|
||||
/// IRQ - true when interrupt waiting
|
||||
irq: bool,
|
||||
|
||||
ira: u8,
|
||||
ora: u8,
|
||||
porta: u8,
|
||||
irb: u8,
|
||||
orb: u8,
|
||||
portb: u8,
|
||||
|
||||
ca1: bool,
|
||||
ca2: bool,
|
||||
cb1: bool,
|
||||
cb2: bool,
|
||||
}
|
||||
|
||||
impl Mos6522 {
|
||||
pub fn new() -> Self {
|
||||
Mos6522::default()
|
||||
}
|
||||
|
||||
/// tick
|
||||
///
|
||||
/// data_bus -> 8 bits from the data bus
|
||||
/// control -> 4 bits to identify which register to control
|
||||
pub fn tick(&mut self, data_bus: u8, control: u8, rw: bool) -> (u8) {
|
||||
println!("Mos6522 Tick Start -> 0x{data_bus:02x} / 0x{control:02x} / {rw}");
|
||||
if rw {
|
||||
// RW true = CPU is writing
|
||||
self.data_bus = data_bus;
|
||||
match control {
|
||||
VIA6522_DDRA => {
|
||||
debug!("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}");
|
||||
self.portb = masked_data;
|
||||
},
|
||||
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}");
|
||||
self.porta = masked_data;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
// RW false = CPU is reading
|
||||
self.data_bus = match control {
|
||||
VIA6522_DDRA => {
|
||||
self.dda
|
||||
}
|
||||
VIA6522_DDRB => {
|
||||
self.ddb
|
||||
}
|
||||
VIA6522_ORA => {
|
||||
self.porta & self.dda
|
||||
}
|
||||
VIA6522_ORB => {
|
||||
self.portb & self.ddb
|
||||
}
|
||||
_ => {
|
||||
debug!("VIA got request for b{:08b} / 0x{:02x}", control, control);
|
||||
// do nothing. bad address for VIA
|
||||
self.data_bus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(self.data_bus)
|
||||
}
|
||||
|
||||
pub fn start_clocks(&mut self) {
|
||||
loop {
|
||||
let cycle_start = Instant::now();
|
||||
// let duration = cycle_start.duration_since(self.clock);
|
||||
// set the time to the new time.
|
||||
// self.clock = cycle_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true); }
|
||||
|
||||
#[test]
|
||||
fn registers() {
|
||||
let mut x = Mos6522::new();
|
||||
x.tick(0b0000_0000, VIA6522_DDRA, true);
|
||||
assert_eq!(x.dda, 0b0000_0000);
|
||||
x.tick(0b1111_1111, VIA6522_DDRA, true);
|
||||
assert_eq!(x.dda, 0b1111_1111);
|
||||
|
||||
x.tick(0b0000_0000, VIA6522_DDRB, true);
|
||||
assert_eq!(x.ddb, 0b0000_0000);
|
||||
x.tick(0b1111_1111, VIA6522_DDRB, true);
|
||||
assert_eq!(x.ddb, 0b1111_1111);
|
||||
|
||||
x.tick(0b0000_0000, VIA6522_ORA, true);
|
||||
assert_eq!(x.porta, 0b0000_0000);
|
||||
x.tick(0b1111_1111, VIA6522_ORA, true);
|
||||
assert_eq!(x.porta, 0b1111_1111);
|
||||
|
||||
x.tick(0b0000_0000, VIA6522_ORB, true);
|
||||
assert_eq!(x.portb, 0b0000_0000);
|
||||
x.tick(0b1111_1111, VIA6522_ORB, true);
|
||||
assert_eq!(x.portb, 0b1111_1111);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_output_porta() {
|
||||
let mut x = Mos6522::new();
|
||||
x.tick(0b1010_1010, VIA6522_DDRA, true);
|
||||
x.tick(0b1111_1111, VIA6522_ORA, true);
|
||||
assert_eq!(x.porta, 0b1010_1010);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_output_portb() {
|
||||
let mut x = Mos6522::new();
|
||||
x.tick(0b0101_0101, VIA6522_DDRB, true);
|
||||
x.tick(0b1111_1111, VIA6522_ORB, true);
|
||||
assert_eq!(x.portb, 0b0101_0101);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
pub enum Via6522Registers {
|
||||
ORA,
|
||||
ORB,
|
||||
DDRA,
|
||||
DDRB,
|
||||
T1WL,
|
||||
T1CL,
|
||||
T1CH,
|
||||
T1LL,
|
||||
T2LL,
|
||||
T2CH,
|
||||
}
|
||||
Reference in New Issue
Block a user