aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorAstatin <[email protected]>2024-09-14 23:49:32 +0900
committerAstatin <astatin@redacted>2024-09-14 23:49:32 +0900
commit7101d14f3bcc0af29b8d51b1f5d58689fee1a571 (patch)
treef0d24574e6ec3153a3f4a5969233946be43719a6 /src/main.rs
parent249921a2094d172e94543446e2af11dcba5075e8 (diff)
Add keyboard support & start supporting serial communication (but tetris doesn't work in 2p)
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs83
1 files changed, 43 insertions, 40 deletions
diff --git a/src/main.rs b/src/main.rs
index f0a7361..b057486 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,38 +5,15 @@ pub mod gamepad;
pub mod interrupts_timers;
pub mod io;
pub mod opcodes;
+pub mod serial;
pub mod state;
-use crate::gamepad::Gamepad;
-use crate::state::{GBState, MemError};
+use crate::gamepad::{Gamepad, Input};
+use crate::state::GBState;
use clap::Parser;
use std::time::SystemTime;
use std::{thread, time};
-pub fn exec_opcode(state: &mut GBState) -> Result<u64, MemError> {
- let opcode = state.mem.r(state.cpu.pc)?;
-
- if state.is_debug {
- println!(
- "{:02x}:{:04x} = {:02x} (IME: {})",
- state.mem.rom_bank, state.cpu.pc, opcode, state.mem.ime
- );
- }
-
- state.cpu.pc += 1;
-
- let n1 = (opcode >> 3) & 0b111;
- let n2 = opcode & 0b111;
-
- match opcode >> 6 {
- 0b00 => opcodes::op00(state, n1, n2),
- 0b01 => opcodes::op01(state, n1, n2),
- 0b10 => opcodes::op10(state, n1, n2),
- 0b11 => opcodes::op11(state, n1, n2),
- _ => panic!(),
- }
-}
-
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
@@ -45,7 +22,16 @@ struct Cli {
/// Setting this saves battery by using thread::sleep instead of spin_sleeping. It can result in lag and inconsistent timing.
#[arg(long)]
- thread_sleep: bool,
+ loop_lock_timing: bool,
+
+ #[arg(long)]
+ fifo_input: Option<String>,
+
+ #[arg(long)]
+ fifo_output: Option<String>,
+
+ #[arg(short, long, default_value_t = false)]
+ keyboard: bool,
#[arg(short, long, default_value_t = 1.0)]
speed: f32,
@@ -56,11 +42,17 @@ fn main() {
println!("Initializing Gamepad...");
- let mut gamepad = Gamepad::new();
-
println!("Starting {:?}...", &cli.rom);
- let mut state = GBState::new();
+ let mut state = match (cli.fifo_input, cli.fifo_output) {
+ (Some(fifo_input), Some(fifo_output)) => {
+ GBState::new(Box::new(serial::FIFOSerial::new(fifo_input, fifo_output)))
+ }
+ (None, None) => GBState::new(Box::new(serial::UnconnectedSerial {})),
+ _ => panic!("If using fifo serial, both input and output should be set"),
+ };
+
+ let mut gamepad = Gamepad::new();
let save_file = format!("{}.sav", &cli.rom);
@@ -87,7 +79,7 @@ fn main() {
}
was_previously_halted = state.mem.halt;
let c = if !state.mem.halt {
- exec_opcode(&mut state).unwrap()
+ state.exec_opcode().unwrap()
} else {
halt_time += 4;
4
@@ -97,18 +89,27 @@ fn main() {
state.tima_timer(c);
state.update_display_interrupts(c);
state.check_interrupts().unwrap();
+ state.mem.update_serial();
nanos_sleep += c as i128 * (consts::CPU_CYCLE_LENGTH_NANOS as f32 / cli.speed) as i128;
if nanos_sleep > 0 {
- gamepad.update_events();
+ let (action_button_reg, direction_button_reg) = if cli.keyboard {
+ (
+ state.mem.display.get_action_gamepad_reg(),
+ state.mem.display.get_direction_gamepad_reg(),
+ )
+ } else {
+ gamepad.update_events();
- let action_button_reg = gamepad.get_action_gamepad_reg();
- let direction_button_reg = gamepad.get_direction_gamepad_reg();
- gamepad.check_special_actions(&mut state);
+ (
+ gamepad.get_action_gamepad_reg(),
+ gamepad.get_direction_gamepad_reg(),
+ )
+ };
+ // gamepad.check_special_actions(&mut state.is_debug);
if state.mem.joypad_is_action
- && (action_button_reg & (state.mem.joypad_reg >> 4))
- != (state.mem.joypad_reg >> 4)
+ && (action_button_reg & (state.mem.joypad_reg >> 4)) != (state.mem.joypad_reg >> 4)
|| (!state.mem.joypad_is_action
&& (direction_button_reg & state.mem.joypad_reg & 0b1111)
!= (state.mem.joypad_reg & 0b1111))
@@ -118,16 +119,18 @@ fn main() {
state.mem.joypad_reg = direction_button_reg | (action_button_reg << 4);
- if cli.thread_sleep {
+ if !cli.loop_lock_timing {
thread::sleep(time::Duration::from_nanos(nanos_sleep as u64 / 10));
} else {
while SystemTime::now().duration_since(now).unwrap().as_nanos()
< nanos_sleep as u128
- {}
+ {
+ for _ in 0..100_000_000 {}
+ }
}
nanos_sleep =
- nanos_sleep - SystemTime::now().duration_since(now).unwrap().as_nanos() as i128;
+ nanos_sleep - SystemTime::now().duration_since(now).unwrap().as_nanos() as i128;
now = SystemTime::now();
if last_ram_bank_enabled && !state.mem.ram_bank_enabled {