a bunch of stuff
/ build (push) Successful in 27s
Details
/ build (push) Successful in 27s
Details
This commit is contained in:
parent
9b72e95201
commit
3e6d21a56c
|
|
@ -1,12 +1,13 @@
|
|||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
// use crate::breakpoint_shell::{BreakPointShell, BreakPointShellCommand};
|
||||
use crate::op::Operation;
|
||||
|
||||
pub enum Command {
|
||||
Ignore,
|
||||
Step,
|
||||
Cont,
|
||||
Kill,
|
||||
Next,
|
||||
}
|
||||
|
||||
pub enum State {
|
||||
|
|
@ -27,7 +28,7 @@ pub trait BreakPointHandler {
|
|||
|
||||
pub struct BreakPointManager {
|
||||
handlers: Vec<Box<dyn BreakPointHandler>>,
|
||||
breakpoints: HashMap<usize, usize>,
|
||||
breakpoints: HashMap<usize, 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
|
||||
// it is better to not own it at all?
|
||||
pub fn register_breakpoint(&mut self, adr: usize, bp: impl BreakPointHandler + 'static) {
|
||||
self.handlers.insert(adr, Box::new(bp));
|
||||
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_bps = Vec::new();
|
||||
new_steppers.reserve(self.steppers.len());
|
||||
|
||||
|
||||
for hdl_i in self.steppers.drain(0..) {
|
||||
println!("hit breakpoint {adr:#08x}");
|
||||
let cmd = self.handlers[hdl_i].handler(Trigger::Step(adr));
|
||||
match cmd {
|
||||
Command::Step => new_steppers.push(hdl_i),
|
||||
Command::Kill => return Command::Kill,
|
||||
Command::Cont | Command::Ignore => (),
|
||||
Command::Next => new_bps.push(hdl_i),
|
||||
}
|
||||
}
|
||||
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}");
|
||||
let cmd = self.handlers[*hdl_i].handler(Trigger::Address(adr));
|
||||
match cmd {
|
||||
Command::Step => self.steppers.push(*hdl_i),
|
||||
Command::Kill => return Command::Kill,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,13 @@ struct BreakPointShellParser {
|
|||
pub enum ShellCommand {
|
||||
#[command(visible_alias="s")]
|
||||
Step,
|
||||
#[command(visible_alias="c")]
|
||||
Continue,
|
||||
#[command(visible_alias="n")]
|
||||
Next,
|
||||
#[command(visible_alias="q")]
|
||||
Quit,
|
||||
// TODO UP
|
||||
}
|
||||
|
||||
impl BreakPointShell {
|
||||
|
|
@ -57,6 +62,8 @@ impl BreakPointHandler for BreakPointShell {
|
|||
match parser.cmd {
|
||||
ShellCommand::Step => break Command::Step,
|
||||
ShellCommand::Quit => break Command::Kill,
|
||||
ShellCommand::Continue => break Command::Cont,
|
||||
ShellCommand::Next => break Command::Next,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
74
src/emu.rs
74
src/emu.rs
|
|
@ -121,7 +121,7 @@ impl GameBoy {
|
|||
let (dst_ref, dst_adr) = match dst {
|
||||
Loc::Mem(ref src) => match src {
|
||||
AddrLoc::Val => {
|
||||
let adr = self.next16(pc) as usize;
|
||||
let adr = self.read16(pc) as usize;
|
||||
(&mut self.mem[adr], adr)
|
||||
}
|
||||
_ => todo!(),
|
||||
|
|
@ -155,7 +155,7 @@ impl GameBoy {
|
|||
let dst_ref = match dst {
|
||||
Loc::Reg(reg) => {
|
||||
// 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]
|
||||
}
|
||||
Loc::Val => panic!("value as dst is not allowed!"),
|
||||
|
|
@ -172,24 +172,29 @@ impl GameBoy {
|
|||
dst_ref[1] = h;
|
||||
}
|
||||
|
||||
fn next16(&self, adr: usize) -> u16 {
|
||||
let ladr = self.mem[adr + 1] as u16;
|
||||
let hadr = self.mem[adr + 2] as u16;
|
||||
fn read16(&self, adr: usize) -> u16 {
|
||||
let ladr = self.mem[adr] as u16;
|
||||
let hadr = self.mem[adr+1] as u16;
|
||||
(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) {
|
||||
use Instr::*;
|
||||
|
||||
let mut pc = self.pc as usize;
|
||||
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 op = match Operation::try_from(instr) {
|
||||
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:?}");
|
||||
|
||||
match op.inst {
|
||||
|
|
@ -209,7 +220,7 @@ impl GameBoy {
|
|||
}
|
||||
Nop => (),
|
||||
Jp => {
|
||||
let new_pc = self.next16(pc);
|
||||
let new_pc = self.read16(pc+1);
|
||||
self.pc = new_pc;
|
||||
println!("jp {pc:#06x}->{new_pc:#06x}");
|
||||
return;
|
||||
|
|
@ -224,21 +235,44 @@ impl GameBoy {
|
|||
}
|
||||
Call => {
|
||||
let sp = self.sp as usize;
|
||||
self.mem[sp - 1] = (pc >> 8) as u8;
|
||||
self.mem[sp - 2] = (pc & 0xFF) as u8;
|
||||
let new_pc = self.next16(pc);
|
||||
let old_pc = self.pc;
|
||||
self.mem[sp - 1] = ((pc+op.offs) >> 8) as u8;
|
||||
self.mem[sp - 2] = ((pc+op.offs) & 0xFF) as u8;
|
||||
let new_pc = self.read16(pc+1);
|
||||
self.pc = new_pc;
|
||||
self.sp -= 2;
|
||||
println!("call {new_pc:#06x} <- {old_pc:#06x}");
|
||||
println!("call {new_pc:#06x}");
|
||||
return;
|
||||
}
|
||||
Ret => {
|
||||
let new_pc = self.next16((self.sp as usize) - 1);
|
||||
let old_pc = self.pc;
|
||||
let new_pc = self.read16(self.sp as usize);
|
||||
self.pc = new_pc;
|
||||
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),
|
||||
Ld16(dst, src) => self.op_ld16(dst, src),
|
||||
|
|
|
|||
114
src/op.rs
114
src/op.rs
|
|
@ -1,3 +1,5 @@
|
|||
use std::fmt;
|
||||
|
||||
pub const HD_MSK: u8 = 0b1100_0000;
|
||||
pub const T1_MSK: u8 = 0b0011_1000;
|
||||
pub const T2_MSK: u8 = 0b0000_0111;
|
||||
|
|
@ -15,11 +17,18 @@ pub enum Instr {
|
|||
|
||||
// Misc
|
||||
Nop,
|
||||
Psh(Register), // double (16bit) register, eg B => BC
|
||||
Pop(Register),
|
||||
|
||||
// Load
|
||||
Ld(Loc, Loc),
|
||||
Ld16(Loc, Loc),
|
||||
|
||||
// Arith
|
||||
// TODO can we do Inc16/Inc8 with one via Register::WIDE
|
||||
Inc(Register),
|
||||
Dec(Register),
|
||||
|
||||
// CPU ctl
|
||||
Di,
|
||||
|
||||
|
|
@ -47,16 +56,85 @@ pub enum Loc {
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Register {
|
||||
A = 0x07,
|
||||
F = 0x08,
|
||||
B = 0x00,
|
||||
C = 0x01,
|
||||
D = 0x02,
|
||||
E = 0x03,
|
||||
H = 0x04,
|
||||
L = 0x05,
|
||||
A,
|
||||
F,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
H,
|
||||
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 {
|
||||
|
|
@ -89,6 +167,10 @@ impl TryFrom<u8> for Register {
|
|||
}
|
||||
}
|
||||
|
||||
fn payload(v: u8) -> u8 {
|
||||
(v & 0b110_000) >> 4
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Operation {
|
||||
type Error = String;
|
||||
|
||||
|
|
@ -105,6 +187,18 @@ impl TryFrom<u8> for Operation {
|
|||
0b11_110_011 => (Di, 1, 1),
|
||||
0b11_101_010 => (Ld(Mem(AddrLoc::Val), Reg(Register::A)), 4, 3),
|
||||
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 => {
|
||||
let reg = Register::try_from((value & T1_MSK) >> 3)?;
|
||||
(Ld(Reg(reg), Val), 2, 2)
|
||||
|
|
@ -115,7 +209,7 @@ impl TryFrom<u8> for Operation {
|
|||
(Ld(Reg(dst), Reg(src)), 1, 1)
|
||||
}
|
||||
_ 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,
|
||||
0b01 => Register::D,
|
||||
0b10 => Register::H,
|
||||
|
|
|
|||
Loading…
Reference in New Issue