Skip to content

Commit

Permalink
agon-cli-emulator binary, with some new command line options. sdcard …
Browse files Browse the repository at this point in the history
…update
tomm committed Dec 18, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent f95db96 commit d03c7b2
Showing 11 changed files with 201 additions and 70 deletions.
16 changes: 13 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[workspace]
members = ["agon-light-emulator-debugger"]
members = ["agon-light-emulator-debugger", "agon-ez80-emulator", "agon-cli-emulator"]

[workspace.package]
version = "0.9.75"
version = "0.9.76"
edition = "2021"
authors = ["Tom Morton <[email protected]>"]
license = "GPL-3.0"
@@ -29,7 +29,7 @@ sdl2-sys = "*"
sdl2 = "0.36.0"
pico-args = "0.5.0"
agon-ez80-emulator = { workspace = true }
agon-light-emulator-debugger = { path = "agon-light-emulator-debugger" }
agon-light-emulator-debugger = { workspace = true }
libloading = "0.8.0"
home = "0.5.9"
serialport = "4.3.0"
@@ -42,3 +42,5 @@ raw_tty = "0.1.0"

[workspace.dependencies]
agon-ez80-emulator = { path = "agon-ez80-emulator" }
agon-light-emulator-debugger = { path = "agon-light-emulator-debugger" }
agon-cli-emulator = { path = "agon-cli-emulator" }
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@ else
endif

cargo:
# First build agon-cli emulator
cargo build -r --manifest-path=./agon-cli-emulator/Cargo.toml
ifeq ($(OS),Windows_NT)
set FORCE=1 && cargo build -r
cp ./target/release/fab-agon-emulator.exe .
@@ -54,7 +56,8 @@ ifneq ($(shell ./fab-agon-emulator --prefix),)
install -D -t $(shell ./fab-agon-emulator --prefix)/share/fab-agon-emulator/ firmware/vdp_*.so
install -D -t $(shell ./fab-agon-emulator --prefix)/share/fab-agon-emulator/ firmware/mos_*.bin
install -D -t $(shell ./fab-agon-emulator --prefix)/share/fab-agon-emulator/ firmware/mos_*.map
install -D -t $(shell ./fab-agon-emulator --prefix)/bin/ fab-agon-emulator
install -D -t $(shell ./fab-agon-emulator --prefix)/bin/ target/release/fab-agon-emulator
install -D -t $(shell ./fab-agon-emulator --prefix)/bin/ target/release/agon-cli-emulator
else
@echo "make install requires an install PREFIX (eg PREFIX=/usr/local make)"
endif
14 changes: 14 additions & 0 deletions agon-cli-emulator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "agon-cli-emulator"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true

[dependencies]
agon-ez80-emulator = { workspace = true }
agon-light-emulator-debugger = { workspace = true }
pico-args = "0.5.0"

