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