diff --git a/beneater/src/bin/beneater.rs b/beneater/src/bin/beneater.rs index 09b86c4..da15e06 100644 --- a/beneater/src/bin/beneater.rs +++ b/beneater/src/bin/beneater.rs @@ -3,13 +3,14 @@ use beneater::parts::cpu_display::CpuDisplay; use macroquad::prelude::*; use macroquad::telemetry::frame; use beneater::parts::ben_eater_pc::BenEaterPC; -use beneater::parts::display_matrix::DisplayMatrix; +use beneater::parts::backplane::Backplane; #[macroquad::main("Ben Eaters PC")] async fn main() { println!("Taxation is Theft"); - let mut computer = BenEaterPC::new(); - computer.load_rom("resources/beneater/roms/ror.bin"); + 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"; @@ -23,7 +24,7 @@ async fn main() { draw_text("Ben Eater", 20.0, 20.0, 30.0, BLACK); dm.render(20.0, 40.0); - CpuDisplay::render(&computer.cpu, 20.0, 120.0); + // CpuDisplay::render(&computer.cpu, 20.0, 120.0); frame_number += 1; @@ -37,6 +38,5 @@ async fn main() { } next_frame().await - } } diff --git a/beneater/src/parts/backplane.rs b/beneater/src/parts/backplane.rs new file mode 100644 index 0000000..01ca2d4 --- /dev/null +++ b/beneater/src/parts/backplane.rs @@ -0,0 +1,58 @@ +use core::mos6502cpu::Mos6502Cpu; +use crate::parts::mos6522_peripheral::Mos6522Peripheral; +use crate::parts::via6522::VIA6522; +use core::constants::constants_system::*; +use core::periph::at28c256::At28C256; +pub struct Backplane { + cpu: Mos6502Cpu, + via: VIA6522, + memory: [u8; SIZE_64KB], + rom: At28C256 +} + +impl Backplane { + pub fn new() -> Self { + Backplane { + cpu: Mos6502Cpu::default(), + via: VIA6522::default(), + memory: [0x00; SIZE_64KB], + rom: At28C256::default() + } + } + + pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) { + self.rom.program(to_load); + } + + pub fn tick(&mut self) { + // is the CPU in read or write state + let address = self.cpu.address_bus(); + let data = self.cpu.data_bus(); + match address { + /// VIA + 0x6000..0x6010 => { + if self.cpu.read_signal { + self.cpu.set_data_bus(self.via.read((address - 0x6000) as u8)); + } else { + self.via.write((address - 0x6000) as u8, self.cpu.data_bus()); + } + } + /// 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; + } + } + /// ROM + 0x4000..=0x7fff => { + + } + /// The ether. Scarrrrrrrryyyy...... + _ => { + println!("Lost READ:?{} to {:04x}", self.cpu.read_signal, address); + } + } + } +} \ No newline at end of file diff --git a/beneater/src/parts/display_matrix.rs b/beneater/src/parts/display_matrix.rs index 672855e..ef4e8dd 100644 --- a/beneater/src/parts/display_matrix.rs +++ b/beneater/src/parts/display_matrix.rs @@ -1,197 +1,209 @@ -use macroquad::prelude::*; -use crate::parts::address_bus::AddressBus; -use crate::parts::data_bus::DataBus; -use crate::parts::display_matrix::MatrixEntryMode::{Delete, DeleteShift, Insert, InsertShift}; +use std::time::{Duration, Instant}; -pub enum MatrixEntryMode { - Delete, - DeleteShift, - Insert, - InsertShift, -} - -pub struct DisplayMatrix { - width: f32, - height: f32, - text_buffer: [u8; 80], - cgram: [u8; 64], - data_bus: DataBus, +#[derive(Debug)] +pub struct HD44780 { + // Bus inputs + data_bus: u8, rs: bool, rw: bool, + enable: bool, + prev_enable: bool, + + // Internal memory + ddram: [u8; 80], + cgram: [u8; 64], + + // Cursor & display state cursor_position: u8, - busy: bool, - entry_mode: MatrixEntryMode, - cursor: bool, display_on: bool, - blink: bool, - cursor_shift: bool, - display_shift: bool, - enabled: bool, + cursor_on: bool, + blink_on: bool, + entry_increment: bool, + entry_shift: bool, + + // Function set flags + data_length_8bit: bool, + two_line_mode: bool, + font_5x10: bool, + + // Busy flag + busy: bool, + last_command_time: Instant, } -impl DisplayMatrix { - pub fn set_bus(&mut self, rs: bool, rw: bool, bus: u8, e: bool) { - self.rs = rs; - self.rw = rw; - self.data_bus.data = bus; - self.enabled = e; - } - - /// Reset the Display to its 'factory boot' state - pub fn reset(&mut self) { - // 1. Display clear - self.set_bus(false, false, 0b0000_0001, true); - self.tick(false, false, true, 0b0000_0001); - // Function Set - // DL = 1; 8-bit interface data - // N = 0; 1-line display - // F = 0; 5 × 8 dot character font - self.tick(false, false, true, 0b0011_0000);; - // 3. Display on/off control: - // D = 0; Display off - // C = 0; Cursor off - // B = 0; Blinking off - self.tick(false, false, true, 0b0000_1000); - // 4. Entry mode set: - // I/D = 1; Increment by 1 - // S = 0; No shift - self.tick(false, false,true, 0b0000_0110); - self.busy = false; - } - - pub fn new(width: f32, height: f32) -> DisplayMatrix { - let mut matrix = DisplayMatrix { - width, - height, - text_buffer: String::from(""), - data_bus: DataBus::new(), +impl HD44780 { + pub fn new() -> Self { + Self { + data_bus: 0, rs: false, rw: false, - cursor_position: 0x00, - busy: false, - entry_mode: MatrixEntryMode::InsertShift, - display_on: false, - cursor: false, - blink: false, - cursor_shift: false, - display_shift: false, - enabled: false, - }; - matrix - } + enable: false, + prev_enable: false, - /// Tick - pub fn tick(&mut self, rw: bool, rs: bool, enabled: bool, data: u8) { - self.enabled = enabled; - self.data_bus.data = data; - self.rw = rw; - self.rs = rs; - // parse whats on the data bus. - match (self.rs, self.rw) { - (true, true) => { - // read from cg or ddram - } - (true, false) => { - // write to cg or ddram - println!("WRITE TO CG/DD RAM -> {:08b} / {:02x} / {}", self.data_bus.data, self.data_bus.data, self.data_bus.data); - } - (false, true) => { - // read the busy flag. - self.data_bus.data = (self.busy as u8) << 7 | (self.cursor_position & 0x7F); - self.enabled = true; - } - (false, false) => { - match self.data_bus.data { - 0b0000_0001 => { - // clear display - self.text_buffer = " ".repeat(32); - } - 0b0000_0010..=0b0000_0011 => { - // return home - self.cursor_position = 0x00; - } - 0b0000_0100..=0b0000_0111 => { - self.entry_mode = match self.data_bus.data { - 0b01 => DeleteShift, - 0b10 => Insert, - 0b11 => InsertShift, - _ => { - // Default mode - Delete - } - }; - } - 0b0000_1000..=0b0000_1111 => { - // display control - self.display_on = self.data_bus.data & 0b100 == 0b100; - self.cursor = self.data_bus.data & 0b10 == 0b10; - self.blink = self.data_bus.data & 0b1 == 0b1; - } - 0b0001_0000..=0b0001_1111 => { - // cursor control - self.cursor_shift = self.data_bus.data & 0b1000 == 0b1000; - self.display_shift = self.data_bus.data & 0b100 == 0b100; - } - 0b0010_0000..=0b0011_1111 => { - // function set - println!("Ignoring function set. this is going to play like an 8bit 2 row"); - } - 0b0100_0000..=0b0111_1111 => { - // set CGRam Address - println!("Ignoring set CGRam Address. Not Changing how the characters are displayed."); - } - 0b1000_0000..=0b1111_1111 => { - // set DDRam address - self.cursor_position = self.data_bus.data & 0b0111_1111; - } - _ => { - // Invalid Command - } - } - } + ddram: [b' '; 80], + cgram: [0; 64], + + cursor_position: 0, + display_on: true, + cursor_on: false, + blink_on: false, + entry_increment: true, + entry_shift: false, + + data_length_8bit: true, + two_line_mode: true, + font_5x10: false, + + busy: false, + last_command_time: Instant::now(), } } - pub fn push_letter(&mut self, letter_to_push: char) { - self.cursor_position += 1; - self.text_buffer.push(letter_to_push) + pub fn write_control_lines(&mut self, rs: bool, rw: bool, enable: bool) { + self.rs = rs; + self.rw = rw; + + // On rising edge of Enable + if enable && !self.prev_enable { + self.evaluate(); + } + + self.prev_enable = enable; } - pub fn clear_display(&mut self) { - self.cursor_position = 0; - self.text_buffer.clear() + pub fn set_data_bus(&mut self, value: u8) { + self.data_bus = value; } - pub fn render(&self, x_offset: f32, y_offset: f32) { - DisplayMatrix::draw_square(x_offset, - y_offset, - x_offset + self.width, - y_offset + self.height, - BLACK); - - let mut tmp = self.text_buffer.clone(); - tmp.push('#'); - draw_text(&*tmp, x_offset + 5.0, y_offset + 20.0, 20.0, BLACK); + pub fn read_data_bus(&self) -> u8 { + if !self.rs && self.rw { + // Return busy flag + current address + let busy_flag = if self.busy { 0x80 } else { 0x00 }; + busy_flag | (self.cursor_position & 0x7F) + } else { + // Not implemented: read from DDRAM/CGRAM + 0 + } } - fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) { - // println!("Square from {x1:2.0}x{y1:2.0} to {x2:2.0}x{y2:2.0} with {:?}", color); - draw_line(x1, y1, x2, y1, 1.0, color); - draw_line(x1, y1, x1, y2, 1.0, color); - draw_line(x1, y2, x2, y2, 1.0, color); - draw_line(x2, y1, x2, y2, 1.0, color); + 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; + } + + if self.rs { + self.write_data(self.data_bus); + } else { + self.execute_command(self.data_bus); + } + + self.busy = true; + self.last_command_time = Instant::now(); + } + + fn write_data(&mut self, data: u8) { + if self.cursor_position < 0x50 { + self.ddram[self.cursor_position as usize] = data; + self.cursor_position = self.cursor_position.wrapping_add(1); + } + } + + fn execute_command(&mut self, cmd: u8) { + match cmd { + 0x01 => { + self.ddram.fill(b' '); + self.cursor_position = 0; + } + 0x02 => { + self.cursor_position = 0; + } + 0x04..=0x07 => { + self.entry_increment = (cmd & 0b10) != 0; + self.entry_shift = (cmd & 0b01) != 0; + } + 0x08..=0x0F => { + self.display_on = (cmd & 0b100) != 0; + self.cursor_on = (cmd & 0b010) != 0; + self.blink_on = (cmd & 0b001) != 0; + } + 0x10..=0x1F => { + // Cursor/display shift — not yet implemented + } + 0x20..=0x3F => { + self.data_length_8bit = (cmd & 0b10000) != 0; + self.two_line_mode = (cmd & 0b1000) != 0; + self.font_5x10 = (cmd & 0b100) != 0; + } + 0x40..=0x7F => { + // Set CGRAM address — stub + } + 0x80..=0xFF => { + self.cursor_position = cmd & 0x7F; + } + _ => {} + } + } + + pub fn get_display_lines(&self) -> (String, String) { + let row1: String = self.ddram[0x00..0x10].iter().map(|&b| b as char).collect(); + let row2: String = self.ddram[0x40..0x50].iter().map(|&b| b as char).collect(); + (row1, row2) } } + #[cfg(test)] -mod test { +mod tests { use super::*; - #[test] - fn smoke() { assert!(true); } + fn pulse_enable(lcd: &mut HD44780) { + lcd.write_control_lines(lcd.rs, lcd.rw, true); + lcd.write_control_lines(lcd.rs, lcd.rw, false); + } #[test] - fn device_init() { - let display = DisplayMatrix::new(100.0, 100.0); + 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); + lcd.tick(); + assert!(lcd.ddram.iter().all(|&b| b == b' ')); } -} + + #[test] + 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); + lcd.tick(); + assert_eq!(lcd.ddram[0], b'A'); + } + + #[test] + 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); + lcd.tick(); + assert_eq!(lcd.cursor_position, 0x40); + } + + #[test] + fn test_read_busy_flag_and_address() { + let mut lcd = HD44780::new(); + lcd.busy = true; + lcd.cursor_position = 0x15; + lcd.write_control_lines(false, true, true); + let data = lcd.read_data_bus(); + assert_eq!(data, 0x80 | 0x15); + } +} \ No newline at end of file diff --git a/beneater/src/parts/mod.rs b/beneater/src/parts/mod.rs index b2f1179..d789a31 100644 --- a/beneater/src/parts/mod.rs +++ b/beneater/src/parts/mod.rs @@ -6,3 +6,5 @@ pub mod address_bus; pub mod data_bus; pub mod cpu_display; pub mod ram_display; +pub mod mos6522_peripheral; +pub mod backplane; diff --git a/beneater/src/parts/mos6522_peripheral.rs b/beneater/src/parts/mos6522_peripheral.rs new file mode 100644 index 0000000..14cdc37 --- /dev/null +++ b/beneater/src/parts/mos6522_peripheral.rs @@ -0,0 +1,5 @@ +pub trait Mos6522Peripheral { + fn write(&mut self, port: u8); + fn control(&mut self, control: u8); + fn read(&mut self) -> u8; +} diff --git a/beneater/src/parts/via6522.rs b/beneater/src/parts/via6522.rs index 5a7af90..0ad5fd7 100644 --- a/beneater/src/parts/via6522.rs +++ b/beneater/src/parts/via6522.rs @@ -1,45 +1,127 @@ -pub enum Via6522Port { - A(u8), - B(u8) +use crate::parts::display_matrix::HD44780; +use crate::parts::mos6522_peripheral::Mos6522Peripheral; + +pub struct VIA6522 { + // Data registers + ora: u8, + orb: u8, + + // Data direction + ddra: u8, + ddrb: u8, + + // Control lines (external pins) + ca1: bool, + ca2: bool, + cb1: bool, + cb2: bool, + + // Timers + t1_counter: u16, + t1_latch: u16, + t1_enabled: bool, + + t2_counter: u16, + t2_latch: u16, + t2_enabled: bool, + + // Interrupt flags + ifr: u8, + ier: u8, + + // Peripheral (e.g., LCD) + pub lcd: Option>, } -#[derive(Default)] -pub struct Via6522 { - data_bus: u8, - address_bus: u16, - port_a_state: u8, - port_b_data: u8, - port_a_direction: u8, - port_b_direction: u8, - memory_offset: u16, -} - -impl Via6522 { - pub fn new(offset: u16) -> Self { - Via6522 { - memory_offset: offset, - ..Default::default() +impl VIA6522 { + pub fn new() -> Self { + Self { + ora: 0, + orb: 0, + ddra: 0, + ddrb: 0, + ca1: false, + ca2: false, + cb1: false, + cb2: false, + t1_counter: 0, + t1_latch: 0, + t1_enabled: false, + t2_counter: 0, + t2_latch: 0, + t2_enabled: false, + ifr: 0, + ier: 0, + lcd: Some(HD44780::new().into()), } } - pub fn set_port_direction(&mut self, port: Via6522Port) { - match port { - Via6522Port::A(x) => { - self.port_a_direction = x; - }, - Via6522Port::B(x) => { - self.port_b_direction = x; + pub fn read(&self, addr: u8) -> u8 { + match addr & 0x0F { + 0x0 => self.orb, + 0x1 => self.ora, + 0x2 => self.ddrb, + 0x3 => self.ddra, + 0x4 => (self.t1_counter & 0xFF) as u8, + 0x5 => (self.t1_counter >> 8) as u8, + 0x6 => (self.t1_latch & 0xFF) as u8, + 0x7 => (self.t1_latch >> 8) as u8, + 0x8 => (self.t2_counter & 0xFF) as u8, + 0x9 => (self.t2_latch & 0xFF) as u8, + 0xD => self.ifr, + 0xE => self.ier | 0x80, + _ => 0, + } + } + + pub fn write(&mut self, addr: u8, value: u8) { + match addr & 0x0F { + 0x0 => self.orb = value, + 0x1 => self.ora = value, + 0x2 => self.ddrb = value, + 0x3 => self.ddra = value, + 0x4 => { + self.t1_latch = (self.t1_latch & 0xFF00) | value as u16; + self.t1_counter = self.t1_latch; + } + 0x5 => { + self.t1_latch = (value as u16) << 8 | (self.t1_latch & 0x00FF); + self.t1_counter = self.t1_latch; + self.t1_enabled = true; + } + 0x6 => self.t1_latch = (self.t1_latch & 0xFF00) | value as u16, + 0x7 => self.t1_latch = (value as u16) << 8 | (self.t1_latch & 0x00FF), + 0x8 => self.t2_counter = value as u16, + 0x9 => self.t2_latch = value as u16, + 0xD => self.ifr &= !value, // Clear interrupt flags + 0xE => { + if value & 0x80 != 0 { + self.ier |= value & 0x7F; + } else { + self.ier &= !(value & 0x7F); + } + } + _ => {} + } + } + + pub fn tick(&mut self) { + if self.t1_enabled { + if self.t1_counter > 0 { + self.t1_counter -= 1; + if self.t1_counter == 0 { + self.ifr |= 0x40; // Set T1 interrupt + } + } + } + + if self.t2_enabled { + if self.t2_counter > 0 { + self.t2_counter -= 1; + if self.t2_counter == 0 { + self.ifr |= 0x20; // Set T2 interrupt + } } } } - - /// check for output pins and see what they say - pub fn update_pins(&mut self) { - - } - - /// check for input mode pins and see what they say - pub fn read_pins(&self) { - - } -} \ No newline at end of file +} diff --git a/core/src/constants/constants_system.rs b/core/src/constants/constants_system.rs index e31d0d4..e1cc22c 100644 --- a/core/src/constants/constants_system.rs +++ b/core/src/constants/constants_system.rs @@ -2,6 +2,5 @@ pub const SIZE_1KB: usize = 1024; 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; \ No newline at end of file diff --git a/core/src/mos6502cpu.rs b/core/src/mos6502cpu.rs index 90407e0..bde7943 100644 --- a/core/src/mos6502cpu.rs +++ b/core/src/mos6502cpu.rs @@ -11,33 +11,47 @@ use crate::constants::constants_system::*; use crate::instruction_table::INSTRUCTION_TABLE; pub struct Mos6502Cpu { - // this is public for rendering quickly. - pub memory: Box<[u8]>, + memory: [u8; SIZE_64KB], + /// accumulator a: u8, + /// x register x: u8, + /// y register y: u8, + /// cpu flags flags: Mos6502Flags, + /// program counter pc: u16, + /// stack offset s: u8, pub microcode_step: u8, - pub address_bus: u16, - pub data_bus: u8, + address_bus: u16, + data_bus: u8, ir: Instruction, // Instruction Register oi: OpInfo, has_reset: bool, iv: u16, // Interrupt Vector cycle_carry: u16, // Value to hold between microsteps - ir_bytes: Box<[u8]> + ir_bytes: [u8; 4], + /// CPU Read signal + pub read_signal: bool +} + +impl Mos6502Cpu { + + /// set_data_bus + /// + /// Sets data on the data bus. + /// Used when CPU is in "R" mode + pub fn set_data_bus(&mut self, to_set: u8) { + self.data_bus = to_set; + } } impl Default for Mos6502Cpu { fn default() -> Self { - let vec = vec![0x00; SIZE_64KB]; - let boxed_slize: Box<[u8]> = vec.into_boxed_slice(); - let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory"); - let mut working = Mos6502Cpu { - memory: boxed_array, + memory: [0x00; SIZE_64KB], a: 0x00, x: 0x00, y: 0x00, @@ -56,7 +70,8 @@ impl Default for Mos6502Cpu { has_reset: false, iv: 0xfffe, cycle_carry: 0x0000, - ir_bytes: [].into() + ir_bytes: [0x00; 4], + read_signal: true }; working.reset_cpu(); working @@ -64,13 +79,19 @@ impl Default for Mos6502Cpu { } impl Mos6502Cpu { + pub fn address_bus(&self) -> u16 { + self.address_bus + } + + pub fn data_bus(&self) -> u8 { + self.data_bus + } + pub fn new() -> Mos6502Cpu { - let vec = vec![0x00; SIZE_64KB]; - let boxed_slize: Box<[u8]> = vec.into_boxed_slice(); - let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory"); + let array = [0x00u8; SIZE_64KB]; let mut working = Mos6502Cpu { - memory: boxed_array, - ir_bytes: [].into(), + memory: array, + ir_bytes: [0x00; 4], ..Default::default() }; working.reset_cpu(); @@ -105,6 +126,7 @@ impl Mos6502Cpu { } pub fn poke(&mut self, offset: u16, value: u8) { + println!("Setting memory at {offset:04x} to {value:02x}"); self.memory[offset as usize] = value } @@ -112,7 +134,10 @@ impl Mos6502Cpu { self.a } pub fn poke_a(&mut self, new_a: u8) { - self.a = new_a; + + println!("Updating register A from [{}] to [{}]", self.a, new_a); + + self.a = new_a; } pub fn peek_x(&self) -> u8 { @@ -284,6 +309,8 @@ impl Mos6502Cpu { let (new_x, new_carry) = self.x.overflowing_add(1); self.poke_x(new_x); self.poke_flag(Carry, new_carry); + self.address_bus = self.pc; + self.data_bus = 0x00; } } Operation::INY => { @@ -291,11 +318,15 @@ impl Mos6502Cpu { let (new_y, new_carry) = self.y.overflowing_add(1); self.poke_y(new_y); self.poke_flag(Carry, new_carry); + self.address_bus = self.pc; + self.data_bus = 0x00; } } Operation::JMP => { match self.ir.operand { Operand::Word(offset) => { self.pc = offset; + self.address_bus = self.pc; + self.data_bus = 0x00; } _ => {} } @@ -597,8 +628,8 @@ mod test { let mut cpu = Mos6502Cpu::default(); cpu.memory[0x6000] = ISA_OP_LDA_ABS; cpu.memory[0x6001] = 0xef; - cpu.memory[0x6002] = 0xbe; - cpu.memory[0xbeef] = 0xab; + cpu.memory[0x6002] = 0x0e; + cpu.memory[0x0eef] = 0xab; cpu.pc = 0x6000; for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) { cpu.tick(); } @@ -611,9 +642,9 @@ mod test { let mut cpu = Mos6502Cpu::default(); cpu.memory[0x6000] = ISA_OP_LDA_ABSX; cpu.memory[0x6001] = 0xef; - cpu.memory[0x6002] = 0xbe; + cpu.memory[0x6002] = 0x0e; cpu.poke_x(0x01); - cpu.memory[0xbef0] = 0xab; + cpu.memory[0x0ef0] = 0xab; cpu.pc = 0x6000; for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSX) { cpu.tick(); } @@ -628,7 +659,7 @@ mod test { cpu.memory[0x6001] = 0xef; cpu.memory[0x6002] = 0xbe; cpu.poke_y(0x01); - cpu.memory[0xbef0] = 0xab; + cpu.memory[0x0ef0] = 0xab; cpu.pc = 0x6000; for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSY) { cpu.tick(); } diff --git a/core/src/mos6502flags.rs b/core/src/mos6502flags.rs index 24d9a6b..9795a29 100644 --- a/core/src/mos6502flags.rs +++ b/core/src/mos6502flags.rs @@ -1,4 +1,12 @@ +use crate::mos6502flags::Mos6502Flag::{Break, Carry, Decimal, Interrupt, Negative, Overflow, Zero}; +pub const BIT_NEGATIVE: u8 = 7; +pub const BIT_OVERFLOW: u8 = 6; +pub const BIT_BREAK: u8 = 4; +pub const BIT_DECIMAL: u8 = 3; +pub const BIT_INTERRUPT: u8 = 2; +pub const BIT_ZERO: u8 = 1; +pub const BIT_CARRY: u8 = 0; /// Represents the status flags in the 6502 processor's status register (P). #[derive(Debug, Copy, Clone, PartialEq)] pub enum Mos6502Flag { @@ -42,7 +50,21 @@ pub enum Mos6502Flag { Negative, } -#[derive(Default)] +impl Mos6502Flag { + pub fn index(&self) -> u8 { + match self { + Carry => BIT_CARRY, + Zero => BIT_ZERO, + Interrupt => BIT_INTERRUPT, + Decimal => BIT_DECIMAL, + Break => BIT_BREAK, + Overflow => BIT_OVERFLOW, + Negative => BIT_NEGATIVE + } + } +} + +#[derive(Default, PartialEq, Debug)] pub struct Mos6502Flags { carry: bool, zero: bool, @@ -56,78 +78,133 @@ pub struct Mos6502Flags { impl Mos6502Flags { pub fn dump(&self) -> String { format!("{}{}{}{}{}{}{}", - if self.carry { 'C' } else { 'c' }, - if self.zero { 'Z' } else { 'z' }, - if self.interrupt { 'I' } else { 'i' }, - if self.decimal { 'D' } else { 'd' }, - if self.break_flag { 'B' } else { 'b' }, - if self.overflow { 'O' } else { 'o' }, - if self.negative { 'N' } else { 'n' } + if self.carry { 'C' } else { 'c' }, + if self.zero { 'Z' } else { 'z' }, + if self.interrupt { 'I' } else { 'i' }, + if self.decimal { 'D' } else { 'd' }, + if self.break_flag { 'B' } else { 'b' }, + if self.overflow { 'O' } else { 'o' }, + if self.negative { 'N' } else { 'n' } ) } } impl Mos6502Flags { - pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) { - self.change_flag(flag_to_set, true); + println!("Setting {flag_to_set:?} flag"); + match flag_to_set { + Carry => self.carry = true, + Zero => self.zero = true, + Interrupt => self.interrupt = true, + Decimal => self.decimal = true, + Break => self.break_flag = true, + Overflow => self.overflow = true, + Negative => self.negative = true, + } } pub fn clear_flag(&mut self, flag_to_clear: Mos6502Flag) { - self.change_flag(flag_to_clear, false); - } + println!("Clearing {flag_to_clear:?} flag"); + match flag_to_clear { + Carry => self.carry = false, + Zero => self.zero = false, + Interrupt => self.interrupt = false, + Decimal => self.decimal = false, + Break => self.break_flag = false, + Overflow => self.overflow = false, + Negative => self.negative = false, + } } fn change_flag(&mut self, flag_to_change: Mos6502Flag, new_value: bool) { - match flag_to_change { - Mos6502Flag::Carry => { - self.carry = new_value - } - Mos6502Flag::Zero => { - self.zero = new_value - } - Mos6502Flag::Interrupt => { - self.interrupt = new_value - } - Mos6502Flag::Decimal => { - self.decimal = new_value - } - Mos6502Flag::Break => { - self.break_flag = new_value - } - Mos6502Flag::Overflow => { - self.overflow = new_value - } - Mos6502Flag::Negative => { - self.negative = new_value - } + if new_value { + self.set_flag(flag_to_change); + } else { + self.clear_flag(flag_to_change); } } pub fn flag(&self, flag_to_read: Mos6502Flag) -> bool { match flag_to_read { - Mos6502Flag::Carry => { - self.carry - } - Mos6502Flag::Zero => { - self.zero - } - Mos6502Flag::Interrupt => { - self.interrupt - } - Mos6502Flag::Decimal => { - self.decimal - } - Mos6502Flag::Break => { - self.break_flag - } - Mos6502Flag::Overflow => { - self.overflow - } - Mos6502Flag::Negative => { - self.negative - } + Mos6502Flag::Negative => self.negative, + Mos6502Flag::Overflow => self.overflow, + // 5 + Mos6502Flag::Break => self.break_flag, + Mos6502Flag::Decimal => self.decimal, + Mos6502Flag::Interrupt => self.interrupt, + Mos6502Flag::Zero => self.zero, + Mos6502Flag::Carry => self.carry, } } + + pub fn as_byte(&self) -> u8 { + let mut working = 0x00; + + if self.flag(Negative) { working += 1 << Negative.index(); } + if self.flag(Overflow) { working += 1 << Overflow.index(); } + working += 1 << 5; // Always Set + if self.flag(Break) { working += 1 << Break.index(); } + if self.flag(Decimal) { working += 1 << Decimal.index(); } + if self.flag(Interrupt) { working += 1 << Interrupt.index(); } + if self.flag(Zero) { working += 1 << Zero.index(); } + if self.flag(Carry) { working += 1 << Carry.index(); } + + working + } + + + + pub fn from_byte(src: u8) -> Self { + let mut working = Self::default(); + + working.change_flag(Negative, Self::bit(src, Negative.index())); + working.change_flag(Overflow, Self::bit(src, Overflow.index())); + working.change_flag(Break, Self::bit(src, Break.index())); + working.change_flag(Decimal, Self::bit(src, Decimal.index())); + working.change_flag(Interrupt, Self::bit(src, Interrupt.index())); + working.change_flag(Zero, Self::bit(src, Zero.index())); + working.change_flag(Carry, Self::bit(src, Carry.index())); + + working + } + + /// bit + /// + /// src -> Source byte to check in + /// pos -> Which bit to check + /// + /// returns bool + /// + /// True if the bit is set. + /// False if the bit is not set + #[inline] + fn bit(src: u8, pos: u8) -> bool { + (src >> pos) & 1 != 0 + } } +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn smoke() { assert!(true); } + + #[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)); + } +} diff --git a/core/src/periph/at28c256/mod.rs b/core/src/periph/at28c256/mod.rs index d097864..be1e3d4 100644 --- a/core/src/periph/at28c256/mod.rs +++ b/core/src/periph/at28c256/mod.rs @@ -14,6 +14,12 @@ pub struct At28C256 { data: Box<[u8; SIZE_32KB]>, } +impl At28C256 { + pub fn program(&mut self, new_program: &[u8; 32768]) { + self.data= new_program.into(); + } +} + #[cfg(test)] mod test { use crate::constants::constants_system::SIZE_1KB; diff --git a/core/src/periph/at28c256/rom_chip.rs b/core/src/periph/at28c256/rom_chip.rs index 3de9161..29849b2 100644 --- a/core/src/periph/at28c256/rom_chip.rs +++ b/core/src/periph/at28c256/rom_chip.rs @@ -8,7 +8,7 @@ impl RomChip for At28C256 { self.data[*offset as usize] } - fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box { + fn program(new_data: &[u8; SIZE_32KB]) -> Box { println!("Writing new chip."); let mut working = At28C256::default(); working.data = Box::new(*new_data); diff --git a/core/src/periph/hm62256.rs b/core/src/periph/hm62256.rs index 65cc5d3..ee951d2 100644 --- a/core/src/periph/hm62256.rs +++ b/core/src/periph/hm62256.rs @@ -29,7 +29,7 @@ impl RomChip for Hm62256 { self.data[effective as usize] } - fn program(_: Box<[u8; SIZE_32KB]>) -> Box { + fn program(_: &[u8; SIZE_32KB]) -> Box { debug!("Dont program ram."); Hm62256::default().into() } diff --git a/core/src/periph/rom_chip.rs b/core/src/periph/rom_chip.rs index b567be3..7569ff7 100644 --- a/core/src/periph/rom_chip.rs +++ b/core/src/periph/rom_chip.rs @@ -8,5 +8,5 @@ pub trait RomChip { /// Program /// /// Replaces all data in the ROM chip - fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box; + fn program(new_data: &[u8; SIZE_32KB]) -> Box; }