#[target.'cfg(target_os = "linux")'.dependencies]
#raw_tty = "0.1.0"
167 changes: 106 additions & 61 deletions agon-ez80-emulator/src/bin/agon.rs → agon-cli-emulator/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
mod parse_args;
//use agon_ez80_emulator::debugger;
//use agon_ez80_emulator::debugger::{DebugCmd, DebugResp, DebuggerConnection, Trigger};
use crate::parse_args::parse_args;
use agon_ez80_emulator::{gpio, AgonMachine, AgonMachineConfig, RamInit, SerialLink};
use std::io::{self, BufRead, Write};
use std::sync::mpsc;
@@ -49,7 +53,7 @@ fn handle_vdp(
0x11 => {
rx_from_ez80.recv().unwrap();
} // color
v if v >= 0x20 && v != 0x7f => {
v if v == 8 || (v >= 0x20 && v != 0x7f) => {
//print!("\x1b[0m{}\x1b[90m", char::from_u32(data as u32).unwrap());
print!("{}", char::from_u32(data as u32).unwrap());
}
@@ -123,6 +127,7 @@ fn start_vdp(
tx_vdp_to_ez80: Sender<u8>,
rx_ez80_to_vdp: Receiver<u8>,
gpios: std::sync::Arc<std::sync::Mutex<gpio::GpioSet>>,
emulator_shutdown: std::sync::Arc<std::sync::atomic::AtomicBool>,
) {
let (tx_stdin, rx_stdin): (Sender<String>, Receiver<String>) = mpsc::channel();

@@ -139,7 +144,7 @@ fn start_vdp(
let mut vdp_terminal_mode = false;
let mut last_kb_input = std::time::Instant::now();
let mut last_vsync = std::time::Instant::now();
loop {
while !emulator_shutdown.load(std::sync::atomic::Ordering::Relaxed) {
if !handle_vdp(&tx_vdp_to_ez80, &rx_ez80_to_vdp, &mut vdp_terminal_mode) {
// no packets from ez80. sleep a little
std::thread::sleep(std::time::Duration::from_millis(1));
@@ -216,80 +221,120 @@ impl SerialLink for ChannelSerialLink {
}
}

const PREFIX: Option<&'static str> = option_env!("PREFIX");

fn main() {
let args = match parse_args() {
Ok(a) => a,
Err(e) => {
eprintln!("Error parsing arguments: {}", e);
std::process::exit(-1);
}
};

let (tx_vdp_to_ez80, from_vdp): (Sender<u8>, Receiver<u8>) = mpsc::channel();
let (to_vdp, rx_ez80_to_vdp): (Sender<u8>, Receiver<u8>) = mpsc::channel();
let soft_reset = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let emulator_shutdown = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let gpios = std::sync::Arc::new(std::sync::Mutex::new(gpio::GpioSet::new()));
let exit_status = std::sync::Arc::new(std::sync::atomic::AtomicI32::new(0));
let gpios = std::sync::Arc::new(std::sync::Mutex::new(gpio::GpioSet::new()));
let ez80_paused = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let gpios_ = gpios.clone();

let mut unlimited_cpu = false;
let mut sdcard_img = None;
let mut args: Vec<String> = std::env::args().skip(1).collect();
while args.len() > 0 {
let arg = args.remove(0);
match arg.as_str() {
"-u" | "--unlimited-cpu" => {
unlimited_cpu = true;
}
"--sdcard-img" => {
sdcard_img = if args.len() > 0 {
Some(args.remove(0))
} else {
None
};
}
"--help" | "-h" | _ => {
println!("Usage: agon [OPTIONS]");
println!();
println!("Options:");
println!(" --sdcard-img <filename> Use an SDcard image rather than hostfs");
println!(" -u, --unlimited-cpu Don't limit CPU to Agon Light 18.432MHz");
std::process::exit(0);
}
}
}
/*
let (tx_cmd_debugger, rx_cmd_debugger): (Sender<DebugCmd>, Receiver<DebugCmd>) =
mpsc::channel();
let (tx_resp_debugger, rx_resp_debugger): (Sender<DebugResp>, Receiver<DebugResp>) =
mpsc::channel();
*/

let _cpu_thread = std::thread::spawn(move || {
let _exit_status = exit_status.clone();
let default_firmware = match PREFIX {
None => std::path::Path::new(".")
.join("firmware")
.join("mos_console8.bin"),
Some(prefix) => std::path::Path::new(prefix)
.join("share")
.join("fab-agon-emulator")
.join("mos_console8.bin"),
};

// Preserve stdin state, as debugger can leave stdin in raw mode
//#[cfg(target_os = "linux")]
//let _tty = raw_tty::TtyWithGuard::new(std::io::stdin());

let debugger_con = /*if args.debugger {
let _ez80_paused = ez80_paused.clone();
let mut machine = AgonMachine::new(AgonMachineConfig {
ram_init: RamInit::Random,
uart0_link: Box::new(ChannelSerialLink {
sender: to_vdp,
receiver: from_vdp,
}),
uart1_link: Box::new(DummySerialLink {}),
soft_reset,
exit_status: _exit_status,
paused: _ez80_paused,
emulator_shutdown,
gpios: gpios_,
clockspeed_hz: if unlimited_cpu {
std::u64::MAX
} else {
18_432_000
},
mos_bin: std::path::PathBuf::from("../firmware/mos_console8.bin"),
let _emulator_shutdown = emulator_shutdown.clone();
let _debugger_thread = std::thread::spawn(move || {
agon_light_emulator_debugger::start(
tx_cmd_debugger,
rx_resp_debugger,
_emulator_shutdown,
_ez80_paused.load(std::sync::atomic::Ordering::Relaxed),
);
});
Some(DebuggerConnection {
tx: tx_resp_debugger,
rx: rx_cmd_debugger,
})
} else*/ {
None
};

let _cpu_thread = {
let _exit_status = exit_status.clone();
let _emulator_shutdown = emulator_shutdown.clone();
std::thread::spawn(move || {
let _ez80_paused = ez80_paused.clone();
let mut machine = AgonMachine::new(AgonMachineConfig {
ram_init: if args.zero {
RamInit::Zero
} else {
RamInit::Random
},
uart0_link: Box::new(ChannelSerialLink {
sender: to_vdp,
receiver: from_vdp,
}),
uart1_link: Box::new(DummySerialLink {}),
soft_reset,
exit_status: _exit_status,
paused: _ez80_paused,
emulator_shutdown: _emulator_shutdown,
gpios: gpios_,
clockspeed_hz: if args.unlimited_cpu {
std::u64::MAX
} else {
18_432_000
},
mos_bin: args.mos_bin.unwrap_or(default_firmware),
});

if let Some(f) = sdcard_img {
match std::fs::File::options().read(true).write(true).open(&f) {
Ok(file) => machine.set_sdcard_image(Some(file)),
Err(e) => {
eprintln!("Could not open sdcard image '{}': {:?}", f, e);
std::process::exit(-1);
if let Some(f) = args.sdcard_img {
match std::fs::File::options().read(true).write(true).open(&f) {
Ok(file) => machine.set_sdcard_image(Some(file)),
Err(e) => {
eprintln!("Could not open sdcard image '{}': {:?}", f, e);
std::process::exit(-1);
}
}
} else {
machine.set_sdcard_directory(match args.sdcard {
Some(dir) => std::path::PathBuf::from(dir),
None => std::env::current_dir().unwrap(),
});
}
} else {
machine.set_sdcard_directory(std::env::current_dir().unwrap().join("sdcard"));
}

machine.start(None);
});
machine.start(debugger_con);
});
};

start_vdp(
tx_vdp_to_ez80,
rx_ez80_to_vdp,
gpios,
emulator_shutdown.clone(),
);

start_vdp(tx_vdp_to_ez80, rx_ez80_to_vdp, gpios);
std::process::exit(exit_status.load(std::sync::atomic::Ordering::Relaxed));
}
55 changes: 55 additions & 0 deletions agon-cli-emulator/src/parse_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const HELP: &str = "\
Agon CLI Emulator
USAGE:
agon-cli-emulator [OPTIONS]
OPTIONS:
-h, --help Prints help information
--mos PATH Use a different MOS.bin firmware
--sdcard-img <file> Use a raw SDCard image rather than the host filesystem
--sdcard <path> Sets the path of the emulated SDCard
-u, --unlimited-cpu Don't limit eZ80 CPU frequency
-z, --zero Initialize ram with zeroes instead of random values
";

#[derive(Debug)]
pub struct AppArgs {
//pub debugger: bool,
pub sdcard: Option<String>,
pub sdcard_img: Option<String>,
pub unlimited_cpu: bool,
pub zero: bool,
pub mos_bin: Option<std::path::PathBuf>,
}

pub fn parse_args() -> Result<AppArgs, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();

// for `make install`
if pargs.contains("--prefix") {
print!("{}", option_env!("PREFIX").unwrap_or(""));
std::process::exit(0);
}

if pargs.contains(["-h", "--help"]) {
print!("{}", HELP);
std::process::exit(0);
}

let args = AppArgs {
//debugger: pargs.contains(["-d", "--debugger"]),
sdcard: pargs.opt_value_from_str("--sdcard")?,
sdcard_img: pargs.opt_value_from_str("--sdcard-img")?,
unlimited_cpu: pargs.contains(["-u", "--unlimited_cpu"]),
zero: pargs.contains(["-z", "--zero"]),
mos_bin: pargs.opt_value_from_str("--mos")?,
};

let remaining = pargs.finish();
if !remaining.is_empty() {
eprintln!("Warning: unused arguments left: {:?}.", remaining);
}

Ok(args)
}
1 change: 1 addition & 0 deletions agon-ez80-emulator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -13,3 +13,4 @@ ez80 = { git = "https://github.com/tomm/ez80.git", rev="64558c2acda1464248193f2f
rand = "*"
filetime = "0.2"
chrono = "0.4.38"
pico-args = "0.5.0"
1 change: 0 additions & 1 deletion agon-ez80-emulator/src/debugger.rs
Original file line number Diff line number Diff line change
@@ -140,7 +140,6 @@ impl DebuggerServer {
machine.last_pc
)))
.unwrap();
self.send_disassembly(machine, cpu, None, machine.last_pc, machine.last_pc + 1);
self.send_state(machine, cpu);
}
_ => {}
1 change: 1 addition & 0 deletions dist_scripts/make-dist-linux.sh
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ DIST_DIR=fab-agon-emulator-$VERSION-linux-$ARCH
rm -rf $DIST_DIR
mkdir $DIST_DIR
cp ./target/release/fab-agon-emulator $DIST_DIR
cp ./target/release/agon-cli-emulator $DIST_DIR
cp -r ./firmware $DIST_DIR
cp LICENSE README.md $DIST_DIR
mkdir $DIST_DIR/sdcard
1 change: 1 addition & 0 deletions dist_scripts/make-dist-windows.sh
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ DIST_DIR=fab-agon-emulator-$VERSION-windows-x64
rm -rf $DIST_DIR
mkdir $DIST_DIR
cp ./target/x86_64-pc-windows-gnu/release/fab-agon-emulator.exe $DIST_DIR
cp ./target/x86_64-pc-windows-gnu/release/agon-cli-emulator.exe $DIST_DIR
cp -r ./firmware $DIST_DIR
cp SDL2.dll $DIST_DIR
cp libgcc_s_seh-1.dll $DIST_DIR

0 comments on commit d03c7b2

Please sign in to comment.