1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use core::fmt;
use crate::*;
type TsClock = host::TsCounter<u32>;
#[derive(Clone, Debug, Default)]
struct Mem<'a>(u16, &'a [u8]);
impl Io for Mem<'_> {
type Timestamp = u32;
type WrIoBreak = ();
type RetiBreak = ();
}
impl Memory for Mem<'_> {
type Timestamp = u32;
fn read_debug(&self, addr: u16) -> u8 {
*self.1.get(addr.wrapping_sub(self.0) as usize).unwrap_or(&0xff)
}
}
pub fn disasm_memory<C: Cpu, F: FnMut(CpuDebug) -> Result<(), E>, E>(
pc: u16,
memory: &[u8],
mut debug: F
) -> Result<(), E>
{
let mut cpu = C::default();
let mut cursor: usize = 0;
let mut dbg: Option<CpuDebug> = None;
let mut tsc = TsClock::default();
while cursor < memory.len() {
let pc = pc.wrapping_add(cursor as u16);
cpu.set_pc(pc);
let _ = cpu.execute_next(&mut Mem(pc, &memory[cursor..]), &mut tsc,
Some(|deb: CpuDebug| {
cursor += deb.code.len();
if deb.prefix.is_some() {
cursor -= 1;
}
dbg = Some(deb);
})
);
if cursor > memory.len() {
break;
}
else if let Some(deb) = dbg.take() {
debug(deb)?;
}
else if cpu.is_after_prefix() {
cursor += 1;
}
else {
cpu.reset();
}
}
Ok(())
}
pub fn disasm_memory_write_text<C: Cpu, W: fmt::Write>(
pc: u16,
mem: &[u8],
mut f: W
) -> fmt::Result
{
disasm_memory::<C,_,_>(pc, mem, |deb|
writeln!(f, "{:x}", deb)
)
}
#[cfg(feature = "std")]
pub fn disasm_memory_print_text<C: Cpu>(pc: u16, mem: &[u8]) {
let _ = disasm_memory::<C,_,()>(pc, mem, |deb| {
println!("{:x}", deb);
Ok(())
});
}
#[cfg(test)]
mod tests {
use super::*;
use arrayvec::ArrayString;
#[test]
fn disasm_works() {
let mem = [0x09, 0xdd, 0xfd, 0xdd, 0x09, 0x76, 0, 0xcb];
let mut s = ArrayString::<[_;128]>::new();
disasm_memory_write_text::<Z80NMOS,_>(0xfffe, &mem, &mut s).unwrap();
assert_eq!(&s.as_ref(), &concat!(
"fffeh ADD HL, BC [09]\n",
"0001h ADD IX, BC [dd, 09]\n",
"0003h HALT [76]\n",
"0004h NOP [00]\n"));
let mem = [0xdd, 0xcb, 0x00, 0x00, 0xfd, 0x00];
let mut s = ArrayString::<[_;128]>::new();
disasm_memory_write_text::<Z80NMOS,_>(0xffff, &mem, &mut s).unwrap();
assert_eq!(&s.as_ref(), &concat!(
"ffffh RLC (IX+00h), B [dd, cb, 00, 00]\n",
"0004h NOP [00]\n"));
}
}