added data stack, breakpoints, and character coordinates :)
This commit is contained in:
		
							parent
							
								
									5b9312f643
								
							
						
					
					
						commit
						10559bde8b
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -8,4 +8,5 @@ edition = "2021"
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
bdf = "0.6.0"
 | 
					bdf = "0.6.0"
 | 
				
			||||||
bitvec = "1.0.1"
 | 
					bitvec = "1.0.1"
 | 
				
			||||||
 | 
					iced = { version = "0.12.0", features = ["canvas", "smol"] }
 | 
				
			||||||
minifb = "0.25.0"
 | 
					minifb = "0.25.0"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								src/cpu.rs
								
								
								
								
							
							
						
						
									
										34
									
								
								src/cpu.rs
								
								
								
								
							| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
use crate::error::{ExecutionError, GeorgeError, GeorgeErrorKind, MemoryError};
 | 
					use crate::error::{ExecutionError, GeorgeError, GeorgeErrorKind, MemoryError};
 | 
				
			||||||
use crate::instructions::{get_instruction, Instruction};
 | 
					use crate::instructions::{get_instruction, Instruction};
 | 
				
			||||||
use crate::memory::Mem;
 | 
					use crate::memory::{self, Mem};
 | 
				
			||||||
use crate::types::{Byte, Word};
 | 
					use crate::types::{Byte, Word};
 | 
				
			||||||
 | 
					use std::process::exit;
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    str::FromStr,
 | 
					    str::FromStr,
 | 
				
			||||||
