enabled piping a program from stdin
This commit is contained in:
		
							parent
							
								
									7d0b66f418
								
							
						
					
					
						commit
						f464dbfaf1
					
				| 
						 | 
				
			
			@ -86,7 +86,11 @@ fn help(command: Option<String>) {
 | 
			
		|||
        println!("  rom, -r, --rom <path>: load a rom/binary from path");
 | 
			
		||||
        println!("  screen, -s, --screen <type>: use the \"terminal\" or \"window\" display type");
 | 
			
		||||
        println!("\nconfiguration:");
 | 
			
		||||
        println!("  george-emu searches for a `george.toml` in the current directory.\n  in `george.toml` you can specify a path for the character rom using the key `char_rom` and the main rom/binary with the key `rom`");
 | 
			
		||||
        println!("  george-emu searches for a `george.toml` in the current directory.\n  in `george.toml` you can specify a path for the character rom\n  using the key `char_rom` and the main rom/binary with the key `rom`");
 | 
			
		||||
        println!("\ndebugging:");
 | 
			
		||||
        println!("  you can pipe in a rom for george to evaluate.");
 | 
			
		||||
        println!("  she'll read it until she reaches a breakpoint (`0x02`) or `stp` instruction,");
 | 
			
		||||
        println!("  then will dump her memory to stdout <3");
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,48 +1,75 @@
 | 
			
		|||
use std::io::{self, stdin, IsTerminal};
 | 
			
		||||
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
mod cli;
 | 
			
		||||
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
use cli::get_input;
 | 
			
		||||
use georgeemu::memory::{Mem, MemHandle};
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
use georgeemu::GeorgeEmu;
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
use minifb::{Scale, ScaleMode, Window, WindowOptions};
 | 
			
		||||
 | 
			
		||||
use std::{fs::File, io::Read};
 | 
			
		||||
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
fn main() {
 | 
			
		||||
    use std::{fs::File, io::Read};
 | 
			
		||||
fn main() -> io::Result<()> {
 | 
			
		||||
    use std::io::{stdout, Write};
 | 
			
		||||
 | 
			
		||||
    let window = Window::new(
 | 
			
		||||
        "ʕ·ᴥ·ʔ-☆",
 | 
			
		||||
        512,
 | 
			
		||||
        380,
 | 
			
		||||
        WindowOptions {
 | 
			
		||||
            resize: true,
 | 
			
		||||
            borderless: true,
 | 
			
		||||
            title: true,
 | 
			
		||||
            transparency: false,
 | 
			
		||||
            scale: Scale::FitScreen,
 | 
			
		||||
            scale_mode: ScaleMode::AspectRatioStretch,
 | 
			
		||||
            topmost: false,
 | 
			
		||||
            none: true,
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    .unwrap();
 | 
			
		||||
    use georgeemu::cpu::Cpu;
 | 
			
		||||
 | 
			
		||||
    let config = get_input();
 | 
			
		||||
    let rom = match config.rom {
 | 
			
		||||
        Some(path) => {
 | 
			
		||||
            let mut file = File::open(path).unwrap();
 | 
			
		||||
            let mut bin = vec![0; 0x8000];
 | 
			
		||||
            file.read_exact(&mut bin).unwrap();
 | 
			
		||||
            // println!("reading char rom");
 | 
			
		||||
            bin.try_into().unwrap()
 | 
			
		||||
        }
 | 
			
		||||
        None => *include_bytes!("../roms/george.rom"),
 | 
			
		||||
    };
 | 
			
		||||
    let mut emu = GeorgeEmu::builder().rom(rom).window(window).build();
 | 
			
		||||
    let mut input = stdin();
 | 
			
		||||
 | 
			
		||||
    emu.run();
 | 
			
		||||
    if !input.is_terminal() {
 | 
			
		||||
        let mut bytes = [0u8; 0x8000];
 | 
			
		||||
        input.read_exact(&mut bytes).unwrap();
 | 
			
		||||
        let memory = make_memory(&bytes);
 | 
			
		||||
        let mut cpu = Cpu::new(memory);
 | 
			
		||||
        let final_output = cpu.run_to_end();
 | 
			
		||||
 | 
			
		||||
        let _ = stdout().write_all(&final_output);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    } else {
 | 
			
		||||
        let window = Window::new(
 | 
			
		||||
            "ʕ·ᴥ·ʔ-☆",
 | 
			
		||||
            512,
 | 
			
		||||
            380,
 | 
			
		||||
            WindowOptions {
 | 
			
		||||
                resize: true,
 | 
			
		||||
                borderless: true,
 | 
			
		||||
                title: true,
 | 
			
		||||
                transparency: false,
 | 
			
		||||
                scale: Scale::FitScreen,
 | 
			
		||||
                scale_mode: ScaleMode::AspectRatioStretch,
 | 
			
		||||
                topmost: false,
 | 
			
		||||
                none: true,
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
        let config = get_input();
 | 
			
		||||
        let rom = match config.rom {
 | 
			
		||||
            Some(path) => {
 | 
			
		||||
                let mut file = File::open(path).unwrap();
 | 
			
		||||
                let mut bin = vec![0; 0x8000];
 | 
			
		||||
                file.read_exact(&mut bin).unwrap();
 | 
			
		||||
                bin.try_into().unwrap()
 | 
			
		||||
            }
 | 
			
		||||
            None => *include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/roms/george.rom")),
 | 
			
		||||
        };
 | 
			
		||||
        let mut emu = GeorgeEmu::builder().rom(rom).window(window).build();
 | 
			
		||||
 | 
			
		||||
        emu.run();
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
fn make_memory(bytes: &[u8]) -> MemHandle {
 | 
			
		||||
    let mut memory = Mem::new();
 | 
			
		||||
    memory.load_bytes(bytes);
 | 
			
		||||
    MemHandle::new(memory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								src/cpu.rs
								
								
								
								
							
							
						
						
									
										34
									
								
								src/cpu.rs
								
								
								
								
							| 
						 | 
				
			
			@ -97,11 +97,18 @@ impl MemoryWriter for Cpu {
 | 
			
		|||
 | 
			
		||||
impl Cpu {
 | 
			
		||||
    pub fn new(memory: MemHandle) -> Self {
 | 
			
		||||
        // reset the cpu on initialization so we don't
 | 
			
		||||
        // scream and cry for two days trying to figure
 | 
			
		||||
        // out why george isn't working <3
 | 
			
		||||
        let low_byte = memory.read(0xFFFC);
 | 
			
		||||
        let high_byte = memory.read(0xFFFD);
 | 
			
		||||
        let pc = (high_byte as u16) << 8 | (low_byte as u16);
 | 
			
		||||
 | 
			
		||||
        Cpu {
 | 
			
		||||
            a: 0x00,
 | 
			
		||||
            x: 0x00,
 | 
			
		||||
            y: 0x00,
 | 
			
		||||
            pc: 0x0000,
 | 
			
		||||
            pc,
 | 
			
		||||
            s: 0xFF,
 | 
			
		||||
            p: 0b0010_0100,
 | 
			
		||||
            irq: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -111,8 +118,7 @@ impl Cpu {
 | 
			
		|||
            debug: false,
 | 
			
		||||
            stopped: false,
 | 
			
		||||
            pending_cycles: 0,
 | 
			
		||||
            cycle: false, // cycle_count: 0,
 | 
			
		||||
                          // state_tx,
 | 
			
		||||
            cycle: false,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self {
 | 
			
		||||
| 
						 | 
				
			
			@ -265,4 +271,26 @@ impl Cpu {
 | 
			
		|||
            self.stop();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn quick_cycle(&mut self) {
 | 
			
		||||
        if !self.get_flag(StatusFlag::IrqDisable) && self.irq {
 | 
			
		||||
            self.interrupt();
 | 
			
		||||
        }
 | 
			
		||||
        let opcode = self.read(self.pc);
 | 
			
		||||
        let instruction = get_instruction(opcode);
 | 
			
		||||
        instruction.call(self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn run_to_end(&mut self) -> [u8; 0x10000] {
 | 
			
		||||
        self.quick_cycle();
 | 
			
		||||
        while self.pending_cycles != 0 {
 | 
			
		||||
            let opcode = self.read(self.pc);
 | 
			
		||||
            let instruction = get_instruction(opcode);
 | 
			
		||||
            match instruction.name {
 | 
			
		||||
                "stp" | "breakpoint" => return self.memory.dump(),
 | 
			
		||||
                _ => self.quick_cycle(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        unreachable!()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1028,14 +1028,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        instr_fn: Some(breakpoint),
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        name: "breakpoint",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        name: "end",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue