cpclib_sna/chunks/
wabp.rs1use 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#[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 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 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 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}