cpclib_sna/chunks/
wabp.rs

1// Implement WABP chunk (and file content) for WINAPE
2// this has not been yet deeply tested. Consider everything is false
3
4use std::ops::Deref;
5
6use cpclib_common::riff::{RiffChunk, RiffCode, RiffLen};
7use delegate::delegate;
8
9fn push_u32(vec: &mut Vec<u8>, mut nb: u32) {
10    for _ in 0..4 {
11        vec.push((nb % 256) as _);
12        nb >>= 8;
13    }
14    assert_eq!(nb, 0);
15}
16
17#[repr(u8)]
18#[derive(Clone, Copy)]
19pub enum BreakpointOrigin {
20    User = 1,
21    Assembler = 4
22}
23
24#[repr(u8)]
25#[derive(Clone, Copy)]
26pub enum BreakPointAccess {
27    Read = 1 << 6,
28    Write = 1 << 7,
29    ReadWrite = (1 << 7) + (1 << 6)
30}
31
32// TODO finish to get the other ones
33#[repr(u8)]
34#[derive(Clone, Copy)]
35pub enum BreakpointIoType {
36    User = 0,
37    GateArray = 1
38}
39
40#[derive(Clone, Copy)]
41pub struct BreakpointFlag(u8);
42
43pub struct Counts {
44    max: u32,
45    count: u32
46}
47
48impl Counts {
49    pub fn to_bytes(&self) -> Vec<u8> {
50        let mut vec = Vec::with_capacity(4);
51        push_u32(&mut vec, self.max);
52        push_u32(&mut vec, self.count);
53
54        vec
55    }
56}
57
58pub struct Condition(String);
59
60impl Condition {
61    pub fn to_bytes(&self) -> Vec<u8> {
62        let mut vec = Vec::new();
63        let condition = self.0.as_bytes();
64        let nb_chars = condition.len() as u32;
65        push_u32(&mut vec, nb_chars);
66        for c in condition {
67            vec.push(*c);
68        }
69        vec
70    }
71}
72
73pub struct CountsAndCondition(Option<Counts>, Option<Condition>);
74
75impl CountsAndCondition {
76    pub fn none() -> Self {
77        CountsAndCondition(None, None)
78    }
79
80    pub fn has_counts(&self) -> bool {
81        self.0.is_some()
82    }
83
84    pub fn has_condition(&self) -> bool {
85        self.1.is_some()
86    }
87
88    pub fn to_bytes(&self) -> Vec<u8> {
89        let mut vec = Vec::new();
90
91        if let Some(counts) = &self.0 {
92            vec.extend_from_slice(&counts.to_bytes());
93        }
94
95        if let Some(condition) = &self.1 {
96            vec.extend_from_slice(&condition.to_bytes());
97        }
98        vec
99    }
100}
101
102pub struct WinapeAddress(u32);
103impl Deref for WinapeAddress {
104    type Target = u32;
105
106    fn deref(&self) -> &Self::Target {
107        &self.0
108    }
109}
110
111impl WinapeAddress {
112    pub fn new(address: u16, has_count: bool, has_condition: bool) -> WinapeAddress {
113        let mut addr = address as u32;
114        if has_count {
115            addr += 1 << 31;
116        }
117        if has_condition {
118            addr += 1 << 30;
119        }
120
121        Self(addr)
122    }
123
124    pub fn address(&self) -> u16 {
125        (self.0 & 0xFFFF) as u16
126    }
127
128    pub fn has_count(&self) -> bool {
129        (self.0 & (1 << 31)) != 0
130    }
131
132    pub fn has_condition(&self) -> bool {
133        (self.0 & (1 << 30)) != 0
134    }
135}
136
137pub struct CodeBreakpoint {
138    origin: BreakpointOrigin,
139    address: u16,
140    counts_condition: CountsAndCondition
141}
142
143impl CodeBreakpoint {
144    pub fn new(address: u16) -> Self {
145        Self {
146            origin: BreakpointOrigin::Assembler,
147            address,
148            counts_condition: CountsAndCondition::none()
149        }
150    }
151
152    pub fn winape_address(&self) -> WinapeAddress {
153        WinapeAddress::new(
154            self.address,
155            self.counts_condition.has_counts(),
156            self.counts_condition.has_counts()
157        )
158    }
159}
160
161impl CodeBreakpoint {
162    pub fn to_bytes(&self) -> Vec<u8> {
163        let mut vec = Vec::new();
164
165        vec.push(self.origin as u8);
166        push_u32(&mut vec, *self.winape_address().deref());
167        vec.extend_from_slice(&self.counts_condition.to_bytes());
168
169        vec
170    }
171}
172
173pub struct MemoryBreakpoint {
174    access: BreakPointAccess,
175    address: u16,
176    counts_condition: CountsAndCondition
177}
178
179impl MemoryBreakpoint {
180    pub fn to_bytes(&self) -> Vec<u8> {
181        let mut vec = Vec::new();
182
183        vec.push(self.access as u8);
184        push_u32(&mut vec, *self.winape_address().deref());
185        vec.extend_from_slice(&self.counts_condition.to_bytes());
186        vec.push(0);
187        vec.push(0);
188        vec
189    }
190
191    pub fn winape_address(&self) -> WinapeAddress {
192        WinapeAddress::new(
193            self.address,
194            self.counts_condition.has_counts(),
195            self.counts_condition.has_counts()
196        )
197    }
198}
199pub struct IOBreakpoint {
200    r#type: BreakpointIoType,
201    flag: BreakpointFlag,
202    address: u16,
203    address_mask: u16,
204    counts_condition: CountsAndCondition
205}
206
207impl IOBreakpoint {
208    pub fn winape_address(&self) -> WinapeAddress {
209        WinapeAddress::new(
210            self.address,
211            self.counts_condition.has_counts(),
212            self.counts_condition.has_counts()
213        )
214    }
215
216    pub fn to_bytes(&self) -> Vec<u8> {
217        unimplemented!()
218    }
219}
220
221pub struct CodeBreakpoints(Vec<CodeBreakpoint>);
222pub struct MemoryBreakpoints(Vec<MemoryBreakpoint>);
223pub struct IOBreakpoints(Vec<IOBreakpoint>);
224
225pub enum WabpAnyBreakpoint {
226    Code(CodeBreakpoint),
227    Memory(MemoryBreakpoint),
228    IO(IOBreakpoint)
229}
230
231impl WabpAnyBreakpoint {
232    pub fn new(address: u16) -> Self {
233        WabpAnyBreakpoint::Code(CodeBreakpoint::new(address))
234    }
235}
236
237impl CodeBreakpoints {
238    pub fn to_bytes(&self) -> Vec<u8> {
239        let mut vec = Vec::new();
240
241        // Store the number of breakpoints
242        let nb = self.0.len();
243        push_u32(&mut vec, nb as _);
244
245        for brk in self.0.iter() {
246            vec.extend_from_slice(&brk.to_bytes());
247        }
248
249        vec
250    }
251}
252
253impl MemoryBreakpoints {
254    pub fn to_bytes(&self) -> Vec<u8> {
255        let mut vec = Vec::new();
256
257        // Store the number of breakpoints
258        let nb = self.0.len();
259        push_u32(&mut vec, nb as _);
260
261        for brk in self.0.iter() {
262            vec.extend_from_slice(&brk.to_bytes());
263        }
264
265        vec
266    }
267}
268
269impl IOBreakpoints {
270    pub fn to_bytes(&self) -> Vec<u8> {
271        let mut vec = Vec::new();
272
273        // Store the number of breakpoints
274        let nb = self.0.len();
275        push_u32(&mut vec, nb as _);
276
277        for brk in self.0.iter() {
278            vec.extend_from_slice(&brk.to_bytes());
279        }
280
281        vec
282    }
283}
284
285pub struct Wabp {
286    code: CodeBreakpoints,
287    memory: MemoryBreakpoints,
288    io: IOBreakpoints
289}
290
291impl Default for Wabp {
292    fn default() -> Self {
293        Self::new()
294    }
295}
296
297impl Wabp {
298    pub fn new() -> Self {
299        Wabp {
300            code: CodeBreakpoints(Default::default()),
301            memory: MemoryBreakpoints(Default::default()),
302            io: IOBreakpoints(Default::default())
303        }
304    }
305
306    pub fn to_bytes(&self) -> Vec<u8> {
307        let mut vec = Vec::new();
308        vec.extend_from_slice(&self.code.to_bytes());
309        vec.extend_from_slice(&self.memory.to_bytes());
310        vec.extend_from_slice(&self.io.to_bytes());
311        vec
312    }
313}
314
315impl Wabp {
316    pub fn add_breakpoint(&mut self, brk: WabpAnyBreakpoint) {
317        match brk {
318            WabpAnyBreakpoint::Code(brk) => {
319                self.code.0.push(brk);
320            },
321            WabpAnyBreakpoint::Memory(brk) => {
322                self.memory.0.push(brk);
323            },
324            WabpAnyBreakpoint::IO(brk) => self.io.0.push(brk)
325        }
326    }
327}
328
329pub struct WabpChunk {
330    riff: RiffChunk,
331    wabp: Wabp
332}
333
334impl WabpChunk {
335    const CODE: RiffCode = RiffCode::new([b'W', b'A', b'B', b'P']);
336
337    delegate! {
338        to self.riff {
339            pub fn code(&self) -> &RiffCode;
340            pub fn len(&self) -> &RiffLen;
341            pub fn data(&self) -> &[u8];
342            fn add_bytes(&mut self, data: &[u8]);
343        }
344    }
345
346    pub fn empty() -> Self {
347        Self {
348            riff: RiffChunk::new(Self::CODE, Default::default()),
349            wabp: Wabp::new()
350        }
351    }
352
353    pub fn add_breakpoint(&mut self, brk: WabpAnyBreakpoint) {
354        self.wabp.add_breakpoint(brk);
355        let mut data = self.wabp.to_bytes();
356        self.riff = RiffChunk::from_buffer(&mut data);
357    }
358}