autd3_firmware_emulator/cpu/operation/
modulation.rs1use crate::{CPUEmulator, cpu::params::*};
2
3pub const MOD_BUF_PAGE_SIZE_WIDTH: u16 = 15;
4pub const MOD_BUF_PAGE_SIZE: u16 = 1 << MOD_BUF_PAGE_SIZE_WIDTH;
5pub const MOD_BUF_PAGE_SIZE_MASK: u16 = MOD_BUF_PAGE_SIZE - 1;
6
7#[repr(C, align(2))]
8#[derive(Clone, Copy)]
9struct ModulationHead {
10 tag: u8,
11 flag: u8,
12 size: u8,
13 transition_mode: u8,
14 freq_div: u16,
15 rep: u16,
16 transition_value: u64,
17}
18
19#[repr(C, align(2))]
20#[derive(Clone, Copy)]
21struct ModulationSubseq {
22 tag: u8,
23 flag: u8,
24 size: u16,
25}
26
27#[repr(C, align(2))]
28union Modulation {
29 head: ModulationHead,
30 subseq: ModulationSubseq,
31}
32
33#[repr(C, align(2))]
34#[derive(Clone, Copy)]
35struct ModulationUpdate {
36 tag: u8,
37 segment: u8,
38 transition_mode: u8,
39 __: [u8; 5],
40 transition_value: u64,
41}
42
43impl CPUEmulator {
44 #[must_use]
45 pub(crate) unsafe fn mod_segment_update(&mut self, segment: u8, mode: u8, value: u64) -> u8 {
46 self.bram_write(
47 BRAM_SELECT_CONTROLLER,
48 ADDR_MOD_REQ_RD_SEGMENT,
49 segment as _,
50 );
51 if (mode == TRANSITION_MODE_SYS_TIME)
52 && (value < self.dc_sys_time.sys_time() + SYS_TIME_TRANSITION_MARGIN)
53 {
54 return ERR_MISS_TRANSITION_TIME;
55 }
56 self.bram_write(BRAM_SELECT_CONTROLLER, ADDR_MOD_TRANSITION_MODE, mode as _);
57 self.bram_cpy(
58 BRAM_SELECT_CONTROLLER,
59 ADDR_MOD_TRANSITION_VALUE_0,
60 &raw const value as _,
61 std::mem::size_of::<u64>() >> 1,
62 );
63 self.set_and_wait_update(CTL_FLAG_MOD_SET);
64 NO_ERR
65 }
66
67 pub(crate) unsafe fn change_mod_wr_segment(&mut self, segment: u16) {
68 self.bram_write(BRAM_SELECT_CONTROLLER, ADDR_MOD_MEM_WR_SEGMENT, segment);
69 }
70
71 pub(crate) unsafe fn change_mod_wr_page(&mut self, page: u16) {
72 self.bram_write(BRAM_SELECT_CONTROLLER, ADDR_MOD_MEM_WR_PAGE, page as _);
73 }
74
75 #[must_use]
76 pub(crate) unsafe fn write_mod(&mut self, data: &[u8]) -> u8 {
77 unsafe {
78 let d = Self::cast::<Modulation>(data);
79
80 let segment = if (d.head.flag & MODULATION_FLAG_SEGMENT) != 0 {
81 1
82 } else {
83 0
84 };
85
86 let write;
87 let data = if (d.subseq.flag & MODULATION_FLAG_BEGIN) == MODULATION_FLAG_BEGIN {
88 if Self::validate_transition_mode(
89 self.mod_segment,
90 segment,
91 d.head.rep,
92 d.head.transition_mode,
93 ) {
94 return ERR_INVALID_TRANSITION_MODE;
95 }
96
97 if self.validate_silencer_settings(
98 self.stm_freq_div[self.stm_segment as usize],
99 d.head.freq_div,
100 ) {
101 return ERR_INVALID_SILENCER_SETTING;
102 }
103
104 if d.head.transition_mode != TRANSITION_MODE_NONE {
105 self.mod_segment = segment;
106 }
107 self.mod_cycle = 0;
108 self.mod_transition_mode = d.head.transition_mode;
109 self.mod_transition_value = d.head.transition_value;
110 self.mod_freq_div[segment as usize] = d.head.freq_div;
111 self.mod_rep[segment as usize] = d.head.rep;
112
113 self.bram_write(
114 BRAM_SELECT_CONTROLLER,
115 ADDR_MOD_FREQ_DIV0 + segment as u16,
116 d.head.freq_div,
117 );
118 self.bram_write(
119 BRAM_SELECT_CONTROLLER,
120 ADDR_MOD_REP0 + segment as u16,
121 d.head.rep,
122 );
123
124 self.change_mod_wr_segment(segment as _);
125 self.change_mod_wr_page(0);
126
127 write = d.head.size as u16;
128 data[std::mem::size_of::<ModulationHead>()..].as_ptr() as *const u16
129 } else {
130 write = d.subseq.size;
131 data[std::mem::size_of::<ModulationSubseq>()..].as_ptr() as *const u16
132 };
133
134 let page_capacity =
135 MOD_BUF_PAGE_SIZE - ((self.mod_cycle as u16) & MOD_BUF_PAGE_SIZE_MASK);
136 if write < page_capacity {
137 self.bram_cpy(
138 BRAM_SELECT_MOD,
139 (self.mod_cycle as u16 & MOD_BUF_PAGE_SIZE_MASK) >> 1,
140 data,
141 ((write + 1) >> 1) as usize,
142 );
143 self.mod_cycle += write as u32;
144 } else {
145 self.bram_cpy(
146 BRAM_SELECT_MOD,
147 (self.mod_cycle as u16 & MOD_BUF_PAGE_SIZE_MASK) >> 1,
148 data,
149 (page_capacity >> 1) as usize,
150 );
151 self.mod_cycle += page_capacity as u32;
152
153 self.change_mod_wr_page(
154 (((self.mod_cycle as u16) & !MOD_BUF_PAGE_SIZE_MASK) >> MOD_BUF_PAGE_SIZE_WIDTH)
155 as _,
156 );
157
158 self.bram_cpy(
159 BRAM_SELECT_MOD,
160 0,
161 data.add((page_capacity >> 1) as _),
162 ((write - page_capacity + 1) >> 1) as _,
163 );
164 self.mod_cycle += (write - page_capacity) as u32;
165 }
166
167 if (d.subseq.flag & MODULATION_FLAG_END) == MODULATION_FLAG_END {
168 self.bram_write(
169 BRAM_SELECT_CONTROLLER,
170 ADDR_MOD_CYCLE0 + segment as u16,
171 (self.mod_cycle.max(1) - 1) as _,
172 );
173
174 if (d.subseq.flag & MODULATION_FLAG_UPDATE) == MODULATION_FLAG_UPDATE {
175 return self.mod_segment_update(
176 segment,
177 self.mod_transition_mode,
178 self.mod_transition_value,
179 );
180 }
181 }
182
183 NO_ERR
184 }
185 }
186
187 #[must_use]
188 pub(crate) unsafe fn change_mod_segment(&mut self, data: &[u8]) -> u8 {
189 unsafe {
190 let d = Self::cast::<ModulationUpdate>(data);
191
192 if Self::validate_transition_mode(
193 self.mod_segment,
194 d.segment,
195 self.mod_rep[d.segment as usize],
196 d.transition_mode,
197 ) {
198 return ERR_INVALID_TRANSITION_MODE;
199 }
200
201 if self.validate_silencer_settings(
202 self.stm_freq_div[self.stm_segment as usize],
203 self.mod_freq_div[d.segment as usize],
204 ) {
205 return ERR_INVALID_SILENCER_SETTING;
206 }
207
208 self.mod_segment = d.segment;
209 self.mod_segment_update(d.segment, d.transition_mode, d.transition_value)
210 }
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn mem_layout() {
220 assert_eq!(16, std::mem::size_of::<ModulationHead>());
221 assert_eq!(0, std::mem::offset_of!(ModulationHead, tag));
222 assert_eq!(1, std::mem::offset_of!(ModulationHead, flag));
223 assert_eq!(2, std::mem::offset_of!(ModulationHead, size));
224 assert_eq!(3, std::mem::offset_of!(ModulationHead, transition_mode));
225 assert_eq!(4, std::mem::offset_of!(ModulationHead, freq_div));
226 assert_eq!(6, std::mem::offset_of!(ModulationHead, rep));
227 assert_eq!(8, std::mem::offset_of!(ModulationHead, transition_value));
228
229 assert_eq!(4, std::mem::size_of::<ModulationSubseq>());
230 assert_eq!(0, std::mem::offset_of!(ModulationSubseq, tag));
231 assert_eq!(1, std::mem::offset_of!(ModulationSubseq, flag));
232 assert_eq!(2, std::mem::offset_of!(ModulationSubseq, size));
233
234 assert_eq!(16, std::mem::size_of::<Modulation>());
235 assert_eq!(0, std::mem::offset_of!(Modulation, head));
236 assert_eq!(0, std::mem::offset_of!(Modulation, subseq));
237
238 assert_eq!(16, std::mem::size_of::<ModulationUpdate>());
239 assert_eq!(0, std::mem::offset_of!(ModulationUpdate, tag));
240 assert_eq!(1, std::mem::offset_of!(ModulationUpdate, segment));
241 assert_eq!(2, std::mem::offset_of!(ModulationUpdate, transition_mode));
242 assert_eq!(8, std::mem::offset_of!(ModulationUpdate, transition_value));
243 }
244}