diff --git a/Cargo.lock b/Cargo.lock index b4db118..bf7457c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,31 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bdf" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f550a6818e6f42ccd5883f44e45fff4f68415a0d09abdc81e7d1d78e0780af14" +dependencies = [ + "bit-set", + "thiserror", +] + +[[package]] +name = "bit-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84527c7b0452f22545cc010e72d366a435561d2b28b978035550b3778c4d428d" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -20,6 +45,18 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -78,6 +115,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.30" @@ -171,6 +214,8 @@ dependencies = [ name = "georgeemu" version = "0.1.0" dependencies = [ + "bdf", + "bitvec", "minifb", ] @@ -347,6 +392,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "raw-window-handle" version = "0.4.3" @@ -453,6 +504,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.9.0" @@ -466,6 +523,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -781,6 +858,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11-dl" version = "2.21.0" diff --git a/Cargo.toml b/Cargo.toml index 2407314..9f17eb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bdf = "0.6.0" +bitvec = "1.0.1" minifb = "0.25.0" diff --git a/src/cpu.rs b/src/cpu.rs index 9fa05a5..116069b 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -212,9 +212,9 @@ impl Cpu { let instruction = get_instruction(opcode); match instruction { Instruction::Valid(valid_instruction) => { - println!("Instruction: {:?}, {:?}", valid_instruction.opcode, opcode); - println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi); - println!(""); + //println!("Instruction: {:?}, {:?}", valid_instruction.opcode, opcode); + //println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi); + //println!(""); self.pc += 1; match valid_instruction.opcode.call(self) { Ok(_) => { diff --git a/src/error.rs b/src/error.rs index ffb15e4..ed6fdac 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,7 @@ pub enum GeorgeErrorKind { Memory(MemoryError), Execution(ExecutionError), AddrMode(AddressingModeError), + Mapping(MappingError), } impl From for GeorgeErrorKind { diff --git a/src/george b/src/george index b9b7bd4..1ca1b4f 100644 Binary files a/src/george and b/src/george differ diff --git a/src/george.asm b/src/george.asm index 05a6418..3914634 100644 --- a/src/george.asm +++ b/src/george.asm @@ -1,5 +1,7 @@ .setcpu "65C02" .segment "CODE" +LDA #$0 +STA $4000 main: LDA #$25 LDY #$2F diff --git a/src/georgeencoding.txt b/src/georgeencoding.txt index eafc4a8..eb48021 100644 --- a/src/georgeencoding.txt +++ b/src/georgeencoding.txt @@ -8,7 +8,7 @@ # column #3 the Unicode name (follows a comment sign, '#') 0x00 0x0295 # ʕ -0x01 0x0097 # Middle Dot +0x01 0x00B7 # Middle Dot 0x02 0x1D25 # ᴥ 0x03 0x0294 # ʔ 0x04 0x2661 # White heart @@ -27,18 +27,18 @@ 0x11 0x266A # Eighth note 0x12 0x266B # Beamed eighth notes 0x13 0x266C # Beamed sixteenth notes -0x14 0x0020 # -0x15 0x0020 # -0x16 0x0020 # -0x17 0x0020 # -0x18 0x0020 # -0x19 0x0020 # -0x1A 0x0020 # -0x1B 0x0020 # -0x1C 0x0020 # -0x1D 0x0020 # -0x1E 0x0020 # -0x1F 0x0020 # +0x14 0xFC5D # +0x15 0xF026 # +0x16 0xF027 # +0x17 0xF028 # +0x18 0xFA7E # +0x19 0xFA7F # +0x1A 0xFA80 # +0x1B 0xFC5C # +0x1C 0xFC5B # +0x1D 0xF0AC # +0x1E 0xF04B # +0x1F 0xF04D # 0x20 0x0020 # SPACE 0x21 0x0021 # EXCLAMATION MARK 0x22 0x0022 # QUOTATION MARK @@ -161,11 +161,11 @@ 0x97 0x2566 # 0x98 0x2569 # 0x99 0x256C # -0x9A 0x0020 # -0x9B 0x0020 # -0x9C 0x0020 # -0x9D 0x0020 # -0x9E 0x0020 # +0x9A 0xF04E # +0x9B 0xF050 # +0x9C 0xF051 # +0x9D 0xF052 # +0x9E 0xF048 # 0x9F 0xE0B0 # 0xA0 0xE0B2 # 0xA1 0xE0B4 # @@ -214,52 +214,52 @@ 0xCC 0x2B81 # 0xCD 0x2B82 # 0xCE 0x2B83 # -0xCF 0x0020 # -0xD0 0x0020 # -0xD1 0x0020 # -0xD2 0x0020 # -0xD3 0x0020 # -0xD4 0x0020 # -0xD5 0x0020 # -0xD6 0x0020 # -0xD7 0x0020 # -0xD8 0x0020 # -0xD9 0x0020 # -0xDA 0x0020 # -0xDB 0x0020 # -0xDC 0x0020 # -0xDD 0x0020 # -0xDE 0x0020 # -0xDF 0x0020 # -0xE0 0x0020 # -0xE1 0x0020 # -0xE2 0x0020 # -0xE3 0x0020 # -0xE4 0x0020 # -0xE5 0x0020 # -0xE6 0x0020 # -0xE7 0x0020 # -0xE8 0x0020 # -0xE9 0x0020 # -0xEA 0x0020 # -0xEB 0x0020 # -0xEC 0x0020 # -0xED 0x0020 # -0xEE 0x0020 # -0xEF 0x0020 # -0xF0 0x0020 # -0xF1 0x0020 # -0xF2 0x0020 # -0xF3 0x0020 # -0xF4 0x0020 # -0xF5 0x0020 # -0xF6 0x0020 # -0xF7 0x0020 # -0xF8 0x0020 # -0xF9 0x0020 # -0xFA 0x0020 # -0xFB 0x0020 # -0xFC 0x0020 # -0xFD 0x0020 # -0xFE 0x0020 # -0xFF 0x0020 # +0xCF 0xF049 # +0xD0 0xF04A # +0xD1 0x23F3 # +0xD2 0xF07B # +0xD3 0xF07C # +0xD4 0xF114 # +0xD5 0xF115 # +0xD6 0xF250 # +0xD7 0xF251 # +0xD8 0xF253 # +0xD9 0xF254 # +0xDA 0xF461 # +0xDB 0xF016 # +0xDC 0xF401 # +0xDD 0x1F52E # +0xDE 0xF2DB # +0xDF 0xF008 # +0xE0 0x25C7 # +0xE1 0x25C8 # +0xE2 0x1F311 # +0xE3 0x1F312 # +0xE4 0x1F313 # +0xE5 0x1F314 # +0xE6 0x1F315 # +0xE7 0x1F316 # +0xE8 0x1F317 # +0xE9 0x1F318 # +0xEA 0xF04C # +0xEB 0x2714 # +0xEC 0x2718 # +0xED 0x25C6 # +0xEE 0xF15D # +0xEF 0xF15E # +0xF0 0xF071 # +0xF1 0xF449 # +0xF2 0xF529 # +0xF3 0xF658 # +0xF4 0xF659 # +0xF5 0x0020 # +0xF6 0x1f381 # Space +0xF7 0xf05a # Space +0xF8 0xf06a # Space +0xF9 0xf834 # Space +0xFA 0xf835 # Space +0xFB 0x2690 # Space +0xFC 0x2691 # Space +0xFD 0xf8d7 # Space +0xFE 0xf0e7 # Space +0xFF 0xf7d9 # Space diff --git a/src/main.rs b/src/main.rs index 35dce43..bd0d4c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,13 +24,13 @@ fn main() { let rom = MemMappedDevice::new(0xE000, 0xFFFF, 4, "rom".into()); let mut memory = Mem::new(ram); if let Err(error) = memory.add_area(control) { - println!("Error adding vram: {:?}", error); + println!("Error adding vram: {:?}", error.desc); }; if let Err(error) = memory.add_area(vram) { - println!("Error adding vram: {:?}", error); + println!("Error adding vram: {:?}", error.desc); }; if let Err(error) = memory.add_area(rom) { - println!("Error adding rom: {:?}", error); + println!("Error adding rom: {:?}", error.desc); }; let binary = match std::fs::File::open(PathBuf::from( "/Users/kline/projects/winter/george-emu/src/george", diff --git a/src/memory.rs b/src/memory.rs index 15c9a77..09a81af 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -59,10 +59,16 @@ impl Mem { pub fn new(area: MemMappedDevice) -> Self { Self { areas: vec![area] } } - pub fn add_area(&mut self, area: MemMappedDevice) -> Result<(), MappingError> { + pub fn add_area(&mut self, area: MemMappedDevice) -> Result<(), GeorgeError> { for existing_area in &self.areas { if existing_area.contains(area.end) || existing_area.contains(area.start) { - return Err(MappingError::RegionOccupied); + return Err(GeorgeError { + desc: format!( + "Tried to assign an area already allocated to {:?}", + existing_area + ), + kind: GeorgeErrorKind::Mapping(MappingError::RegionOccupied), + }); } } self.areas.push(area); diff --git a/src/video.rs b/src/video.rs index 74b41f0..e996848 100644 --- a/src/video.rs +++ b/src/video.rs @@ -1,27 +1,111 @@ -use crate::Mem; +use crate::{memory, Mem}; use minifb::{Window, WindowOptions}; use std::{ - sync::{Arc, RwLock}, + char, + fs::File, + io::Read, + process::exit, + sync::{Arc, RwLock, RwLockReadGuard}, thread::sleep, time::{Duration, Instant}, }; +const FG_COLOR: u32 = 0xFFCC00; +//const BG_COLOR: u32 = 0x110500; +const BG_COLOR: u32 = 0x22BB00; + pub struct Crtc { memory: Arc>, buffer: Vec, window: minifb::Window, + char_rom: Vec, +} + +pub fn get_char_bin(path: &str) -> Vec { + let mut file = File::open(path).unwrap(); + let mut buffer = vec![0; 0xFFFF]; + file.read_exact(&mut buffer).unwrap(); + buffer } impl Crtc { pub fn new(memory: Arc>) -> Self { let window = Window::new("screen", 512, 380, WindowOptions::default()).unwrap(); + let char_rom = get_char_bin("./src/cozette.bin"); Self { memory, buffer: vec![0; 512 * 380], window, + char_rom, } } fn draw(&mut self) { + match &mut self.memory.clone().try_read() { + Ok(memory) => { + let hw_ctrl = memory.read(0x4000).unwrap(); + match hw_ctrl & 0b0000_1000 == 0b0000_1000 { + false => self.draw_chars(), + true => self.draw_hires(), + }; + } + Err(_) => { + println!("Couldn't acquire read on shared memory in main thread"); + return; + } + }; + + self.window + .update_with_buffer(&self.buffer, 512, 380) + .unwrap(); + } + + fn draw_chars(&mut self) { + let memory = match self.memory.try_read() { + Ok(read) => read, + Err(_) => { + println!("Couldn't acquire read on shared memory in main thread"); + return; + } + }; + for char_col in 0..65 { + let pixel_col = char_col * 8; + for char_row in 0..30 { + let pixel_row = char_row * 13; + for row in 0..13 { + for i in 0..8 { + let address: usize = ((pixel_col * pixel_row + row * 13) + i) * 8; + self.buffer[address] = BG_COLOR; + } + } + } + } + //for char_col in 0..64 { + // for char_row in 0..29 { + // let ascii = memory.read(0x6000 + char_row * char_col).unwrap(); + // for row in 0..13 { + // for char in 0..=255 { + // if ascii == char { + // let byte = self.char_rom[char as usize + (row * 0xFF)]; + // for i in 0..8 { + // let address: usize = ((char_col as usize * 64 + (8 * i)) + // + (char_row as usize + (13 * row) * 29)) + // * 8 + // + i; + // if (byte >> i) & 0b1 == 1 { + // self.buffer[address] = FG_COLOR; + // } else { + // self.buffer[address] = BG_COLOR; + // } + // } + // } + // } + // } + // } + //} + println!("{:?}", self.buffer); + //exit(0); + } + fn draw_hires(&mut self) { let memory = match self.memory.try_read() { Ok(read) => read, Err(_) => { @@ -29,24 +113,17 @@ impl Crtc { return; } }; - // let bitmask = [128, 64, 32, 16, 8, 4, 2, 1]; - let bitmask = [1, 2, 4, 8, 16, 32, 64, 128]; // I think this is how the bytes will be - // serialized? low bits first? - for addr in 0x6000..0xBF00 { // TODO: eventually this will access memory in the weird interleaved way the hardware is // designed, but this is easiest to implement for now let byte = memory.read(addr).unwrap(); - for (i, mask) in bitmask.iter().enumerate() { - match byte & mask == 0 { - true => self.buffer[(addr - 0x6000) as usize * 8 + i] = 0x110500, - false => self.buffer[(addr - 0x6000) as usize * 8 + i] = 0xFFCC00, + for i in 0..8 { + match byte & 0x80 >> i == 0 { + true => self.buffer[(addr - 0x6000) as usize * 8 + i] = BG_COLOR, + false => self.buffer[(addr - 0x6000) as usize * 8 + i] = FG_COLOR, } } } - self.window - .update_with_buffer(&self.buffer, 512, 380) - .unwrap(); } pub fn run(&mut self) { let frame_duration = Duration::from_millis(16);