use arg::Args;
use log::{Level, LevelFilter, Metadata, Record};
use std::{cell::RefCell, ops::ControlFlow, rc::Rc};
use librsmsx::{
dev::{api::ret_no_hook, util::peek_stack},
prelude::*,
};
const SYSTEM_ROM_FILE: &str = "cbios_main_msx1.rom";
#[derive(Args, Debug)]
struct MyArgs {
#[arg(long)]
cart: String,
#[arg(long = "sys")]
system_rom: String,
#[arg(long, default_value = "true")]
quality: bool,
#[arg(long = "fint", default_value = "16")]
frame_interval: u32,
#[arg(long)]
mtype: String,
}
static MY_LOGGER: MyLogger = MyLogger;
struct MyLogger;
impl log::Log for MyLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= Level::Debug
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
println!("{} - {}", record.level(), record.args());
}
if record.metadata().level() == Level::Error {
panic!();
}
}
fn flush(&self) {}
}
pub struct SampleHook {
calls: u64,
}
impl Default for SampleHook {
fn default() -> Self {
Self::new()
}
}
impl SampleHook {
pub(crate) fn new() -> Self {
Self { calls: 0 }
}
}
impl FuncHook for SampleHook {
fn handle_generic_hook(
&mut self,
data: &mut Z80Data,
memory: &mut Memory,
_ports: &mut Ports,
) -> ControlFlow<()> {
if data.pc() == 0x89c7 {
println!("HGH: pc:0x{:04x} hl:0x{:04x}", data.pc(), data.hl());
let mut addr = data.hl();
loop {
let ch = memory.read_byte(addr);
if ch == 0 {
break;
}
print!("{}", ch as char);
addr += 1;
}
println!();
peek_stack(data, memory, 10);
ret_no_hook(data, memory);
ControlFlow::Continue(()) } else {
ControlFlow::Break(()) }
}
fn handle_call_hook(
&mut self,
_data: &mut Z80Data,
_memory: &mut Memory,
_ports: &mut Ports,
new_pc: u16,
_old_pc: u16,
) -> ControlFlow<()> {
if new_pc == 0xb181 {
println!("regs before: {:?}", _data);
}
self.calls += 1;
if new_pc == 0xb181 {
println!("new call hook #:{} 0x{:04x}", self.calls, new_pc);
println!("regs after: {:?}", _data);
panic!();
}
ControlFlow::Continue(())
}
fn handle_ret_hook(&mut self, _data: &mut Z80Data, _memory: &mut Memory, _next_pc: u16) {}
fn handle_command_hook(
&mut self,
_data: &mut Z80Data,
_memory: &mut Memory,
_ports: &mut Ports,
mode: u64,
) {
println!("debug mode #:{}", mode);
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
log::set_logger(&MY_LOGGER).unwrap();
log::set_max_level(LevelFilter::Debug);
let args: std::vec::Vec<_> = std::env::args().skip(1).collect();
match MyArgs::from_args(args.iter().map(|x| x.as_str())) {
Ok(mut args) => {
if args.system_rom.is_empty() {
args.system_rom = SYSTEM_ROM_FILE.to_string();
}
let base_scale = 2.0;
let scale_magnifier = 2.0;
let mut sys = BaseSystem::new(base_scale * scale_magnifier);
let ppi = Rc::new(RefCell::new(PPI::new()));
let mut memory = Memory::new(ppi.clone());
memory.load_bios_basic(&args.system_rom);
if !args.cart.is_empty() {
memory.load_rom(&args.cart, 1, &args.mtype);
}
let psg = PSG::new(SoundType::Normal, Some(&mut sys));
let vdp = Rc::new(RefCell::new(Vdp::new(GraphicsType::Normal, args.quality)));
let ports = Ports::new(vdp.clone(), ppi.clone(), psg);
let mut cpu_z80 = Z80::new(memory, ports);
cpu_z80.set_hook(Rc::new(RefCell::new(SampleHook::new())));
cpu_z80.reboot();
let mut msx = MSX::new(
cpu_z80,
vdp.clone(),
);
let avg_fps = msx.main_loop(args.frame_interval as isize, &mut sys);
log::info!("Avg FPS: {:.2}", avg_fps);
}
Err(err) => println!("err={:?}", err),
}
Ok(())
}