a bunch of stuff
/ build (push) Successful in 27s Details

This commit is contained in:
45Tatami 2024-04-09 21:18:36 +02:00
parent 9b72e95201
commit 3e6d21a56c
4 changed files with 200 additions and 45 deletions

View File

@ -1,12 +1,13 @@
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
// use crate::breakpoint_shell::{BreakPointShell, BreakPointShellCommand}; use crate::op::Operation;
pub enum Command { pub enum Command {
Ignore, Ignore,
Step, Step,
Cont, Cont,
Kill, Kill,
Next,
} }
pub enum State { pub enum State {
@ -27,7 +28,7 @@ pub trait BreakPointHandler {
pub struct BreakPointManager { pub struct BreakPointManager {
handlers: Vec<Box<dyn BreakPointHandler>>, handlers: Vec<Box<dyn BreakPointHandler>>,
breakpoints: HashMap<usize, usize>, breakpoints: HashMap<usize, Vec<usize>>,
steppers: Vec<usize>, steppers: Vec<usize>,
} }
@ -43,37 +44,56 @@ impl BreakPointManager {
// FIXME handler cannot use borrowed values adding more specific lifetimes could work but maybe // FIXME handler cannot use borrowed values adding more specific lifetimes could work but maybe
// it is better to not own it at all? // it is better to not own it at all?
pub fn register_breakpoint(&mut self, adr: usize, bp: impl BreakPointHandler + 'static) { pub fn register_breakpoint(&mut self, adr: usize, bp: impl BreakPointHandler + 'static) {
self.handlers.insert(adr, Box::new(bp));
let i = self.handlers.len(); let i = self.handlers.len();
self.breakpoints.insert(adr, i); self.handlers.push(Box::new(bp));
self.add_addr_breakpoint(adr, i);
} }
pub fn inform(&mut self, adr: usize) -> Command { fn add_addr_breakpoint(&mut self, adr: usize, hndlr: usize) {
match self.breakpoints.get_mut(&adr) {
Some(bps) => bps.push(hndlr),
None => {
let mut bps = Vec::new();
bps.push(hndlr);
self.breakpoints.insert(adr, bps);
}
}
}
pub fn inform(&mut self, adr: usize, op: &Operation) -> Command {
let mut new_steppers = Vec::new(); let mut new_steppers = Vec::new();
let mut new_bps = Vec::new();
new_steppers.reserve(self.steppers.len()); new_steppers.reserve(self.steppers.len());
for hdl_i in self.steppers.drain(0..) { for hdl_i in self.steppers.drain(0..) {
println!("hit breakpoint {adr:#08x}");
let cmd = self.handlers[hdl_i].handler(Trigger::Step(adr)); let cmd = self.handlers[hdl_i].handler(Trigger::Step(adr));
match cmd { match cmd {
Command::Step => new_steppers.push(hdl_i), Command::Step => new_steppers.push(hdl_i),
Command::Kill => return Command::Kill, Command::Kill => return Command::Kill,
Command::Cont | Command::Ignore => (), Command::Cont | Command::Ignore => (),
Command::Next => new_bps.push(hdl_i),
} }
} }
self.steppers = new_steppers; self.steppers = new_steppers;
new_bps.iter().for_each(|hdl| self.add_addr_breakpoint(adr+op.offs, *hdl));
if let Some(hdl_i) = self.breakpoints.get(&adr) { if let Some(hdlrs) = self.breakpoints.get(&adr) {
let mut new_bps = Vec::new();
for hdl_i in hdlrs {
println!("hit breakpoint {adr:#08x}"); println!("hit breakpoint {adr:#08x}");
let cmd = self.handlers[*hdl_i].handler(Trigger::Address(adr)); let cmd = self.handlers[*hdl_i].handler(Trigger::Address(adr));
match cmd { match cmd {
Command::Step => self.steppers.push(*hdl_i), Command::Step => self.steppers.push(*hdl_i),
Command::Kill => return Command::Kill, Command::Kill => return Command::Kill,
Command::Cont | Command::Ignore => (), Command::Cont | Command::Ignore => (),
Command::Next => new_bps.push(*hdl_i),
} }
} else { }
return Command::Ignore; new_bps.iter().for_each(|hdl| self.add_addr_breakpoint(adr+op.offs, *hdl));
} }
Command::Ignore // FIXME Command::Ignore
} }
} }

View File

@ -18,8 +18,13 @@ struct BreakPointShellParser {
pub enum ShellCommand { pub enum ShellCommand {
#[command(visible_alias="s")] #[command(visible_alias="s")]
Step, Step,
#[command(visible_alias="c")]
Continue,
#[command(visible_alias="n")]
Next,
#[command(visible_alias="q")] #[command(visible_alias="q")]
Quit, Quit,
// TODO UP
} }
impl BreakPointShell { impl BreakPointShell {
@ -57,6 +62,8 @@ impl BreakPointHandler for BreakPointShell {
match parser.cmd { match parser.cmd {
ShellCommand::Step => break Command::Step, ShellCommand::Step => break Command::Step,
ShellCommand::Quit => break Command::Kill, ShellCommand::Quit => break Command::Kill,
ShellCommand::Continue => break Command::Cont,
ShellCommand::Next => break Command::Next,
} }
} }
} }

View File

@ -121,7 +121,7 @@ impl GameBoy {
let (dst_ref, dst_adr) = match dst { let (dst_ref, dst_adr) = match dst {
Loc::Mem(ref src) => match src { Loc::Mem(ref src) => match src {
AddrLoc::Val => { AddrLoc::Val => {
let adr = self.next16(pc) as usize; let adr = self.read16(pc) as usize;
(&mut self.mem[adr], adr) (&mut self.mem[adr], adr)
} }
_ => todo!(), _ => todo!(),
@ -155,7 +155,7 @@ impl GameBoy {
let dst_ref = match dst { let dst_ref = match dst {
Loc::Reg(reg) => { Loc::Reg(reg) => {
// FIXME assuming DD is a typo for DE... // FIXME assuming DD is a typo for DE...
let reg_loc = reg as usize; let reg_loc = reg.into();
&mut self.reg[reg_loc..=reg_loc + 1] &mut self.reg[reg_loc..=reg_loc + 1]
} }
Loc::Val => panic!("value as dst is not allowed!"), Loc::Val => panic!("value as dst is not allowed!"),
@ -172,24 +172,29 @@ impl GameBoy {
dst_ref[1] = h; dst_ref[1] = h;
} }
fn next16(&self, adr: usize) -> u16 { fn read16(&self, adr: usize) -> u16 {
let ladr = self.mem[adr + 1] as u16; let ladr = self.mem[adr] as u16;
let hadr = self.mem[adr + 2] as u16; let hadr = self.mem[adr+1] as u16;
(hadr << 8) + ladr (hadr << 8) + ladr
} }
fn store16(&mut self, loc: Loc, _loc_val: u8, h: u8, l: u8) {
match loc {
Loc::Reg(dst_reg) => {
let dst_reg: usize = dst_reg.into();
self.reg[dst_reg] = h;
self.reg[dst_reg + 1] = l;
}
_ => todo!()
}
}
fn step(&mut self) { fn step(&mut self) {
use Instr::*; use Instr::*;
let mut pc = self.pc as usize; let mut pc = self.pc as usize;
let instr = self.mem[pc]; let instr = self.mem[pc];
match self.bp_manager.inform(pc) {
BpCommand::Ignore | BpCommand::Cont => (),
BpCommand::Step => todo!(),
BpCommand::Kill => panic!("kill from breakpoint"),
};
let win = &self.mem[pc..cmp::min(RAM_SIZE, pc + 3)]; let win = &self.mem[pc..cmp::min(RAM_SIZE, pc + 3)];
let op = match Operation::try_from(instr) { let op = match Operation::try_from(instr) {
Ok(op) => op, Ok(op) => op,
@ -198,6 +203,12 @@ impl GameBoy {
} }
}; };
match self.bp_manager.inform(pc, &op) {
BpCommand::Ignore | BpCommand::Cont | BpCommand::Next => (),
BpCommand::Step => todo!(),
BpCommand::Kill => panic!("kill from breakpoint"),
};
println!("pc:{pc:#08x}:{win:02x?} {op:?}"); println!("pc:{pc:#08x}:{win:02x?} {op:?}");
match op.inst { match op.inst {
@ -209,7 +220,7 @@ impl GameBoy {
} }
Nop => (), Nop => (),
Jp => { Jp => {
let new_pc = self.next16(pc); let new_pc = self.read16(pc+1);
self.pc = new_pc; self.pc = new_pc;
println!("jp {pc:#06x}->{new_pc:#06x}"); println!("jp {pc:#06x}->{new_pc:#06x}");
return; return;
@ -224,21 +235,44 @@ impl GameBoy {
} }
Call => { Call => {
let sp = self.sp as usize; let sp = self.sp as usize;
self.mem[sp - 1] = (pc >> 8) as u8; self.mem[sp - 1] = ((pc+op.offs) >> 8) as u8;
self.mem[sp - 2] = (pc & 0xFF) as u8; self.mem[sp - 2] = ((pc+op.offs) & 0xFF) as u8;
let new_pc = self.next16(pc); let new_pc = self.read16(pc+1);
let old_pc = self.pc;
self.pc = new_pc; self.pc = new_pc;
self.sp -= 2; self.sp -= 2;
println!("call {new_pc:#06x} <- {old_pc:#06x}"); println!("call {new_pc:#06x}");
return; return;
} }
Ret => { Ret => {
let new_pc = self.next16((self.sp as usize) - 1); let new_pc = self.read16(self.sp as usize);
let old_pc = self.pc;
self.pc = new_pc; self.pc = new_pc;
self.sp += 2; self.sp += 2;
println!("ret {new_pc:#06x} <- {old_pc:#06x}"); println!("ret {new_pc:#06x}");
return;
}
Psh(reg) => {
let reg: usize = reg.into();
let sp = self.sp as usize;
self.mem[sp - 1] = self.reg[reg];
self.mem[sp - 2] = self.reg[reg + 1];
self.sp -= 2;
println!("push Reg({reg:#04b})");
}
Pop(reg) => {
let reg: usize = reg.into();
let sp = self.sp as usize;
self.reg[reg + 1] = self.mem[sp];
self.reg[reg] = self.mem[sp + 1];
self.sp += 2;
println!("pop Reg({reg:#04b})");
}
Inc(reg) => {
self.reg[reg] += 1;
println!("Inc Reg({reg:#04b})");
}
Dec(reg) => {
self.reg[reg as usize] -= 1;
println!("Dec Reg({reg:#04b})");
} }
Ld(dst, src) => self.op_ld(dst, src), Ld(dst, src) => self.op_ld(dst, src),
Ld16(dst, src) => self.op_ld16(dst, src), Ld16(dst, src) => self.op_ld16(dst, src),

114
src/op.rs
View File

@ -1,3 +1,5 @@
use std::fmt;
pub const HD_MSK: u8 = 0b1100_0000; pub const HD_MSK: u8 = 0b1100_0000;
pub const T1_MSK: u8 = 0b0011_1000; pub const T1_MSK: u8 = 0b0011_1000;
pub const T2_MSK: u8 = 0b0000_0111; pub const T2_MSK: u8 = 0b0000_0111;
@ -15,11 +17,18 @@ pub enum Instr {
// Misc // Misc
Nop, Nop,
Psh(Register), // double (16bit) register, eg B => BC
Pop(Register),
// Load // Load
Ld(Loc, Loc), Ld(Loc, Loc),
Ld16(Loc, Loc), Ld16(Loc, Loc),
// Arith
// TODO can we do Inc16/Inc8 with one via Register::WIDE
Inc(Register),
Dec(Register),
// CPU ctl // CPU ctl
Di, Di,
@ -47,16 +56,85 @@ pub enum Loc {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum Register { pub enum Register {
A = 0x07, A,
F = 0x08, F,
B = 0x00, B,
C = 0x01, C,
D = 0x02, D,
E = 0x03, E,
H = 0x04, H,
L = 0x05, L,
SP = 0x09, AF,
BC,
DE,
HL,
SP,
}
impl From<Register> for usize {
fn from(v: Register) -> usize {
use Register::*;
match v {
A | AF => 0x07,
B | BC => 0x00,
D | DE => 0x02,
H | HL => 0x04,
F => 0x08,
C => 0x01,
E => 0x03,
L => 0x05,
SP => 0x09
}
}
}
impl Register {
// this is from 16bit arithmetic operation instructions
fn from16_rep(v: u8) -> Register {
use Register::*;
match v {
0b00 => BC,
0b01 => DE,
0b10 => HL,
0b11 => SP,
_ => panic!("unknown register {v}")
}
}
fn repr_psh(v: u8) -> Register {
use Register::*;
match v {
0b00 => B,
0b01 => D,
0b10 => H,
0b11 => A,
_ => panic!("unknown register {v}")
}
}
}
impl<T> std::ops::Index<Register> for [T] {
type Output = T;
fn index(&self, r: Register) -> &Self::Output {
let i: usize = r.into();
&self[i]
}
}
impl<T> std::ops::IndexMut<Register> for [T] {
fn index_mut(&mut self, r: Register) -> &mut Self::Output {
let i: usize = r.into();
&mut self[i]
}
}
impl fmt::Binary for Register {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Binary::fmt(&(*self as usize), f)
}
} }
impl Loc { impl Loc {
@ -89,6 +167,10 @@ impl TryFrom<u8> for Register {
} }
} }
fn payload(v: u8) -> u8 {
(v & 0b110_000) >> 4
}
impl TryFrom<u8> for Operation { impl TryFrom<u8> for Operation {
type Error = String; type Error = String;
@ -105,6 +187,18 @@ impl TryFrom<u8> for Operation {
0b11_110_011 => (Di, 1, 1), 0b11_110_011 => (Di, 1, 1),
0b11_101_010 => (Ld(Mem(AddrLoc::Val), Reg(Register::A)), 4, 3), 0b11_101_010 => (Ld(Mem(AddrLoc::Val), Reg(Register::A)), 4, 3),
0b11_100_000 => (Ld(HMem(AddrLoc::Val), Reg(Register::A)), 3, 2), 0b11_100_000 => (Ld(HMem(AddrLoc::Val), Reg(Register::A)), 3, 2),
_ if (value & (HD_MSK | 0b1_000 | T2_MSK) == 0b00_000_011) => {
(Inc(Register::from16_rep(payload(value))), 2, 1)
}
_ if (value & (HD_MSK | 0b1_000 | T2_MSK) == 0b00_001_011) => {
(Dec(Register::from16_rep(payload(value))), 2, 1)
}
_ if (value & (HD_MSK | 0b1_000 | T2_MSK) == 0b11_000_101) => {
(Psh(Register::repr_psh(payload(value))), 4, 1)
}
_ if (value & (HD_MSK | 0b1_000 | T2_MSK) == 0b11_000_001) => {
(Pop(Register::repr_psh(payload(value))), 3, 1)
}
_ if (value & (HD_MSK | T2_MSK)) == 0b00_000_110 => { _ if (value & (HD_MSK | T2_MSK)) == 0b00_000_110 => {
let reg = Register::try_from((value & T1_MSK) >> 3)?; let reg = Register::try_from((value & T1_MSK) >> 3)?;
(Ld(Reg(reg), Val), 2, 2) (Ld(Reg(reg), Val), 2, 2)
@ -115,7 +209,7 @@ impl TryFrom<u8> for Operation {
(Ld(Reg(dst), Reg(src)), 1, 1) (Ld(Reg(dst), Reg(src)), 1, 1)
} }
_ if (value & (HD_MSK | 0b1_000 | T2_MSK)) == 0b00_000_001 => { _ if (value & (HD_MSK | 0b1_000 | T2_MSK)) == 0b00_000_001 => {
let reg = match (value & 0b110_000) >> 4 { let reg = match payload(value) {
0b00 => Register::B, 0b00 => Register::B,
0b01 => Register::D, 0b01 => Register::D,
0b10 => Register::H, 0b10 => Register::H,