we can type the letter w!
This commit is contained in:
		
							parent
							
								
									9808616203
								
							
						
					
					
						commit
						40ede17ae1
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -8,5 +8,4 @@ edition = "2021"
 | 
			
		|||
[dependencies]
 | 
			
		||||
bdf = "0.6.0"
 | 
			
		||||
bitvec = "1.0.1"
 | 
			
		||||
iced = { version = "0.12.0", features = ["canvas", "smol"] }
 | 
			
		||||
minifb = "0.25.0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								src/cpu.rs
								
								
								
								
							
							
						
						
									
										70
									
								
								src/cpu.rs
								
								
								
								
							| 
						 | 
				
			
			@ -1,8 +1,9 @@
 | 
			
		|||
use crate::error::{ExecutionError, GeorgeError, GeorgeErrorKind, MemoryError};
 | 
			
		||||
use crate::instructions::{get_instruction, Instruction};
 | 
			
		||||
use crate::memory::{self, Mem};
 | 
			
		||||
use crate::memory::Mem;
 | 
			
		||||
use crate::types::{Byte, Word};
 | 
			
		||||
use std::process::exit;
 | 
			
		||||
use std::sync::Mutex;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use std::{
 | 
			
		||||
    str::FromStr,
 | 
			
		||||
| 
						 | 
				
			
			@ -31,13 +32,13 @@ pub struct Cpu {
 | 
			
		|||
    pub p: Byte,  // Status Register
 | 
			
		||||
    pub irq: bool,
 | 
			
		||||
    pub nmi: bool,
 | 
			
		||||
    pub memory: Arc<RwLock<Mem>>,
 | 
			
		||||
    pub memory: Arc<Mutex<Mem>>,
 | 
			
		||||
    pub pending_cycles: usize,
 | 
			
		||||
    cycle_count: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Cpu {
 | 
			
		||||
    pub fn new(memory: Arc<RwLock<Mem>>) -> Self {
 | 
			
		||||
    pub fn new(memory: Arc<Mutex<Mem>>) -> Self {
 | 
			
		||||
        Cpu {
 | 
			
		||||
            a: 0x00,
 | 
			
		||||
            x: 0x00,
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +60,7 @@ impl Cpu {
 | 
			
		|||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    pub fn read(&self, address: Word) -> Result<Byte, MemoryError> {
 | 
			
		||||
        let memory = match self.memory.try_read() {
 | 
			
		||||
        let memory = match self.memory.lock() {
 | 
			
		||||
            Ok(read) => read,
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                println!("Couldn't acquire read lock on memory in cpu thread");
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +122,7 @@ impl Cpu {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write(&mut self, address: Word, data: Byte) -> Result<(), MemoryError> {
 | 
			
		||||
        let mut memory = match self.memory.write() {
 | 
			
		||||
        let mut memory = match self.memory.lock() {
 | 
			
		||||
            Ok(write) => write,
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                println!("Couldn't acquire write lock on memory in cpu thread");
 | 
			
		||||
| 
						 | 
				
			
			@ -133,9 +134,9 @@ impl Cpu {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn execute(&mut self) {
 | 
			
		||||
        self.cycle().unwrap();
 | 
			
		||||
        self.cycle();
 | 
			
		||||
        while self.pending_cycles != 0 {
 | 
			
		||||
            self.cycle().unwrap();
 | 
			
		||||
            self.cycle();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +167,7 @@ impl Cpu {
 | 
			
		|||
    //         }
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
    pub fn cycle(&mut self) -> Result<(), GeorgeError> {
 | 
			
		||||
    pub fn cycle(&mut self) {
 | 
			
		||||
        sleep(Duration::from_nanos(100));
 | 
			
		||||
        if self.pending_cycles == 0 {
 | 
			
		||||
            if self.nmi || (self.irq && !self.get_flag(StatusFlag::IrqDisable)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -178,10 +179,11 @@ impl Cpu {
 | 
			
		|||
                    match self.read_word(0xFFFA) {
 | 
			
		||||
                        Ok(word) => self.pc = word,
 | 
			
		||||
                        Err(error) => {
 | 
			
		||||
                            return Err(GeorgeError {
 | 
			
		||||
                            let george_error = GeorgeError {
 | 
			
		||||
                                kind: GeorgeErrorKind::Memory(error),
 | 
			
		||||
                                desc: String::from_str("Couldn't read NMI vector").unwrap(),
 | 
			
		||||
                            })
 | 
			
		||||
                            };
 | 
			
		||||
                            println!("{:?}", george_error.desc);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                    self.pending_cycles = 8;
 | 
			
		||||
| 
						 | 
				
			
			@ -189,10 +191,11 @@ impl Cpu {
 | 
			
		|||
                    match self.read_word(0xFFFE) {
 | 
			
		||||
                        Ok(word) => self.pc = word,
 | 
			
		||||
                        Err(error) => {
 | 
			
		||||
                            return Err(GeorgeError {
 | 
			
		||||
                            let george_error = GeorgeError {
 | 
			
		||||
                                kind: GeorgeErrorKind::Memory(error),
 | 
			
		||||
                                desc: String::from_str("Couldn't read IRQ vector").unwrap(),
 | 
			
		||||
                            })
 | 
			
		||||
                            };
 | 
			
		||||
                            println!("{:?}", george_error.desc);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                    self.pending_cycles = 7
 | 
			
		||||
| 
						 | 
				
			
			@ -204,62 +207,69 @@ impl Cpu {
 | 
			
		|||
            let opcode = match self.read(self.pc) {
 | 
			
		||||
                Ok(byte) => byte,
 | 
			
		||||
                Err(error) => {
 | 
			
		||||
                    return Err(GeorgeError {
 | 
			
		||||
                        desc: String::from_str("Failed to read the program counter!").unwrap(),
 | 
			
		||||
                    let george_error = GeorgeError {
 | 
			
		||||
                        desc: format!("Failed to read from memory at address {:#06x}!", self.pc),
 | 
			
		||||
                        kind: GeorgeErrorKind::Memory(error),
 | 
			
		||||
                    })
 | 
			
		||||
                    };
 | 
			
		||||
                    println!("{:?}", george_error.desc);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            let instruction = get_instruction(opcode);
 | 
			
		||||
            match instruction {
 | 
			
		||||
                Instruction::Valid(valid_instruction) => {
 | 
			
		||||
                    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!(
 | 
			
		||||
                        "Instruction: {:?}, {:#04x}",
 | 
			
		||||
                        valid_instruction.opcode, opcode
 | 
			
		||||
                    );
 | 
			
		||||
                    println!("");
 | 
			
		||||
                    //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!(
 | 
			
		||||
                    //    "Instruction: {:?}, {:#04x}",
 | 
			
		||||
                    //    valid_instruction.opcode, opcode
 | 
			
		||||
                    //);
 | 
			
		||||
                    //println!("");
 | 
			
		||||
                    self.pc += 1;
 | 
			
		||||
                    match valid_instruction.opcode.call(self) {
 | 
			
		||||
                        Ok(_) => {
 | 
			
		||||
                            self.pending_cycles += valid_instruction.cycles as usize;
 | 
			
		||||
                        },
 | 
			
		||||
                        Err(error) => return Err(GeorgeError{
 | 
			
		||||
                        }
 | 
			
		||||
                        Err(error) => {
 | 
			
		||||
                            let george_error = GeorgeError{
 | 
			
		||||
                            desc: format!("An IncompatibleAddrMode was used at address {:#06x} for instruction {:?}", 
 | 
			
		||||
                                          self.pc, valid_instruction).to_string(), kind: error})
 | 
			
		||||
                                          self.pc, valid_instruction).to_string(), kind: error};
 | 
			
		||||
                            println!("{:?}", george_error.desc);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode {
 | 
			
		||||
                    0x02 => {
 | 
			
		||||
                        let memory = match self.memory.try_read() {
 | 
			
		||||
                        let memory = match self.memory.lock() {
 | 
			
		||||
                            Ok(read) => read,
 | 
			
		||||
                            Err(_) => {
 | 
			
		||||
                                println!("Couldn't acquire read lock on memory in cpu thread");
 | 
			
		||||
                                return Err(GeorgeError {
 | 
			
		||||
                                let george_error = GeorgeError {
 | 
			
		||||
                                    kind: GeorgeErrorKind::Memory(MemoryError::Unwritable),
 | 
			
		||||
                                    desc: "Couldn't acquire read lock on memory in cpu thread"
 | 
			
		||||
                                        .to_string(),
 | 
			
		||||
                                });
 | 
			
		||||
                                };
 | 
			
		||||
                                println!("{:?}", george_error.desc);
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                        };
 | 
			
		||||
                        memory.dump().unwrap();
 | 
			
		||||
                        exit(1);
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => {
 | 
			
		||||
                        return Err(GeorgeError {
 | 
			
		||||
                        let george_error = GeorgeError {
 | 
			
		||||
                            kind: GeorgeErrorKind::Execution(ExecutionError::InvalidInstruction),
 | 
			
		||||
                            desc: format!(
 | 
			
		||||
                        "An invalid instruction with opcode {:#04x} was called at address {:#06x}",
 | 
			
		||||
                        invalid_instruction.opcode, self.pc
 | 
			
		||||
                    ),
 | 
			
		||||
                        });
 | 
			
		||||
                        };
 | 
			
		||||
                        println!("{:?}", george_error.desc);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        self.pending_cycles -= 1;
 | 
			
		||||
        self.cycle_count += 1;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn stop(&mut self) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											BIN
										
									
								
								src/george
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								src/george
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
    .byte $02
 | 
			
		||||
.endmacro 
 | 
			
		||||
 | 
			
		||||
.macro pop ; drops a stack cell
 | 
			
		||||
.macro pop ; drops a data stack cell
 | 
			
		||||
    inx
 | 
			
		||||
    inx
 | 
			
		||||
.endmacro
 | 
			
		||||
| 
						 | 
				
			
			@ -20,18 +20,36 @@
 | 
			
		|||
    inx
 | 
			
		||||
.endmacro
 | 
			
		||||
 | 
			
		||||
.macro push ; 
 | 
			
		||||
.macro push ; push a data stack cell
 | 
			
		||||
    dex
 | 
			
		||||
    dex
 | 
			
		||||
.endmacro
 | 
			
		||||
 | 
			
		||||
.macro push2 ; 
 | 
			
		||||
.macro push2 ; push 2 data stack cells
 | 
			
		||||
    dex
 | 
			
		||||
    dex
 | 
			
		||||
    dex
 | 
			
		||||
    dex
 | 
			
		||||
.endmacro
 | 
			
		||||
 | 
			
		||||
.macro push_char char ; pushes an ascii character code onto the stack
 | 
			
		||||
    lda char
 | 
			
		||||
    push
 | 
			
		||||
    sta 0, x ; char low byte
 | 
			
		||||
    stz 1, x ; char high byte
 | 
			
		||||
.endmacro
 | 
			
		||||
 | 
			
		||||
.macro push_coords coord_x, coord_y ; push a set of (x,y) coordinates onto the data stack
 | 
			
		||||
    lda coord_x
 | 
			
		||||
    push
 | 
			
		||||
    sta 0, x ; low byte
 | 
			
		||||
    stz 1,x ; high byte is zero
 | 
			
		||||
    lda coord_y
 | 
			
		||||
    push
 | 
			
		||||
    sta 0,x ; same here
 | 
			
		||||
    stz 1,x
 | 
			
		||||
.endmacro
 | 
			
		||||
 | 
			
		||||
.macro to_r ; pop the top of the stack off and save it in the return (hardware) stack: (n -- )
 | 
			
		||||
    lda 1, x
 | 
			
		||||
    pha
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +72,7 @@ init:
 | 
			
		|||
 | 
			
		||||
main:
 | 
			
		||||
    jsr draw
 | 
			
		||||
    jmp main
 | 
			
		||||
 | 
			
		||||
initdisplay:
 | 
			
		||||
    lda #$20
 | 
			
		||||
| 
						 | 
				
			
			@ -74,25 +93,29 @@ cleardisplay:
 | 
			
		|||
    bne cleardisplay
 | 
			
		||||
    rts
 | 
			
		||||
 | 
			
		||||
draw: ; draw a character at (20, 30)
 | 
			
		||||
    lda #63
 | 
			
		||||
    push
 | 
			
		||||
    sta 0, x ; low byte
 | 
			
		||||
    stz 1,x ; high byte is zero
 | 
			
		||||
    lda #28
 | 
			
		||||
    push
 | 
			
		||||
    sta 0,x ; same here
 | 
			
		||||
    stz 1,x
 | 
			
		||||
draw:
 | 
			
		||||
    lda #%01000000
 | 
			
		||||
    bit $4400
 | 
			
		||||
    beq @1
 | 
			
		||||
    push_coords #0, #0
 | 
			
		||||
    push_char #$77
 | 
			
		||||
    jsr draw_char
 | 
			
		||||
    @1: 
 | 
			
		||||
    rts
 | 
			
		||||
 | 
			
		||||
draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
 | 
			
		||||
    lda 0, x ; load a with character to draw
 | 
			
		||||
    pop ; and pop it off the stack
 | 
			
		||||
    jsr get_char_address ; calculate where to put the character in memory
 | 
			
		||||
    lda #4
 | 
			
		||||
    sta (0, x) ; store a at the address pointed to on the stack
 | 
			
		||||
    brk
 | 
			
		||||
    rts
 | 
			
		||||
 | 
			
		||||
get_char_address:   ; gets vram address for a character at (x, y),
 | 
			
		||||
                    ; (n1: x n2: y -- n: $6000 + x + (64 * y))
 | 
			
		||||
    ;jsr push_lit ; push 64 onto stack, low byte first
 | 
			
		||||
    ;.byte 64
 | 
			
		||||
    ;.byte 0
 | 
			
		||||
    pha
 | 
			
		||||
    lda #64
 | 
			
		||||
    push ; doing this instead until `push_lit` is fixed
 | 
			
		||||
    sta 0, x
 | 
			
		||||
| 
						 | 
				
			
			@ -109,18 +132,14 @@ get_char_address:   ; gets vram address for a character at (x, y),
 | 
			
		|||
    stz 0, x
 | 
			
		||||
    jsr plus ; add vram start address to result
 | 
			
		||||
 | 
			
		||||
    pla
 | 
			
		||||
    rts
 | 
			
		||||
 | 
			
		||||
fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
 | 
			
		||||
    
 | 
			
		||||
; inc16
 | 
			
		||||
; add 1 to a 16-bit pointer in zero page
 | 
			
		||||
 | 
			
		||||
;inc16:
 | 
			
		||||
;    inc ptr
 | 
			
		||||
;    bne :+
 | 
			
		||||
;    inc ptr+1
 | 
			
		||||
;:   rts
 | 
			
		||||
;
 | 
			
		||||
    jsr get_char_address
 | 
			
		||||
 | 
			
		||||
; --- Data Stack --- ;
 | 
			
		||||
; on this channel we love garth wilson: https://wilsonminesco.com/stacks/StackOps.ASM
 | 
			
		||||
; data stack is built up of 2-byte cells
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@
 | 
			
		|||
mod cpu;
 | 
			
		||||
mod error;
 | 
			
		||||
mod instructions;
 | 
			
		||||
mod keyboard;
 | 
			
		||||
mod memory;
 | 
			
		||||
mod types;
 | 
			
		||||
mod video;
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +12,7 @@ use crate::cpu::Cpu;
 | 
			
		|||
use crate::memory::{Mem, MemMappedDevice};
 | 
			
		||||
use crate::video::Crtc;
 | 
			
		||||
 | 
			
		||||
use std::sync::Mutex;
 | 
			
		||||
use std::{
 | 
			
		||||
    path::PathBuf,
 | 
			
		||||
    sync::{Arc, RwLock},
 | 
			
		||||
| 
						 | 
				
			
			@ -44,17 +46,16 @@ fn main() {
 | 
			
		|||
    memory.write(0xFFFC, 0x00).unwrap();
 | 
			
		||||
    memory.write(0xFFFD, 0x02).unwrap();
 | 
			
		||||
 | 
			
		||||
    let shared_memory = Arc::new(RwLock::new(memory));
 | 
			
		||||
    let shared_memory = Arc::new(Mutex::new(memory));
 | 
			
		||||
    let cpu_memory = shared_memory.clone();
 | 
			
		||||
    let display_memory = shared_memory.clone();
 | 
			
		||||
 | 
			
		||||
    let mut screen = Crtc::new(display_memory);
 | 
			
		||||
 | 
			
		||||
    thread::spawn(move || {
 | 
			
		||||
        let mut cpu = Cpu::new(cpu_memory);
 | 
			
		||||
        cpu.reset().unwrap();
 | 
			
		||||
        cpu.execute();
 | 
			
		||||
    });
 | 
			
		||||
    let mut screen = Crtc::new(display_memory);
 | 
			
		||||
    screen.run();
 | 
			
		||||
    shared_memory.write().unwrap().dump().unwrap();
 | 
			
		||||
    shared_memory.lock().unwrap().dump().unwrap();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										173
									
								
								src/video.rs
								
								
								
								
							
							
						
						
									
										173
									
								
								src/video.rs
								
								
								
								
							| 
						 | 
				
			
			@ -3,7 +3,7 @@ use minifb::{Key, Scale, ScaleMode, Window, WindowOptions};
 | 
			
		|||
use std::{
 | 
			
		||||
    fs::File,
 | 
			
		||||
    io::Read,
 | 
			
		||||
    sync::{Arc, RwLock},
 | 
			
		||||
    sync::{Arc, Mutex, RwLock},
 | 
			
		||||
    thread::sleep,
 | 
			
		||||
    time::{Duration, Instant},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ const FG_COLOR: u32 = 0xFFCC00;
 | 
			
		|||
const BG_COLOR: u32 = 0x110500;
 | 
			
		||||
 | 
			
		||||
pub struct Crtc {
 | 
			
		||||
    memory: Arc<RwLock<Mem>>,
 | 
			
		||||
    memory: Arc<Mutex<Mem>>,
 | 
			
		||||
    buffer: Vec<u32>,
 | 
			
		||||
    window: minifb::Window,
 | 
			
		||||
    char_rom: Vec<u8>,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ pub fn get_char_bin(path: &str) -> Vec<u8> {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
impl Crtc {
 | 
			
		||||
    pub fn new(memory: Arc<RwLock<Mem>>) -> Self {
 | 
			
		||||
    pub fn new(memory: Arc<Mutex<Mem>>) -> Self {
 | 
			
		||||
        let window = Window::new(
 | 
			
		||||
            "ʕ·ᴥ·ʔ-☆",
 | 
			
		||||
            512,
 | 
			
		||||
| 
						 | 
				
			
			@ -52,82 +52,127 @@ impl Crtc {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    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(),
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        let memory = match self.memory.lock() {
 | 
			
		||||
            Ok(memory) => memory,
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                println!("Couldn't acquire read on shared memory in main thread");
 | 
			
		||||
                println!("Couldn't acquire read on shared memory in video thread");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let hw_ctrl = memory.read(0x4000).unwrap();
 | 
			
		||||
        match hw_ctrl & 0b0000_1000 == 0b0000_1000 {
 | 
			
		||||
            false => {
 | 
			
		||||
                // the rest of this function is arcane wizardry based on the specifics of george's weird
 | 
			
		||||
                // display and characters... don't fuck around w it
 | 
			
		||||
                let mut i = 0;
 | 
			
		||||
                for char_row in 0..29 {
 | 
			
		||||
                    for char_col in 0..64 {
 | 
			
		||||
                        let ascii = memory.read(0x6000 + i).unwrap();
 | 
			
		||||
                        i += 1;
 | 
			
		||||
                        for row in 0..13 {
 | 
			
		||||
                            let byte = self.char_rom[ascii as usize + (row * 0x101)];
 | 
			
		||||
                            for i in (0..8).rev() {
 | 
			
		||||
                                let buffer_index =
 | 
			
		||||
                                    ((char_row) * 13 + (row)) * 512 + (char_col * 8 + i);
 | 
			
		||||
                                if (byte << i) & 0x80 == 0x80 {
 | 
			
		||||
                                    self.buffer[buffer_index] = FG_COLOR;
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    self.buffer[buffer_index] = BG_COLOR;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            true => {
 | 
			
		||||
                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 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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // the rest of this function is arcane wizardry based on the specifics of george's weird
 | 
			
		||||
        // display and characters... don't fuck around w it
 | 
			
		||||
        let mut i = 0;
 | 
			
		||||
        for char_row in 0..29 {
 | 
			
		||||
            for char_col in 0..64 {
 | 
			
		||||
                let ascii = memory.read(0x6000 + i).unwrap();
 | 
			
		||||
                i += 1;
 | 
			
		||||
                for row in 0..13 {
 | 
			
		||||
                    let byte = self.char_rom[ascii as usize + (row * 0x101)];
 | 
			
		||||
                    for i in (0..8).rev() {
 | 
			
		||||
                        let buffer_index = ((char_row) * 13 + (row)) * 512 + (char_col * 8 + i);
 | 
			
		||||
                        if (byte << i) & 0x80 == 0x80 {
 | 
			
		||||
                            self.buffer[buffer_index] = FG_COLOR;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            self.buffer[buffer_index] = BG_COLOR;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn draw_hires(&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 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 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,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn run(&mut self) {
 | 
			
		||||
        let frame_duration = Duration::from_millis(16);
 | 
			
		||||
        let mut previous_draw = Instant::now();
 | 
			
		||||
 | 
			
		||||
        loop {
 | 
			
		||||
            if self.window.is_key_down(Key::Q) {
 | 
			
		||||
                return;
 | 
			
		||||
            let mut row0 = 0;
 | 
			
		||||
            let mut row1 = 0;
 | 
			
		||||
            let mut row2 = 0;
 | 
			
		||||
            let mut row3 = 0;
 | 
			
		||||
            let mut row4 = 0;
 | 
			
		||||
            let mut row5 = 0;
 | 
			
		||||
 | 
			
		||||
            self.window.get_keys().iter().for_each(|key| match key {
 | 
			
		||||
                Key::Escape => row0 ^= 0b1000_0000,
 | 
			
		||||
                Key::W => row0 ^= 0b0100_0000,
 | 
			
		||||
                Key::E => row0 ^= 0b0010_0000,
 | 
			
		||||
                Key::R => row0 ^= 0b0001_0000,
 | 
			
		||||
                Key::T => row0 ^= 0b0000_1000,
 | 
			
		||||
                Key::U => row0 ^= 0b0000_0100,
 | 
			
		||||
                Key::O => row0 ^= 0b0000_0010,
 | 
			
		||||
                Key::Backspace => row0 ^= 0b0000_0001,
 | 
			
		||||
                Key::Tab => row1 ^= 0b1000_0000,
 | 
			
		||||
                Key::Q => row1 ^= 0b0100_0000,
 | 
			
		||||
                Key::S => row1 ^= 0b0010_0000,
 | 
			
		||||
                Key::G => row1 ^= 0b0001_0000,
 | 
			
		||||
                Key::Y => row1 ^= 0b0000_1000,
 | 
			
		||||
                Key::I => row1 ^= 0b0000_0100,
 | 
			
		||||
                Key::P => row1 ^= 0b0000_0010,
 | 
			
		||||
                Key::Enter => row1 ^= 0b0000_0001,
 | 
			
		||||
                Key::LeftShift | Key::RightShift => row2 ^= 0b1000_0000,
 | 
			
		||||
                Key::D => row2 ^= 0b0100_0000,
 | 
			
		||||
                Key::V => row2 ^= 0b0010_0000,
 | 
			
		||||
                Key::H => row2 ^= 0b0001_0000,
 | 
			
		||||
                Key::K => row2 ^= 0b0000_1000,
 | 
			
		||||
                Key::Apostrophe => row2 ^= 0b0000_0100,
 | 
			
		||||
                Key::Slash => row2 ^= 0b0000_0010,
 | 
			
		||||
                Key::A => row2 ^= 0b0000_0001,
 | 
			
		||||
                Key::LeftCtrl | Key::RightCtrl => row3 ^= 0b1000_0000,
 | 
			
		||||
                Key::Z => row3 ^= 0b0100_0000,
 | 
			
		||||
                Key::F => row3 ^= 0b0010_0000,
 | 
			
		||||
                Key::B => row3 ^= 0b0001_0000,
 | 
			
		||||
                Key::J => row3 ^= 0b0000_1000,
 | 
			
		||||
                Key::L => row3 ^= 0b0000_0100,
 | 
			
		||||
                Key::Key2 => row3 ^= 0b0000_0010,
 | 
			
		||||
                Key::Key4 => row3 ^= 0b0000_0001,
 | 
			
		||||
                Key::LeftAlt | Key::RightAlt => row4 ^= 0b1000_0000,
 | 
			
		||||
                Key::X => row4 ^= 0b0100_0000,
 | 
			
		||||
                Key::C => row4 ^= 0b0010_0000,
 | 
			
		||||
                Key::N => row4 ^= 0b0001_0000,
 | 
			
		||||
                Key::M => row4 ^= 0b0000_1000,
 | 
			
		||||
                Key::Comma => row4 ^= 0b0000_0100,
 | 
			
		||||
                Key::Key1 => row4 ^= 0b0000_0010,
 | 
			
		||||
                Key::Key3 => row4 ^= 0b0000_0001,
 | 
			
		||||
                Key::LeftSuper => row5 ^= 0b1000_0000,
 | 
			
		||||
                Key::Space => row5 ^= 0b0100_0000,
 | 
			
		||||
                Key::RightSuper => row5 ^= 0b0010_0000,
 | 
			
		||||
                _ => {}
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            match &mut self.memory.lock() {
 | 
			
		||||
                Ok(memory) => {
 | 
			
		||||
                    memory.write(0x4400, row0).unwrap();
 | 
			
		||||
                    memory.write(0x4401, row1).unwrap();
 | 
			
		||||
                    memory.write(0x4402, row2).unwrap();
 | 
			
		||||
                    memory.write(0x4403, row3).unwrap();
 | 
			
		||||
                    memory.write(0x4404, row4).unwrap();
 | 
			
		||||
                    memory.write(0x4405, row5).unwrap();
 | 
			
		||||
                }
 | 
			
		||||
                Err(error) => println!("{error}"),
 | 
			
		||||
            }
 | 
			
		||||
            let now = Instant::now();
 | 
			
		||||
            if now - previous_draw > frame_duration {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue