enabled piping a program from stdin

This commit is contained in:
august kline 2024-09-26 21:08:45 -04:00
parent 7d0b66f418
commit f464dbfaf1
4 changed files with 96 additions and 37 deletions

View File

@ -86,7 +86,11 @@ fn help(command: Option<String>) {
println!(" rom, -r, --rom <path>: load a rom/binary from path"); println!(" rom, -r, --rom <path>: load a rom/binary from path");
println!(" screen, -s, --screen <type>: use the \"terminal\" or \"window\" display type"); println!(" screen, -s, --screen <type>: use the \"terminal\" or \"window\" display type");
println!("\nconfiguration:"); 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); exit(0);
} }
} }

View File

@ -1,48 +1,75 @@
use std::io::{self, stdin, IsTerminal};
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
mod cli; mod cli;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use cli::get_input; use cli::get_input;
use georgeemu::memory::{Mem, MemHandle};
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use georgeemu::GeorgeEmu; use georgeemu::GeorgeEmu;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use minifb::{Scale, ScaleMode, Window, WindowOptions}; use minifb::{Scale, ScaleMode, Window, WindowOptions};
use std::{fs::File, io::Read};
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn main() { fn main() -> io::Result<()> {
use std::{fs::File, io::Read}; use std::io::{stdout, Write};
let window = Window::new( use georgeemu::cpu::Cpu;
"ʕ·ᴥ·ʔ-☆",
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 mut input = stdin();
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();
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")] #[cfg(target_arch = "wasm32")]

View File

@ -97,11 +97,18 @@ impl MemoryWriter for Cpu {
impl Cpu { impl Cpu {
pub fn new(memory: MemHandle) -> Self { 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 { Cpu {
a: 0x00, a: 0x00,
x: 0x00, x: 0x00,
y: 0x00, y: 0x00,
pc: 0x0000, pc,
s: 0xFF, s: 0xFF,
p: 0b0010_0100, p: 0b0010_0100,
irq: false, irq: false,
@ -111,8 +118,7 @@ impl Cpu {
debug: false, debug: false,
stopped: false, stopped: false,
pending_cycles: 0, pending_cycles: 0,
cycle: false, // cycle_count: 0, cycle: false,
// state_tx,
} }
} }
pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self { pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self {
@ -265,4 +271,26 @@ impl Cpu {
self.stop(); 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!()
}
} }

View File

@ -1028,14 +1028,14 @@ pub const OPCODES: [Instruction; 256] = [
instr_fn: Some(breakpoint), instr_fn: Some(breakpoint),
address_fn: None, address_fn: None,
cycles: 0, cycles: 0,
name: "none", name: "breakpoint",
addr_mode: "implied", addr_mode: "implied",
}, },
Instruction { Instruction {
instr_fn: None, instr_fn: None,
address_fn: None, address_fn: None,
cycles: 0, cycles: 0,
name: "none", name: "end",
addr_mode: "implied", addr_mode: "implied",
}, },
Instruction { Instruction {