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!(" 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);
}
}

View File

@ -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")]

View File

@ -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!()
}
}

View File

@ -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 {