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,17 +1,36 @@
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};
#[cfg(not(target_arch = "wasm32"))] use std::{fs::File, io::Read};
fn main() {
use std::{fs::File, io::Read};
#[cfg(not(target_arch = "wasm32"))]
fn main() -> io::Result<()> {
use std::io::{stdout, Write};
use georgeemu::cpu::Cpu;
let mut input = stdin();
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( let window = Window::new(
"ʕ·ᴥ·ʔ-☆", "ʕ·ᴥ·ʔ-☆",
512, 512,
@ -35,14 +54,22 @@ fn main() {
let mut file = File::open(path).unwrap(); let mut file = File::open(path).unwrap();
let mut bin = vec![0; 0x8000]; let mut bin = vec![0; 0x8000];
file.read_exact(&mut bin).unwrap(); file.read_exact(&mut bin).unwrap();
// println!("reading char rom");
bin.try_into().unwrap() bin.try_into().unwrap()
} }
None => *include_bytes!("../roms/george.rom"), None => *include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/roms/george.rom")),
}; };
let mut emu = GeorgeEmu::builder().rom(rom).window(window).build(); let mut emu = GeorgeEmu::builder().rom(rom).window(window).build();
emu.run(); 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 {