| 
						 | 
					@ -166,7 +167,7 @@ impl Cpu {
 | 
				
			||||||
    //     }
 | 
					    //     }
 | 
				
			||||||
    // }
 | 
					    // }
 | 
				
			||||||
    pub fn cycle(&mut self) -> Result<(), GeorgeError> {
 | 
					    pub fn cycle(&mut self) -> Result<(), GeorgeError> {
 | 
				
			||||||
        sleep(Duration::from_nanos(500));
 | 
					        sleep(Duration::from_nanos(100));
 | 
				
			||||||
        if self.pending_cycles == 0 {
 | 
					        if self.pending_cycles == 0 {
 | 
				
			||||||
            if self.nmi || (self.irq && !self.get_flag(StatusFlag::IrqDisable)) {
 | 
					            if self.nmi || (self.irq && !self.get_flag(StatusFlag::IrqDisable)) {
 | 
				
			||||||
                let _ = self.push_stack_word(self.pc);
 | 
					                let _ = self.push_stack_word(self.pc);
 | 
				
			||||||
| 
						 | 
					@ -228,15 +229,32 @@ impl Cpu {
 | 
				
			||||||
                                          self.pc, valid_instruction).to_string(), kind: error})
 | 
					                                          self.pc, valid_instruction).to_string(), kind: error})
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Instruction::Invalid(invalid_instruction) => {
 | 
					                Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode {
 | 
				
			||||||
                    return Err(GeorgeError {
 | 
					                    0x02 => {
 | 
				
			||||||
                        kind: GeorgeErrorKind::Execution(ExecutionError::InvalidInstruction),
 | 
					                        let memory = match self.memory.try_read() {
 | 
				
			||||||
                        desc: format!(
 | 
					                            Ok(read) => read,
 | 
				
			||||||
 | 
					                            Err(_) => {
 | 
				
			||||||
 | 
					                                println!("Couldn't acquire read lock on memory in cpu thread");
 | 
				
			||||||
 | 
					                                return Err(GeorgeError {
 | 
				
			||||||
 | 
					                                    kind: GeorgeErrorKind::Memory(MemoryError::Unwritable),
 | 
				
			||||||
 | 
					                                    desc: "Couldn't acquire read lock on memory in cpu thread"
 | 
				
			||||||
 | 
					                                        .to_string(),
 | 
				
			||||||
 | 
					                                });
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                        memory.dump().unwrap();
 | 
				
			||||||
 | 
					                        exit(1);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    _ => {
 | 
				
			||||||
 | 
					                        return Err(GeorgeError {
 | 
				
			||||||
 | 
					                            kind: GeorgeErrorKind::Execution(ExecutionError::InvalidInstruction),
 | 
				
			||||||
 | 
					                            desc: format!(
 | 
				
			||||||
                        "An invalid instruction with opcode {:#04x} was called at address {:#06x}",
 | 
					                        "An invalid instruction with opcode {:#04x} was called at address {:#06x}",
 | 
				
			||||||
                        invalid_instruction.opcode, self.pc
 | 
					                        invalid_instruction.opcode, self.pc
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    })
 | 
					                        });
 | 
				
			||||||
                }
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.pending_cycles -= 1;
 | 
					        self.pending_cycles -= 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								src/george
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								src/george
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										221
									
								
								src/george.asm
								
								
								
								
							
							
						
						
									
										221
									
								
								src/george.asm
								
								
								
								
							| 
						 | 
					@ -1,25 +1,204 @@
 | 
				
			||||||
.setcpu "65C02"
 | 
					.setcpu "65C02"
 | 
				
			||||||
.segment "CODE"
 | 
					.segment "CODE"
 | 
				
			||||||
LDA #$60
 | 
					
 | 
				
			||||||
STA $01
 | 
					; okay so rn i wanna set up a very basic system init, and write a few subroutines to draw characters at x,y coordinates
 | 
				
			||||||
LDY #$0
 | 
					    n = $01 ; temporary storage for data stack operations
 | 
				
			||||||
fill:
 | 
					
 | 
				
			||||||
    LDA #$20
 | 
					.macro breakpoint ; $02 isn't a valid instruction, the emulator will see this and halt, dump memory contents
 | 
				
			||||||
    STY $00
 | 
					    .byte $02
 | 
				
			||||||
    STA ($00)
 | 
					.endmacro 
 | 
				
			||||||
    INY
 | 
					
 | 
				
			||||||
    CPY #$ff
 | 
					.macro pop ; drops a stack cell
 | 
				
			||||||
    BNE fill
 | 
					    inx
 | 
				
			||||||
 | 
					    inx
 | 
				
			||||||
 | 
					.endmacro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.macro pop2 ; drops 2 data stack cells
 | 
				
			||||||
 | 
					    inx
 | 
				
			||||||
 | 
					    inx
 | 
				
			||||||
 | 
					    inx
 | 
				
			||||||
 | 
					    inx
 | 
				
			||||||
 | 
					.endmacro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.macro push ; 
 | 
				
			||||||
 | 
					    dex
 | 
				
			||||||
 | 
					    dex
 | 
				
			||||||
 | 
					.endmacro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.macro push2 ; 
 | 
				
			||||||
 | 
					    dex
 | 
				
			||||||
 | 
					    dex
 | 
				
			||||||
 | 
					    dex
 | 
				
			||||||
 | 
					    dex
 | 
				
			||||||
 | 
					.endmacro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.macro to_r ; pop the top of the stack off and save it in the return (hardware) stack: (n -- )
 | 
				
			||||||
 | 
					    lda 1, x
 | 
				
			||||||
 | 
					    pha
 | 
				
			||||||
 | 
					    lda 0, x
 | 
				
			||||||
 | 
					    pha
 | 
				
			||||||
 | 
					    pop
 | 
				
			||||||
 | 
					.endmacro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.macro from_r ; pop the top of the return stack off and put it on the data stack: ( -- n)
 | 
				
			||||||
 | 
					    push
 | 
				
			||||||
 | 
					    pla
 | 
				
			||||||
 | 
					    sta 0, x
 | 
				
			||||||
 | 
					    pla
 | 
				
			||||||
 | 
					    sta 1, x
 | 
				
			||||||
 | 
					.endmacro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					init:
 | 
				
			||||||
 | 
					    ldx #0; initialize data stack pointer
 | 
				
			||||||
 | 
					    jsr initdisplay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main:
 | 
					main:
 | 
				
			||||||
    LDY #$0
 | 
					    jsr draw
 | 
				
			||||||
    STY $6000
 | 
					
 | 
				
			||||||
    LDY #$1
 | 
					initdisplay:
 | 
				
			||||||
    STY $6001
 | 
					    lda #$20
 | 
				
			||||||
    LDY #$2
 | 
					    ldy #0
 | 
				
			||||||
    STY $6002
 | 
					    jsr cleardisplay
 | 
				
			||||||
    LDY #$1
 | 
					    rts
 | 
				
			||||||
    STY $6003
 | 
					
 | 
				
			||||||
    LDY #$3
 | 
					cleardisplay:
 | 
				
			||||||
    STY $6004
 | 
					    sta $6000,y
 | 
				
			||||||
    JMP main
 | 
					    sta $6100,y
 | 
				
			||||||
 | 
					    sta $6200,y
 | 
				
			||||||
 | 
					    sta $6300,y
 | 
				
			||||||
 | 
					    sta $6400,y
 | 
				
			||||||
 | 
					    sta $6500,y
 | 
				
			||||||
 | 
					    sta $6600,y
 | 
				
			||||||
 | 
					    sta $6700,y ; this goes slightly over but it's fine
 | 
				
			||||||
 | 
					    iny
 | 
				
			||||||
 | 
					    bne cleardisplay
 | 
				
			||||||
 | 
					    rts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; TODO: get this to work, (also i think emu-side i need better tooling), rn it just draws a heart to $6000, so i think the addition isn't working or something
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					    lda #64
 | 
				
			||||||
 | 
					    push ; doing this instead until `push_lit` is fixed
 | 
				
			||||||
 | 
					    sta 0, x
 | 
				
			||||||
 | 
					    stz 1, x
 | 
				
			||||||
 | 
					    jsr mult ; multiply 64 with y (n2)
 | 
				
			||||||
 | 
					    jsr plus ; add result with x (n1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ;jsr push_lit ; push vram address onto the stack
 | 
				
			||||||
 | 
					    ;.byte $00
 | 
				
			||||||
 | 
					    ;.byte $60
 | 
				
			||||||
 | 
					    lda #$60
 | 
				
			||||||
 | 
					    push
 | 
				
			||||||
 | 
					    sta 1, x
 | 
				
			||||||
 | 
					    stz 0, x
 | 
				
			||||||
 | 
					    jsr plus ; add vram start address to result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rts
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					; inc16
 | 
				
			||||||
 | 
					; add 1 to a 16-bit pointer in zero page
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;inc16:
 | 
				
			||||||
 | 
					;    inc ptr
 | 
				
			||||||
 | 
					;    bne :+
 | 
				
			||||||
 | 
					;    inc ptr+1
 | 
				
			||||||
 | 
					;:   rts
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; on this channel we love garth wilson: https://wilsonminesco.com/stacks/StackOps.ASM
 | 
				
			||||||
 | 
					; data stack is built up of 2-byte cells
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; TODO: this is broken, the return address gets mangled somewhere in here, could be an emulator problem tho
 | 
				
			||||||
 | 
					push_lit: ; this bad boy lets you inline a literal (low byte first) right after `jsr push_lit` and put it on the stack, once again, on this channel we love garth wilson
 | 
				
			||||||
 | 
					   push2
 | 
				
			||||||
 | 
					   phx
 | 
				
			||||||
 | 
					       tsx
 | 
				
			||||||
 | 
					       txa
 | 
				
			||||||
 | 
					       tay
 | 
				
			||||||
 | 
					   plx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   lda $102, y
 | 
				
			||||||
 | 
					   sta 0, x
 | 
				
			||||||
 | 
					   clc
 | 
				
			||||||
 | 
					   adc #2
 | 
				
			||||||
 | 
					   sta $102, y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   lda $103, y
 | 
				
			||||||
 | 
					   sta 1, x
 | 
				
			||||||
 | 
					   adc #0
 | 
				
			||||||
 | 
					   sta $103, y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fetch: 
 | 
				
			||||||
 | 
					    lda (0, x)
 | 
				
			||||||
 | 
					    pha
 | 
				
			||||||
 | 
					    inc 0, x
 | 
				
			||||||
 | 
					    bne @1
 | 
				
			||||||
 | 
					    inc 1, x
 | 
				
			||||||
 | 
					@1:     lda (0, x)
 | 
				
			||||||
 | 
					        bra put
 | 
				
			||||||
 | 
					    push
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					put:
 | 
				
			||||||
 | 
					    sta 1, x
 | 
				
			||||||
 | 
					    pla
 | 
				
			||||||
 | 
					    sta 0, x
 | 
				
			||||||
 | 
					    rts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					plus: ; add: (n1 n2 -- n1+n2)
 | 
				
			||||||
 | 
					    clc
 | 
				
			||||||
 | 
					    lda 0, x
 | 
				
			||||||
 | 
					    adc 2, x
 | 
				
			||||||
 | 
					    sta 2, x
 | 
				
			||||||
 | 
					    lda 1, x
 | 
				
			||||||
 | 
					    adc 3, x
 | 
				
			||||||
 | 
					    sta 3, x
 | 
				
			||||||
 | 
					    pop
 | 
				
			||||||
 | 
					    rts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mult: ; multiply: (n1 n2 -- n1*n2), frankly, i don't know how this works, but TODO: will try to figure it out later
 | 
				
			||||||
 | 
					    phy
 | 
				
			||||||
 | 
					    stz n
 | 
				
			||||||
 | 
					    ldy #0
 | 
				
			||||||
 | 
					@1:     lsr 3, x
 | 
				
			||||||
 | 
					        ror 2, x
 | 
				
			||||||
 | 
					        bcc @2
 | 
				
			||||||
 | 
					            clc
 | 
				
			||||||
 | 
					            lda n
 | 
				
			||||||
 | 
					            adc 0, x
 | 
				
			||||||
 | 
					            sta n
 | 
				
			||||||
 | 
					            tya
 | 
				
			||||||
 | 
					            adc 1, x
 | 
				
			||||||
 | 
					            tay
 | 
				
			||||||
 | 
					@2:     asl 0, x
 | 
				
			||||||
 | 
					        rol 1, x
 | 
				
			||||||
 | 
					        lda 2, x
 | 
				
			||||||
 | 
					        ora 3, x
 | 
				
			||||||
 | 
					    bne @1
 | 
				
			||||||
 | 
					    lda n
 | 
				
			||||||
 | 
					    sta 2, x
 | 
				
			||||||
 | 
					    sty 3, x
 | 
				
			||||||
 | 
					    pop
 | 
				
			||||||
 | 
					    ply
 | 
				
			||||||
 | 
					    rts
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.segment "VRAM"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,4 +8,5 @@ MEMORY {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SEGMENTS {
 | 
					SEGMENTS {
 | 
				
			||||||
        CODE: load = "PROGRAM", type = rw;
 | 
					        CODE: load = "PROGRAM", type = rw;
 | 
				
			||||||
 | 
					        VRAM: load = "VRAM", type = rw;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1900,7 +1900,7 @@ fn get_address(
 | 
				
			||||||
    ) -> Result<AddressingModeValue, ExecutionError> {
 | 
					    ) -> Result<AddressingModeValue, ExecutionError> {
 | 
				
			||||||
        let byte = cpu.read(cpu.pc)?;
 | 
					        let byte = cpu.read(cpu.pc)?;
 | 
				
			||||||
        cpu.pc += 1;
 | 
					        cpu.pc += 1;
 | 
				
			||||||
        let address: Word = (byte + cpu.x) as Word;
 | 
					        let address: Word = (byte.wrapping_add(cpu.x)) as Word;
 | 
				
			||||||
        Ok(AddressingModeValue::Absolute(address))
 | 
					        Ok(AddressingModeValue::Absolute(address))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2072,6 +2072,7 @@ impl Opcode {
 | 
				
			||||||
                        // check out https://docs.rs/emulator_6502/latest/src/emulator_6502/opcodes/mod.rs.html
 | 
					                        // check out https://docs.rs/emulator_6502/latest/src/emulator_6502/opcodes/mod.rs.html
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(result as Byte));
 | 
					                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(result as Byte));
 | 
				
			||||||
 | 
					                    cpu.a = result as Byte;
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(GeorgeErrorKind::AddrMode(
 | 
					                _ => Err(GeorgeErrorKind::AddrMode(
 | 
				
			||||||
| 
						 | 
					@ -2607,7 +2608,7 @@ impl Opcode {
 | 
				
			||||||
                    let byte = cpu.read(address.try_into()?)?;
 | 
					                    let byte = cpu.read(address.try_into()?)?;
 | 
				
			||||||
                    cpu.set_flag(StatusFlag::Carry, cpu.a >= byte);
 | 
					                    cpu.set_flag(StatusFlag::Carry, cpu.a >= byte);
 | 
				
			||||||
                    cpu.set_flag(StatusFlag::Zero, cpu.a == byte);
 | 
					                    cpu.set_flag(StatusFlag::Zero, cpu.a == byte);
 | 
				
			||||||
                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a - byte));
 | 
					                    cpu.set_flag(StatusFlag::Negative, cpu.a <= byte);
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(GeorgeErrorKind::AddrMode(
 | 
					                _ => Err(GeorgeErrorKind::AddrMode(
 | 
				
			||||||
| 
						 | 
					@ -2660,7 +2661,7 @@ impl Opcode {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Opcode::DEX(mode) => match mode {
 | 
					            Opcode::DEX(mode) => match mode {
 | 
				
			||||||
                AddressingMode::Implied => {
 | 
					                AddressingMode::Implied => {
 | 
				
			||||||
                    cpu.x -= 1;
 | 
					                    cpu.x = cpu.x.wrapping_sub(1);
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(GeorgeErrorKind::AddrMode(
 | 
					                _ => Err(GeorgeErrorKind::AddrMode(
 | 
				
			||||||
| 
						 | 
					@ -2698,7 +2699,7 @@ impl Opcode {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Opcode::INC(mode) => match mode {
 | 
					            Opcode::INC(mode) => match mode {
 | 
				
			||||||
                AddressingMode::Accumulator => {
 | 
					                AddressingMode::Accumulator => {
 | 
				
			||||||
                    cpu.a += 1;
 | 
					                    cpu.a = cpu.a.wrapping_add(1);
 | 
				
			||||||
                    cpu.set_flag(StatusFlag::Zero, cpu.a == 0);
 | 
					                    cpu.set_flag(StatusFlag::Zero, cpu.a == 0);
 | 
				
			||||||
                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a));
 | 
					                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a));
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
| 
						 | 
					@ -2720,7 +2721,9 @@ impl Opcode {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Opcode::INX(mode) => match mode {
 | 
					            Opcode::INX(mode) => match mode {
 | 
				
			||||||
                AddressingMode::Implied => {
 | 
					                AddressingMode::Implied => {
 | 
				
			||||||
                    cpu.x += 1;
 | 
					                    cpu.x = cpu.x.wrapping_add(1);
 | 
				
			||||||
 | 
					                    cpu.set_flag(StatusFlag::Zero, cpu.x == 0);
 | 
				
			||||||
 | 
					                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.x));
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(GeorgeErrorKind::AddrMode(
 | 
					                _ => Err(GeorgeErrorKind::AddrMode(
 | 
				
			||||||
| 
						 | 
					@ -2729,7 +2732,9 @@ impl Opcode {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Opcode::INY(mode) => match mode {
 | 
					            Opcode::INY(mode) => match mode {
 | 
				
			||||||
                AddressingMode::Implied => {
 | 
					                AddressingMode::Implied => {
 | 
				
			||||||
                    cpu.y += 1;
 | 
					                    cpu.y = cpu.y.wrapping_add(1);
 | 
				
			||||||
 | 
					                    cpu.set_flag(StatusFlag::Zero, cpu.y == 0);
 | 
				
			||||||
 | 
					                    cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.y));
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(GeorgeErrorKind::AddrMode(
 | 
					                _ => Err(GeorgeErrorKind::AddrMode(
 | 
				
			||||||
| 
						 | 
					@ -3113,9 +3118,9 @@ impl Opcode {
 | 
				
			||||||
                )),
 | 
					                )),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Opcode::RTS(mode) => match mode {
 | 
					            Opcode::RTS(mode) => match mode {
 | 
				
			||||||
                AddressingMode::Implied => {
 | 
					                AddressingMode::Stack => {
 | 
				
			||||||
                    let return_address = cpu.pop_stack_word()?;
 | 
					                    let return_address = cpu.pop_stack_word()?;
 | 
				
			||||||
                    cpu.pc = return_address + 1;
 | 
					                    cpu.pc = return_address + 3; // Go back to where we jsr'ed, skipping the operand
 | 
				
			||||||
                    Ok(())
 | 
					                    Ok(())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(GeorgeErrorKind::AddrMode(
 | 
					                _ => Err(GeorgeErrorKind::AddrMode(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,4 +56,5 @@ fn main() {
 | 
				
			||||||
        cpu.execute();
 | 
					        cpu.execute();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    screen.run();
 | 
					    screen.run();
 | 
				
			||||||
 | 
					    shared_memory.write().unwrap().dump().unwrap();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
use crate::error::{GeorgeError, GeorgeErrorKind, MappingError, MemoryError};
 | 
					use crate::error::{GeorgeError, GeorgeErrorKind, MappingError, MemoryError};
 | 
				
			||||||
use crate::types::{Byte, Word};
 | 
					use crate::types::{Byte, Word};
 | 
				
			||||||
 | 
					use std::io::{self, Write};
 | 
				
			||||||
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::{fs::File, io::Read};
 | 
					use std::{fs::File, io::Read};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
| 
						 | 
					@ -59,6 +61,18 @@ impl Mem {
 | 
				
			||||||
    pub fn new(area: MemMappedDevice) -> Self {
 | 
					    pub fn new(area: MemMappedDevice) -> Self {
 | 
				
			||||||
        Self { areas: vec![area] }
 | 
					        Self { areas: vec![area] }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn dump(&self) -> io::Result<()> {
 | 
				
			||||||
 | 
					        let mut outfile = File::create("./coredump.bin")?;
 | 
				
			||||||
 | 
					        let mut data = Vec::new();
 | 
				
			||||||
 | 
					        for area in &self.areas {
 | 
				
			||||||
 | 
					            for byte in &area.data {
 | 
				
			||||||
 | 
					                data.push(byte.to_owned());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        outfile.set_len(0xFFFF)?;
 | 
				
			||||||
 | 
					        outfile.write_all(&data)?;
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn add_area(&mut self, area: MemMappedDevice) -> Result<(), GeorgeError> {
 | 
					    pub fn add_area(&mut self, area: MemMappedDevice) -> Result<(), GeorgeError> {
 | 
				
			||||||
        for existing_area in &self.areas {
 | 
					        for existing_area in &self.areas {
 | 
				
			||||||
            if existing_area.contains(area.end) || existing_area.contains(area.start) {
 | 
					            if existing_area.contains(area.end) || existing_area.contains(area.start) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/video.rs
								
								
								
								
							
							
						
						
									
										31
									
								
								src/video.rs
								
								
								
								
							| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
use crate::Mem;
 | 
					use crate::Mem;
 | 
				
			||||||
use minifb::{Window, WindowOptions};
 | 
					use minifb::{Key, Scale, ScaleMode, Window, WindowOptions};
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    fs::File,
 | 
					    fs::File,
 | 
				
			||||||
    io::Read,
 | 
					    io::Read,
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,22 @@ pub fn get_char_bin(path: &str) -> Vec<u8> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Crtc {
 | 
					impl Crtc {
 | 
				
			||||||
    pub fn new(memory: Arc<RwLock<Mem>>) -> Self {
 | 
					    pub fn new(memory: Arc<RwLock<Mem>>) -> Self {
 | 
				
			||||||
        let window = Window::new("screen", 512, 380, WindowOptions::default()).unwrap();
 | 
					        let window = Window::new(
 | 
				
			||||||
 | 
					            "ʕ·ᴥ·ʔ-☆",
 | 
				
			||||||
 | 
					            512,
 | 
				
			||||||
 | 
					            380,
 | 
				
			||||||
 | 
					            WindowOptions {
 | 
				
			||||||
 | 
					                resize: true,
 | 
				
			||||||
 | 
					                borderless: true,
 | 
				
			||||||
 | 
					                title: true,
 | 
				
			||||||
 | 
					                transparency: false,
 | 
				
			||||||
 | 
					                scale: Scale::X2,
 | 
				
			||||||
 | 
					                scale_mode: ScaleMode::AspectRatioStretch,
 | 
				
			||||||
 | 
					                topmost: false,
 | 
				
			||||||
 | 
					                none: true,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
        let char_rom = get_char_bin("./src/cozette.bin");
 | 
					        let char_rom = get_char_bin("./src/cozette.bin");
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            memory,
 | 
					            memory,
 | 
				
			||||||
| 
						 | 
					@ -64,11 +79,14 @@ impl Crtc {
 | 
				
			||||||
                return;
 | 
					                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_row in 0..29 {
 | 
				
			||||||
            for char_col in 0..64 {
 | 
					            for char_col in 0..64 {
 | 
				
			||||||
                let ascii = memory
 | 
					                let ascii = memory.read(0x6000 + i).unwrap();
 | 
				
			||||||
                    .read(0x6000 + (char_row as u16 * char_col as u16))
 | 
					                i += 1;
 | 
				
			||||||
                    .unwrap();
 | 
					 | 
				
			||||||
                for row in 0..13 {
 | 
					                for row in 0..13 {
 | 
				
			||||||
                    let byte = self.char_rom[ascii as usize + (row * 0x101)];
 | 
					                    let byte = self.char_rom[ascii as usize + (row * 0x101)];
 | 
				
			||||||
                    for i in (0..8).rev() {
 | 
					                    for i in (0..8).rev() {
 | 
				
			||||||
| 
						 | 
					@ -108,6 +126,9 @@ impl Crtc {
 | 
				
			||||||
        let mut previous_draw = Instant::now();
 | 
					        let mut previous_draw = Instant::now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        loop {
 | 
					        loop {
 | 
				
			||||||
 | 
					            if self.window.is_key_down(Key::Q) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            let now = Instant::now();
 | 
					            let now = Instant::now();
 | 
				
			||||||
            if now - previous_draw > frame_duration {
 | 
					            if now - previous_draw > frame_duration {
 | 
				
			||||||
                self.draw();
 | 
					                self.draw();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue