1use crate::arm_encoder::ArmEncoder;
6use synth_core::Result;
7use synth_synthesis::{ArmOp, MemAddr, Operand2, Reg};
8
9pub struct ResetHandlerGenerator {
11 stack_top: u32,
13 data_start: u32,
15 data_end: u32,
17 data_load_addr: u32,
19 bss_start: u32,
21 bss_end: u32,
23}
24
25impl ResetHandlerGenerator {
26 pub fn new() -> Self {
28 Self {
29 stack_top: 0x20010000, data_start: 0x20000000, data_end: 0x20000100, data_load_addr: 0x08001000, bss_start: 0x20000100, bss_end: 0x20001000, }
36 }
37
38 pub fn with_memory_layout(
40 mut self,
41 stack_top: u32,
42 data_start: u32,
43 data_end: u32,
44 data_load: u32,
45 bss_start: u32,
46 bss_end: u32,
47 ) -> Self {
48 self.stack_top = stack_top;
49 self.data_start = data_start;
50 self.data_end = data_end;
51 self.data_load_addr = data_load;
52 self.bss_start = bss_start;
53 self.bss_end = bss_end;
54 self
55 }
56
57 #[allow(clippy::vec_init_then_push)]
59 pub fn generate_instructions(&self) -> Vec<ArmOp> {
60 let mut instrs = Vec::new();
61
62 instrs.push(ArmOp::Movw {
69 rd: Reg::R0,
70 imm16: (self.data_load_addr & 0xFFFF) as u16,
71 });
72 instrs.push(ArmOp::Movt {
73 rd: Reg::R0,
74 imm16: (self.data_load_addr >> 16) as u16,
75 });
76
77 instrs.push(ArmOp::Movw {
79 rd: Reg::R1,
80 imm16: (self.data_start & 0xFFFF) as u16,
81 });
82 instrs.push(ArmOp::Movt {
83 rd: Reg::R1,
84 imm16: (self.data_start >> 16) as u16,
85 });
86
87 instrs.push(ArmOp::Movw {
89 rd: Reg::R2,
90 imm16: (self.data_end & 0xFFFF) as u16,
91 });
92 instrs.push(ArmOp::Movt {
93 rd: Reg::R2,
94 imm16: (self.data_end >> 16) as u16,
95 });
96
97 instrs.push(ArmOp::Label {
100 name: ".Lcopy_check".to_string(),
101 });
102 instrs.push(ArmOp::Cmp {
103 rn: Reg::R1,
104 op2: Operand2::Reg(Reg::R2),
105 });
106 instrs.push(ArmOp::Bhs {
108 label: ".Lcopy_done".to_string(),
109 });
110 instrs.push(ArmOp::Ldr {
113 rd: Reg::R3,
114 addr: MemAddr {
115 base: Reg::R0,
116 offset: 0,
117 offset_reg: None,
118 },
119 });
120 instrs.push(ArmOp::Add {
121 rd: Reg::R0,
122 rn: Reg::R0,
123 op2: Operand2::Imm(4),
124 });
125 instrs.push(ArmOp::Str {
127 rd: Reg::R3,
128 addr: MemAddr {
129 base: Reg::R1,
130 offset: 0,
131 offset_reg: None,
132 },
133 });
134 instrs.push(ArmOp::Add {
135 rd: Reg::R1,
136 rn: Reg::R1,
137 op2: Operand2::Imm(4),
138 });
139 instrs.push(ArmOp::B {
141 label: ".Lcopy_check".to_string(),
142 });
143 instrs.push(ArmOp::Label {
144 name: ".Lcopy_done".to_string(),
145 });
146
147 instrs.push(ArmOp::Movw {
150 rd: Reg::R0,
151 imm16: (self.bss_start & 0xFFFF) as u16,
152 });
153 instrs.push(ArmOp::Movt {
154 rd: Reg::R0,
155 imm16: (self.bss_start >> 16) as u16,
156 });
157
158 instrs.push(ArmOp::Movw {
159 rd: Reg::R1,
160 imm16: (self.bss_end & 0xFFFF) as u16,
161 });
162 instrs.push(ArmOp::Movt {
163 rd: Reg::R1,
164 imm16: (self.bss_end >> 16) as u16,
165 });
166
167 instrs.push(ArmOp::Mov {
168 rd: Reg::R2,
169 op2: Operand2::Imm(0),
170 });
171
172 instrs.push(ArmOp::Label {
175 name: ".Lzero_check".to_string(),
176 });
177 instrs.push(ArmOp::Cmp {
178 rn: Reg::R0,
179 op2: Operand2::Reg(Reg::R1),
180 });
181 instrs.push(ArmOp::Bhs {
183 label: ".Lzero_done".to_string(),
184 });
185 instrs.push(ArmOp::Str {
186 rd: Reg::R2,
187 addr: MemAddr {
188 base: Reg::R0,
189 offset: 0,
190 offset_reg: None,
191 },
192 });
193 instrs.push(ArmOp::Add {
194 rd: Reg::R0,
195 rn: Reg::R0,
196 op2: Operand2::Imm(4),
197 });
198 instrs.push(ArmOp::B {
200 label: ".Lzero_check".to_string(),
201 });
202 instrs.push(ArmOp::Label {
203 name: ".Lzero_done".to_string(),
204 });
205
206 instrs.push(ArmOp::Bl {
208 label: "main".to_string(),
209 });
210
211 instrs.push(ArmOp::B {
213 label: ".".to_string(), });
215
216 instrs
217 }
218
219 pub fn generate_assembly(&self) -> String {
221 let mut asm = String::new();
222
223 asm.push_str(" .syntax unified\n");
224 asm.push_str(" .cpu cortex-m3\n");
225 asm.push_str(" .fpu softvfp\n");
226 asm.push_str(" .thumb\n\n");
227
228 asm.push_str(" .section .text.Reset_Handler\n");
229 asm.push_str(" .weak Reset_Handler\n");
230 asm.push_str(" .type Reset_Handler, %function\n");
231 asm.push_str("Reset_Handler:\n");
232
233 asm.push_str(" /* Copy data section from Flash to RAM */\n");
235 asm.push_str(" ldr r0, =_sidata /* start of .data in Flash */\n");
236 asm.push_str(" ldr r1, =_sdata /* start of .data in RAM */\n");
237 asm.push_str(" ldr r2, =_edata /* end of .data in RAM */\n");
238 asm.push_str(" movs r3, #0\n");
239 asm.push_str(" b LoopCopyDataInit\n\n");
240
241 asm.push_str("CopyDataInit:\n");
242 asm.push_str(" ldr r4, [r0, r3]\n");
243 asm.push_str(" str r4, [r1, r3]\n");
244 asm.push_str(" adds r3, r3, #4\n\n");
245
246 asm.push_str("LoopCopyDataInit:\n");
247 asm.push_str(" adds r4, r1, r3\n");
248 asm.push_str(" cmp r4, r2\n");
249 asm.push_str(" bcc CopyDataInit\n\n");
250
251 asm.push_str(" /* Zero fill .bss section */\n");
253 asm.push_str(" ldr r2, =_sbss\n");
254 asm.push_str(" ldr r4, =_ebss\n");
255 asm.push_str(" movs r3, #0\n");
256 asm.push_str(" b LoopFillZerobss\n\n");
257
258 asm.push_str("FillZerobss:\n");
259 asm.push_str(" str r3, [r2]\n");
260 asm.push_str(" adds r2, r2, #4\n\n");
261
262 asm.push_str("LoopFillZerobss:\n");
263 asm.push_str(" cmp r2, r4\n");
264 asm.push_str(" bcc FillZerobss\n\n");
265
266 asm.push_str(" /* Call static constructors */\n");
268 asm.push_str(" bl __libc_init_array\n\n");
269
270 asm.push_str(" /* Call main() */\n");
272 asm.push_str(" bl main\n\n");
273
274 asm.push_str("LoopForever:\n");
276 asm.push_str(" b LoopForever\n\n");
277
278 asm.push_str(" .size Reset_Handler, .-Reset_Handler\n");
279
280 asm
281 }
282
283 pub fn generate_binary(&self) -> Result<Vec<u8>> {
285 self.generate_binary_for_isa(false)
286 }
287
288 pub fn generate_binary_for_isa(&self, thumb_mode: bool) -> Result<Vec<u8>> {
290 let encoder = if thumb_mode {
291 ArmEncoder::new_thumb2()
292 } else {
293 ArmEncoder::new_arm32()
294 };
295 let instrs = self.generate_instructions();
296
297 let mut code = Vec::new();
298 for instr in &instrs {
299 let encoded = encoder.encode(instr)?;
300 code.extend_from_slice(&encoded);
301 }
302
303 Ok(code)
304 }
305}
306
307impl Default for ResetHandlerGenerator {
308 fn default() -> Self {
309 Self::new()
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 #[test]
318 fn test_reset_handler_creation() {
319 let handler = ResetHandlerGenerator::new();
320 assert_eq!(handler.stack_top, 0x20010000);
321 }
322
323 #[test]
324 fn test_reset_handler_instructions() {
325 let handler = ResetHandlerGenerator::new();
326 let instrs = handler.generate_instructions();
327 assert!(!instrs.is_empty());
328
329 assert!(matches!(instrs[instrs.len() - 2], ArmOp::Bl { .. }));
331 assert!(matches!(instrs[instrs.len() - 1], ArmOp::B { .. }));
332 }
333
334 #[test]
335 fn test_reset_handler_binary() {
336 let handler = ResetHandlerGenerator::new();
337 let binary = handler.generate_binary().unwrap();
338 assert!(!binary.is_empty());
339 assert_eq!(binary.len() % 4, 0); }
341
342 #[test]
343 fn test_reset_handler_assembly() {
344 let handler = ResetHandlerGenerator::new();
345 let asm = handler.generate_assembly();
346
347 assert!(asm.contains("Reset_Handler:"));
348 assert!(asm.contains("CopyDataInit"));
349 assert!(asm.contains("FillZerobss"));
350 assert!(asm.contains("bl main"));
351 }
352
353 #[test]
354 fn test_custom_memory_layout() {
355 let handler = ResetHandlerGenerator::new().with_memory_layout(
356 0x20020000, 0x20000000, 0x20000200, 0x08002000, 0x20000200, 0x20002000,
358 );
359
360 assert_eq!(handler.stack_top, 0x20020000);
361 assert_eq!(handler.data_start, 0x20000000);
362 }
363}