autd3_firmware_emulator/cpu/
emulator.rs1use autd3_driver::{
2 ethercat::{DcSysTime, EC_OUTPUT_FRAME_SIZE},
3 link::{Ack, Header, MsgId, RxMessage, TxMessage},
4};
5
6use crate::fpga::emulator::FPGAEmulator;
7
8use super::params::*;
9
10pub struct CPUEmulator {
11 pub(crate) idx: usize,
12 pub(crate) err: u8,
13 pub(crate) last_msg_id: MsgId,
14 pub(crate) rx_data: u8,
15 pub(crate) reads_fpga_state: bool,
16 pub(crate) reads_fpga_state_store: bool,
17 pub(crate) mod_cycle: u32,
18 pub(crate) stm_write: u32,
19 pub(crate) stm_cycle: [u32; 2],
20 pub(crate) stm_mode: [u16; 2],
21 pub(crate) stm_rep: [u16; 2],
22 pub(crate) stm_freq_div: [u16; 2],
23 pub(crate) stm_segment: u8,
24 pub(crate) stm_transition_mode: u8,
25 pub(crate) stm_transition_value: u64,
26 pub(crate) num_foci: u8,
27 pub(crate) mod_freq_div: [u16; 2],
28 pub(crate) mod_segment: u8,
29 pub(crate) mod_rep: [u16; 2],
30 pub(crate) mod_transition_mode: u8,
31 pub(crate) mod_transition_value: u64,
32 pub(crate) gain_stm_mode: u8,
33 pub(crate) fpga: FPGAEmulator,
34 pub(crate) synchronized: bool,
35 pub(crate) num_transducers: usize,
36 pub(crate) fpga_flags_internal: u16,
37 pub(crate) silencer_strict: bool,
38 pub(crate) min_freq_div_intensity: u16,
39 pub(crate) min_freq_div_phase: u16,
40 pub(crate) is_rx_data_used: bool,
41 pub(crate) dc_sys_time: DcSysTime,
42 pub(crate) port_a_podr: u8,
43 pub(crate) broken: bool,
44}
45
46impl CPUEmulator {
47 #[must_use]
48 pub fn new(id: usize, num_transducers: usize) -> Self {
49 let mut s = Self {
50 idx: id,
51 err: 0x00,
52 last_msg_id: MsgId::new(0xFF),
53 rx_data: 0x00,
54 reads_fpga_state: false,
55 reads_fpga_state_store: false,
56 mod_cycle: 0,
57 stm_cycle: [1, 1],
58 stm_mode: [STM_MODE_GAIN, STM_MODE_GAIN],
59 gain_stm_mode: 0,
60 stm_transition_mode: TRANSITION_MODE_SYNC_IDX,
61 stm_transition_value: 0,
62 num_foci: 1,
63 mod_transition_mode: TRANSITION_MODE_SYNC_IDX,
64 mod_transition_value: 0,
65 fpga: FPGAEmulator::new(num_transducers),
66 synchronized: false,
67 num_transducers,
68 fpga_flags_internal: 0x0000,
69 mod_freq_div: [10, 10],
70 mod_segment: 0,
71 stm_freq_div: [0xFFFF, 0xFFFF],
72 stm_segment: 0,
73 stm_write: 0,
74 silencer_strict: true,
75 min_freq_div_intensity: 10,
76 min_freq_div_phase: 40,
77 is_rx_data_used: false,
78 dc_sys_time: DcSysTime::now(),
79 stm_rep: [0xFFFF, 0xFFFF],
80 mod_rep: [0xFFFF, 0xFFFF],
81 port_a_podr: 0x00,
82 broken: false,
83 };
84 s.init();
85 s
86 }
87
88 pub const fn break_down(&mut self) {
89 self.broken = true;
90 }
91
92 pub const fn repair(&mut self) {
93 self.broken = false;
94 }
95
96 #[must_use]
97 pub const fn idx(&self) -> usize {
98 self.idx
99 }
100
101 #[must_use]
102 pub const fn num_transducers(&self) -> usize {
103 self.num_transducers
104 }
105
106 #[must_use]
107 pub const fn dc_sys_time(&self) -> DcSysTime {
108 self.dc_sys_time
109 }
110
111 #[must_use]
112 pub const fn synchronized(&self) -> bool {
113 self.synchronized
114 }
115
116 #[must_use]
117 pub const fn fpga(&self) -> &FPGAEmulator {
118 &self.fpga
119 }
120
121 #[must_use]
122 pub const fn fpga_mut(&mut self) -> &mut FPGAEmulator {
123 &mut self.fpga
124 }
125
126 #[must_use]
127 pub const fn silencer_strict(&self) -> bool {
128 self.silencer_strict
129 }
130
131 #[must_use]
132 pub const fn reads_fpga_state(&self) -> bool {
133 self.reads_fpga_state
134 }
135
136 #[must_use]
137 pub const fn port_a_podr(&self) -> u8 {
138 self.port_a_podr
139 }
140
141 #[must_use]
142 pub const fn rx(&self) -> RxMessage {
143 RxMessage::new(
144 self.rx_data,
145 Ack::new()
146 .with_err(self.err)
147 .with_msg_id(self.last_msg_id.get() & 0x0F),
148 )
149 }
150
151 pub fn send(&mut self, tx: &[TxMessage]) {
152 if self.broken {
153 return;
154 }
155 self.ecat_recv(&tx[self.idx]);
156 }
157
158 pub fn init(&mut self) {
159 self.fpga.init();
160 unsafe {
161 _ = self.clear(&[]);
162 }
163 }
164
165 pub fn update(&mut self) {
166 self.update_with_sys_time(DcSysTime::now());
167 }
168
169 pub fn update_with_sys_time(&mut self, sys_time: DcSysTime) {
170 self.fpga.update_with_sys_time(sys_time);
171 self.read_fpga_state();
172 self.dc_sys_time = sys_time;
173 }
174
175 #[must_use]
176 pub const fn should_update(&self) -> bool {
177 self.reads_fpga_state
178 }
179
180 pub fn set_last_msg_id(&mut self, msg_id: MsgId) {
181 self.last_msg_id = msg_id;
182 }
183}
184
185impl CPUEmulator {
186 #[must_use]
187 pub(crate) const fn cast<T>(data: &[u8]) -> T {
188 unsafe { (data.as_ptr() as *const T).read_unaligned() }
189 }
190
191 #[must_use]
192 const fn get_addr(select: u8, addr: u16) -> u16 {
193 ((select as u16 & 0x0003) << 14) | (addr & 0x3FFF)
194 }
195
196 #[must_use]
197 pub(crate) fn bram_read(&self, select: u8, addr: u16) -> u16 {
198 let addr = Self::get_addr(select, addr);
199 self.fpga.read(addr)
200 }
201
202 pub(crate) fn bram_write(&mut self, select: u8, addr: u16, data: u16) {
203 let addr = Self::get_addr(select, addr);
204 self.fpga.write(addr, data)
205 }
206
207 pub(crate) fn bram_cpy(
208 &mut self,
209 select: u8,
210 addr_base: u16,
211 src: *const u16,
212 size: usize,
213 ) -> *const u16 {
214 let mut addr = Self::get_addr(select, addr_base);
215 let mut src = src;
216 (0..size).for_each(|_| unsafe {
217 self.fpga.write(addr, src.read());
218 addr = addr.wrapping_add(1);
219 src = src.add(1);
220 });
221 src
222 }
223
224 pub(crate) fn bram_set(&mut self, select: u8, addr_base: u16, value: u16, size: usize) {
225 let mut addr = Self::get_addr(select, addr_base);
226 (0..size).for_each(|_| {
227 self.fpga.write(addr, value);
228 addr += 1;
229 })
230 }
231
232 fn read_fpga_state(&mut self) {
233 if self.is_rx_data_used {
234 return;
235 }
236 if self.reads_fpga_state {
237 self.rx_data = FPGA_STATE_READS_FPGA_STATE_ENABLED
238 | self.bram_read(BRAM_SELECT_CONTROLLER, ADDR_FPGA_STATE) as u8;
239 } else {
240 self.rx_data &= !FPGA_STATE_READS_FPGA_STATE_ENABLED;
241 }
242 }
243
244 #[must_use]
245 fn handle_payload(&mut self, data: &[u8]) -> u8 {
246 unsafe {
247 match data[0] {
248 TAG_NOP => NO_ERR,
249 TAG_CLEAR => self.clear(data),
250 TAG_SYNC => self.synchronize(data),
251 TAG_FIRM_INFO => self.firm_info(data),
252 TAG_MODULATION => self.write_mod(data),
253 TAG_MODULATION_CHANGE_SEGMENT => self.change_mod_segment(data),
254 TAG_SILENCER => self.config_silencer(data),
255 TAG_GAIN => self.write_gain(data),
256 TAG_GAIN_CHANGE_SEGMENT => self.change_gain_segment(data),
257 TAG_GAIN_STM_CHANGE_SEGMENT => self.change_gain_stm_segment(data),
258 TAG_FOCI_STM => self.write_foci_stm(data),
259 TAG_FOCI_STM_CHANGE_SEGMENT => self.change_foci_stm_segment(data),
260 TAG_GAIN_STM => self.write_gain_stm(data),
261 TAG_FORCE_FAN => self.configure_force_fan(data),
262 TAG_READS_FPGA_STATE => self.configure_reads_fpga_state(data),
263 TAG_CONFIG_PULSE_WIDTH_ENCODER => self.config_pwe(data),
264 TAG_DEBUG => self.config_gpio_output(data),
265 TAG_EMULATE_GPIO_IN => self.emulate_gpio_in(data),
266 TAG_CPU_GPIO_OUT => self.cpu_gpio_out(data),
267 TAG_PHASE_CORRECTION => self.phase_corr(data),
268 TAG_OUTPUT_MASK => self.output_mask(data),
269 _ => ERR_NOT_SUPPORTED_TAG,
270 }
271 }
272 }
273
274 fn ecat_recv(&mut self, data: *const TxMessage) {
275 let data: &[u8] = unsafe { std::slice::from_raw_parts(data as _, EC_OUTPUT_FRAME_SIZE) };
276
277 let header = unsafe { &*(data.as_ptr() as *const Header) };
278
279 if self.last_msg_id == header.msg_id {
280 return;
281 }
282 self.last_msg_id = header.msg_id;
283
284 self.read_fpga_state();
285
286 if header.msg_id > MsgId::MAX {
287 self.err = ERR_INVALID_MSG_ID;
288 return;
289 }
290
291 self.err = self.handle_payload(&data[std::mem::size_of::<Header>()..]);
292 if self.err != NO_ERR {
293 return;
294 }
295
296 if header.slot_2_offset != 0 {
297 self.err = self.handle_payload(
298 &data[std::mem::size_of::<Header>() + header.slot_2_offset as usize..],
299 );
300 if self.err != NO_ERR {
301 return;
302 }
303 }
304
305 self.bram_write(
306 BRAM_SELECT_CONTROLLER,
307 ADDR_CTL_FLAG,
308 self.fpga_flags_internal,
309 );
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 use rand::Rng;
318
319 #[test]
320 fn cpu_idx() {
321 let mut rng = rand::rng();
322 let idx: u16 = rng.random();
323 let cpu = CPUEmulator::new(idx as _, 249);
324 assert_eq!(idx as usize, cpu.idx());
325 }
326
327 #[test]
328 fn num_transducers() {
329 let cpu = CPUEmulator::new(0, 249);
330 assert_eq!(249, cpu.num_transducers());
331 }
332
333 #[test]
334 fn dc_sys_time() {
335 let mut cpu = CPUEmulator::new(0, 249);
336
337 let sys_time = DcSysTime::now() + std::time::Duration::from_nanos(1111);
338 cpu.update_with_sys_time(sys_time);
339 assert_eq!(sys_time, cpu.dc_sys_time());
340 }
341
342 #[test]
343 fn should_update() {
344 let mut cpu = CPUEmulator::new(0, 249);
345 assert!(!cpu.should_update());
346
347 cpu.reads_fpga_state = true;
348 assert!(cpu.should_update());
349 }
350}