1use std::{sync::Arc, time::Duration};
4
5use probe_rs_target::{Architecture, CoreType, InstructionSet};
6
7use crate::{
8 CoreInformation, CoreInterface, CoreRegister, CoreStatus, Error, HaltReason, MemoryInterface,
9 architecture::xtensa::{
10 arch::{
11 CpuRegister, Register, SpecialRegister,
12 instruction::{Instruction, InstructionEncoding},
13 },
14 communication_interface::{
15 DebugCause, IBreakEn, ProgramStatus, WindowProperties, XtensaCommunicationInterface,
16 },
17 registers::{FP, PC, RA, SP, XTENSA_CORE_REGISTERS},
18 sequences::XtensaDebugSequence,
19 xdm::PowerStatus,
20 },
21 core::{
22 BreakpointCause,
23 registers::{CoreRegisters, RegisterId, RegisterValue},
24 },
25 memory::CoreMemoryInterface,
26 semihosting::{SemihostingCommand, decode_semihosting_syscall},
27};
28
29pub(crate) mod arch;
30pub mod xdm;
31
32pub mod communication_interface;
33pub(crate) mod register_cache;
34pub mod registers;
35pub mod sequences;
36
37#[derive(Debug)]
39pub struct XtensaCoreState {
40 enabled: bool,
42
43 breakpoints_enabled: bool,
45
46 breakpoint_set: [bool; 2],
50
51 pc_written: bool,
54
55 semihosting_command: Option<SemihostingCommand>,
57}
58
59impl XtensaCoreState {
60 pub(crate) fn new() -> Self {
62 Self {
63 enabled: false,
64 breakpoints_enabled: false,
65 breakpoint_set: [false; 2],
66 pc_written: false,
67 semihosting_command: None,
68 }
69 }
70
71 fn breakpoint_mask(&self) -> u32 {
73 self.breakpoint_set
74 .iter()
75 .enumerate()
76 .fold(0, |acc, (i, &set)| if set { acc | (1 << i) } else { acc })
77 }
78}
79
80pub struct Xtensa<'probe> {
82 interface: XtensaCommunicationInterface<'probe>,
83 state: &'probe mut XtensaCoreState,
84 sequence: Arc<dyn XtensaDebugSequence>,
85}
86
87impl<'probe> Xtensa<'probe> {
88 const IBREAKA_REGS: [SpecialRegister; 2] =
89 [SpecialRegister::IBreakA0, SpecialRegister::IBreakA1];
90
91 pub fn new(
93 interface: XtensaCommunicationInterface<'probe>,
94 state: &'probe mut XtensaCoreState,
95 sequence: Arc<dyn XtensaDebugSequence>,
96 ) -> Result<Self, Error> {
97 let mut this = Self {
98 interface,
99 state,
100 sequence,
101 };
102
103 this.on_attach()?;
104
105 Ok(this)
106 }
107
108 fn on_attach(&mut self) -> Result<(), Error> {
109 let core_reset;
111 if self.state.enabled {
112 let status = self.interface.xdm.power_status({
113 let mut clear_value = PowerStatus(0);
114 clear_value.set_core_was_reset(true);
115 clear_value.set_debug_was_reset(true);
116 clear_value
117 })?;
118 core_reset = status.core_was_reset() || !status.core_domain_on();
119 let debug_reset = status.debug_was_reset() || !status.debug_domain_on();
120
121 if core_reset {
122 tracing::debug!("Core was reset");
123 *self.state = XtensaCoreState::new();
124 }
125 if debug_reset {
126 tracing::debug!("Debug was reset");
127 self.state.enabled = false;
128 }
129 } else {
130 core_reset = true;
131 }
132
133 if !self.state.enabled {
135 self.interface.enter_debug_mode()?;
137 self.state.enabled = true;
138
139 if core_reset {
140 let was_running = self
142 .interface
143 .halt_with_previous(Duration::from_millis(500))?;
144
145 self.sequence.on_connect(&mut self.interface)?;
146
147 if was_running {
148 self.run()?;
149 }
150 }
151 }
152
153 Ok(())
154 }
155
156 fn core_info(&mut self) -> Result<CoreInformation, Error> {
157 let pc = self.read_core_reg(self.program_counter().id)?;
158
159 Ok(CoreInformation { pc: pc.try_into()? })
160 }
161
162 fn skip_breakpoint(&mut self) -> Result<(), Error> {
163 self.state.semihosting_command = None;
164 if !self.state.pc_written {
165 let debug_cause = self.debug_cause()?;
166
167 let pc_increment = if debug_cause.break_instruction() {
168 3
169 } else if debug_cause.break_n_instruction() {
170 2
171 } else {
172 0
173 };
174
175 if pc_increment > 0 {
176 let mut pc_value = self.interface.read_register_untyped(Register::CurrentPc)?;
178 pc_value += pc_increment;
179 self.interface
180 .write_register_untyped(Register::CurrentPc, pc_value)?;
181 } else if debug_cause.ibreak_exception() {
182 let pc_value = self.interface.read_register_untyped(Register::CurrentPc)?;
183 let bps = self.hw_breakpoints()?;
184 if let Some(bp_unit) = bps.iter().position(|bp| *bp == Some(pc_value as u64)) {
185 self.clear_hw_breakpoint(bp_unit)?;
187 let ps = self.current_ps()?;
189 self.interface.step(1, ps.intlevel())?;
190 self.set_hw_breakpoint(bp_unit, pc_value as u64)?;
192 }
193 }
194 }
195
196 Ok(())
197 }
198
199 fn check_for_semihosting(&mut self) -> Result<Option<SemihostingCommand>, Error> {
202 const SEMI_BREAK: u32 = const {
203 let InstructionEncoding::Narrow(bytes) = Instruction::Break(1, 14).encode();
204 bytes
205 };
206
207 if let Some(command) = self.state.semihosting_command {
209 return Ok(Some(command));
210 }
211
212 let pc: u64 = self.read_core_reg(self.program_counter().id)?.try_into()?;
213
214 let mut actual_instruction = [0u8; 3];
215 self.read_8(pc, &mut actual_instruction)?;
216 let actual_instruction = u32::from_le_bytes([
217 actual_instruction[0],
218 actual_instruction[1],
219 actual_instruction[2],
220 0,
221 ]);
222
223 tracing::debug!("Semihosting check pc={pc:#x} instruction={actual_instruction:#010x}");
224
225 let command = if actual_instruction == SEMI_BREAK {
226 let syscall = decode_semihosting_syscall(self)?;
227 if let SemihostingCommand::Unknown(details) = syscall {
228 self.sequence
229 .clone()
230 .on_unknown_semihosting_command(self, details)?
231 } else {
232 Some(syscall)
233 }
234 } else {
235 None
236 };
237 self.state.semihosting_command = command;
238
239 Ok(command)
240 }
241
242 fn on_halted(&mut self) -> Result<(), Error> {
243 self.state.pc_written = false;
244
245 let status = self.status()?;
249 tracing::debug!("Core halted: {:#?}", status);
250
251 if status.is_halted() {
252 self.sequence.on_halt(&mut self.interface)?;
253 }
254
255 Ok(())
256 }
257
258 fn halt_with_previous(&mut self, timeout: Duration) -> Result<bool, Error> {
259 let was_running = self.interface.halt_with_previous(timeout)?;
260 if was_running {
261 self.on_halted()?;
262 }
263
264 Ok(was_running)
265 }
266
267 fn halted_access<F, T>(&mut self, op: F) -> Result<T, Error>
268 where
269 F: FnOnce(&mut Self) -> Result<T, Error>,
270 {
271 let was_running = self.halt_with_previous(Duration::from_millis(100))?;
272
273 let result = op(self);
274
275 if was_running {
276 self.run()?;
277 }
278
279 result
280 }
281
282 fn current_ps(&mut self) -> Result<ProgramStatus, Error> {
283 Ok(self
286 .interface
287 .read_register_untyped(Register::CurrentPs)
288 .map(ProgramStatus)?)
289 }
290
291 fn debug_cause(&mut self) -> Result<DebugCause, Error> {
292 Ok(self.interface.read_register::<DebugCause>()?)
293 }
294
295 fn spill_registers(&mut self) -> Result<(), Error> {
296 if self.current_ps()?.excm() {
297 return Ok(());
300 }
301 if self.current_ps()?.woe() {
302 let register_file = self.read_window_registers()?;
303 register_file.spill(&mut self.interface)?;
306 }
307
308 Ok(())
309 }
310
311 fn read_window_registers(&mut self) -> Result<RegisterFile, Error> {
312 let register_file = RegisterFile::read(
313 self.interface.core_properties().window_option_properties,
314 &mut self.interface,
315 )?;
316
317 let window_reg_count = register_file.core.window_regs;
318 for reg in 0..window_reg_count {
319 let reg =
320 CpuRegister::try_from(reg).expect("Could not convert register to CpuRegister");
321 let value = register_file.read_register(reg);
322 self.interface
323 .state
324 .register_cache
325 .store(Register::Cpu(reg), value);
326 }
327 Ok(register_file)
328 }
329}
330
331impl CoreMemoryInterface for Xtensa<'_> {
332 type ErrorType = Error;
333
334 fn memory(&self) -> &dyn MemoryInterface<Self::ErrorType> {
335 &self.interface
336 }
337 fn memory_mut(&mut self) -> &mut dyn MemoryInterface<Self::ErrorType> {
338 &mut self.interface
339 }
340}
341
342impl CoreInterface for Xtensa<'_> {
343 fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
344 self.interface.wait_for_core_halted(timeout)?;
345 self.on_halted()?;
346
347 Ok(())
348 }
349
350 fn core_halted(&mut self) -> Result<bool, Error> {
351 let was_halted = self.interface.state.is_halted;
352 let is_halted = self.interface.core_halted()?;
353
354 if !was_halted && is_halted {
355 self.on_halted()?;
356 }
357
358 Ok(is_halted)
359 }
360
361 fn status(&mut self) -> Result<CoreStatus, Error> {
362 let status = if self.core_halted()? {
363 let debug_cause = self.debug_cause()?;
364
365 let mut reason = debug_cause.halt_reason();
366 if reason == HaltReason::Breakpoint(BreakpointCause::Software) {
367 self.state.pc_written = false;
369 if let Some(cmd) = self.check_for_semihosting()? {
371 reason = HaltReason::Breakpoint(BreakpointCause::Semihosting(cmd));
372 }
373 }
374
375 CoreStatus::Halted(reason)
376 } else {
377 CoreStatus::Running
378 };
379
380 Ok(status)
381 }
382
383 fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
384 self.halt_with_previous(timeout)?;
385
386 self.core_info()
387 }
388
389 fn run(&mut self) -> Result<(), Error> {
390 self.skip_breakpoint()?;
391 Ok(self.interface.resume_core()?)
392 }
393
394 fn reset(&mut self) -> Result<(), Error> {
395 self.reset_and_halt(Duration::from_millis(500))?;
396
397 self.run()
398 }
399
400 fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
401 self.state.semihosting_command = None;
402 self.sequence
403 .reset_system_and_halt(&mut self.interface, timeout)?;
404
405 self.on_halted()?;
406
407 self.on_attach()?;
409
410 self.core_info()
411 }
412
413 fn step(&mut self) -> Result<CoreInformation, Error> {
414 self.skip_breakpoint()?;
415
416 let ps = self.current_ps()?;
418 self.interface.step(1, ps.intlevel())?;
419
420 self.on_halted()?;
421
422 self.core_info()
423 }
424
425 fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error> {
426 self.halted_access(|this| {
427 let register = Register::try_from(address)?;
428 let value = this.interface.read_register_untyped(register)?;
429
430 Ok(RegisterValue::U32(value))
431 })
432 }
433
434 fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error> {
435 self.halted_access(|this| {
436 let value: u32 = value.try_into()?;
437
438 if address == this.program_counter().id {
439 this.state.pc_written = true;
440 }
441
442 let register = Register::try_from(address)?;
443 this.interface.write_register_untyped(register, value)?;
444
445 Ok(())
446 })
447 }
448
449 fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
450 Ok(self.interface.available_breakpoint_units())
451 }
452
453 fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
454 self.halted_access(|this| {
455 let mut breakpoints = Vec::with_capacity(this.available_breakpoint_units()? as usize);
456
457 let enabled_breakpoints = this.interface.read_register::<IBreakEn>()?;
458
459 for i in 0..this.available_breakpoint_units()? as usize {
460 let is_enabled = enabled_breakpoints.0 & (1 << i) != 0;
461 let breakpoint = if is_enabled {
462 let address = this
463 .interface
464 .read_register_untyped(Self::IBREAKA_REGS[i])?;
465
466 Some(address as u64)
467 } else {
468 None
469 };
470
471 breakpoints.push(breakpoint);
472 }
473
474 Ok(breakpoints)
475 })
476 }
477
478 fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
479 self.halted_access(|this| {
480 this.state.breakpoints_enabled = state;
481 let mask = if state {
482 this.state.breakpoint_mask()
483 } else {
484 0
485 };
486
487 this.interface.write_register(IBreakEn(mask))?;
488
489 Ok(())
490 })
491 }
492
493 fn set_hw_breakpoint(&mut self, unit_index: usize, addr: u64) -> Result<(), Error> {
494 self.halted_access(|this| {
495 this.state.breakpoint_set[unit_index] = true;
496 this.interface
497 .write_register_untyped(Self::IBREAKA_REGS[unit_index], addr as u32)?;
498
499 if this.state.breakpoints_enabled {
500 let mask = this.state.breakpoint_mask();
501 this.interface.write_register(IBreakEn(mask))?;
502 }
503
504 Ok(())
505 })
506 }
507
508 fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), Error> {
509 self.halted_access(|this| {
510 this.state.breakpoint_set[unit_index] = false;
511
512 if this.state.breakpoints_enabled {
513 let mask = this.state.breakpoint_mask();
514 this.interface.write_register(IBreakEn(mask))?;
515 }
516
517 Ok(())
518 })
519 }
520
521 fn registers(&self) -> &'static CoreRegisters {
522 &XTENSA_CORE_REGISTERS
523 }
524
525 fn program_counter(&self) -> &'static CoreRegister {
526 &PC
527 }
528
529 fn frame_pointer(&self) -> &'static CoreRegister {
530 &FP
531 }
532
533 fn stack_pointer(&self) -> &'static CoreRegister {
534 &SP
535 }
536
537 fn return_address(&self) -> &'static CoreRegister {
538 &RA
539 }
540
541 fn hw_breakpoints_enabled(&self) -> bool {
542 self.state.breakpoints_enabled
543 }
544
545 fn architecture(&self) -> Architecture {
546 Architecture::Xtensa
547 }
548
549 fn core_type(&self) -> CoreType {
550 CoreType::Xtensa
551 }
552
553 fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
554 Ok(InstructionSet::Xtensa)
556 }
557
558 fn fpu_support(&mut self) -> Result<bool, Error> {
559 Ok(false)
561 }
562
563 fn floating_point_register_count(&mut self) -> Result<usize, Error> {
564 Ok(0)
566 }
567
568 fn reset_catch_set(&mut self) -> Result<(), Error> {
569 Err(Error::NotImplemented("reset_catch_set"))
570 }
571
572 fn reset_catch_clear(&mut self) -> Result<(), Error> {
573 Err(Error::NotImplemented("reset_catch_clear"))
574 }
575
576 fn debug_core_stop(&mut self) -> Result<(), Error> {
577 self.interface.leave_debug_mode()?;
578 Ok(())
579 }
580
581 fn spill_registers(&mut self) -> Result<(), Error> {
582 self.spill_registers()
583 }
584}
585
586struct RegisterFile {
587 core: WindowProperties,
588 registers: Vec<u32>,
589 window_base: u8,
590 window_start: u32,
591}
592
593impl RegisterFile {
594 fn read(
595 xtensa: WindowProperties,
596 interface: &mut XtensaCommunicationInterface<'_>,
597 ) -> Result<Self, Error> {
598 let window_base_result = interface.schedule_read_register(SpecialRegister::Windowbase)?;
599 let window_start_result = interface.schedule_read_register(SpecialRegister::Windowstart)?;
600
601 let mut register_values = Vec::with_capacity(xtensa.num_aregs as usize);
602
603 let ar0 = arch::CpuRegister::A0 as u8;
604
605 interface.restore_registers()?;
608
609 for ar in ar0..ar0 + xtensa.window_regs {
612 let reg = CpuRegister::try_from(ar)?;
613 interface.state.register_cache.remove(reg.into());
614 }
615
616 let mut regs = Vec::with_capacity(xtensa.window_regs as usize);
617 for _ in 0..xtensa.num_aregs / xtensa.window_regs {
618 for ar in ar0..ar0 + xtensa.window_regs {
620 let reg = CpuRegister::try_from(ar)?;
621 let deferred_result = interface.schedule_read_register(reg)?;
622 regs.push(deferred_result);
623 }
624
625 let rotw_arg = xtensa.window_regs / xtensa.rotw_rotates;
627 interface
628 .xdm
629 .schedule_execute_instruction(Instruction::Rotw(rotw_arg));
630
631 for deferred in regs.drain(..) {
633 let result = interface.read_deferred_result(deferred)?;
634 register_values.push(result);
635 }
636
637 for ar in ar0..ar0 + xtensa.window_regs {
640 let reg = CpuRegister::try_from(ar)?;
641 interface.state.register_cache.remove(reg.into());
642 }
643 }
644
645 interface
647 .xdm
648 .execute()
649 .expect("Failed to execute read. This shouldn't happen.");
650
651 let window_base = interface.read_deferred_result(window_base_result)?;
654
655 let window_start = interface.read_deferred_result(window_start_result)?;
671
672 register_values.rotate_right((window_base * xtensa.rotw_rotates as u32) as usize);
675
676 Ok(Self {
677 core: xtensa,
678 registers: register_values,
679 window_base: window_base as u8,
680 window_start,
681 })
682 }
683
684 fn spill(&self, xtensa: &mut XtensaCommunicationInterface<'_>) -> Result<(), Error> {
685 if !self.core.has_windowed_registers {
686 return Ok(());
687 }
688
689 if self.window_start == 0 {
690 return Ok(());
692 }
693
694 let mut window_base = self.next_window_base(self.window_base);
714
715 while let Some(window) = RegisterWindow::at_windowbase(self, window_base) {
716 window.spill(xtensa)?;
717 window_base = self.next_window_base(window_base);
718
719 if window_base == self.window_base {
720 break;
725 }
726 }
727
728 Ok(())
729 }
730
731 fn is_window_start(&self, windowbase: u8) -> bool {
732 self.window_start & 1 << (windowbase % self.core.windowbase_size()) != 0
733 }
734
735 fn next_window_base(&self, window_base: u8) -> u8 {
736 let mut wb = (window_base + 1) % self.core.windowbase_size();
737 while wb != window_base {
738 if self.is_window_start(wb) {
739 break;
740 }
741 wb = (wb + 1) % self.core.windowbase_size();
742 }
743
744 wb
745 }
746
747 fn wb_offset_to_canonical(&self, idx: u8) -> u8 {
748 (idx + self.window_base * self.core.rotw_rotates) % self.core.num_aregs
749 }
750
751 fn read_register(&self, reg: CpuRegister) -> u32 {
752 let index = self.wb_offset_to_canonical(reg as u8);
753 self.registers[index as usize]
754 }
755}
756
757struct RegisterWindow<'a> {
758 window_base: u8,
759
760 window_size: u8,
762
763 file: &'a RegisterFile,
764}
765
766impl<'a> RegisterWindow<'a> {
767 fn at_windowbase(file: &'a RegisterFile, window_base: u8) -> Option<Self> {
768 if !file.is_window_start(window_base) {
769 return None;
770 }
771
772 let next_window_base = file.next_window_base(window_base);
773 let window_size = (next_window_base + file.core.windowbase_size() - window_base)
774 % file.core.windowbase_size();
775
776 Some(Self {
777 window_base,
778 file,
779 window_size: window_size.min(3),
780 })
781 }
782
783 fn read_register(&self, reg: CpuRegister) -> u32 {
785 let index = self.wb_offset_to_canonical(reg as u8);
786 self.file.registers[index as usize]
787 }
788
789 fn wb_offset_to_canonical(&self, idx: u8) -> u8 {
790 (idx + self.window_base * self.file.core.rotw_rotates) % self.file.core.num_aregs
791 }
792
793 fn spill(&self, interface: &mut XtensaCommunicationInterface<'_>) -> Result<(), Error> {
794 let a0_a3 = [
796 self.read_register(CpuRegister::A0),
797 self.read_register(CpuRegister::A1),
798 self.read_register(CpuRegister::A2),
799 self.read_register(CpuRegister::A3),
800 ];
801
802 match self.window_size {
803 0 => {} 1 => interface.write_32(self.read_register(CpuRegister::A5) as u64 - 16, &a0_a3)?,
806
807 2 => {
809 let sp = interface.read_word_32(self.read_register(CpuRegister::A1) as u64 - 12)?;
810
811 interface.write_32(self.read_register(CpuRegister::A9) as u64 - 16, &a0_a3)?;
812
813 let regs = [
814 self.read_register(CpuRegister::A4),
815 self.read_register(CpuRegister::A5),
816 self.read_register(CpuRegister::A6),
817 self.read_register(CpuRegister::A7),
818 ];
819 interface.write_32(sp as u64 - 32, ®s)?;
820 }
821
822 3 => {
824 let sp = interface.read_word_32(self.read_register(CpuRegister::A1) as u64 - 12)?;
825 interface.write_32(self.read_register(CpuRegister::A13) as u64 - 16, &a0_a3)?;
826
827 let regs = [
828 self.read_register(CpuRegister::A4),
829 self.read_register(CpuRegister::A5),
830 self.read_register(CpuRegister::A6),
831 self.read_register(CpuRegister::A7),
832 self.read_register(CpuRegister::A8),
833 self.read_register(CpuRegister::A9),
834 self.read_register(CpuRegister::A10),
835 self.read_register(CpuRegister::A11),
836 ];
837 interface.write_32(sp as u64 - 48, ®s)?;
838 }
839
840 _ => unreachable!(),
843 }
844
845 Ok(())
846 }
847}