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!(" 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
34
src/cpu.rs
34
src/cpu.rs
|
@ -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!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue