1use crate::common::serial_io::{
2 CancelableReader, CancelableWriter, for_tool, is_cancelled_io_error, sleep_with_cancel,
3};
4use crate::{Error, Result, SifliTool};
5use probe_rs::architecture::arm::armv8m::Dcrdr;
6use probe_rs::{MemoryMappedRegister, memory_mapped_bitfield_register};
7use std::cmp::{max, min};
8use std::fmt;
9use std::io::{BufReader, BufWriter, Read, Write};
10use std::time::{Duration, Instant};
11
12pub const START_WORD: [u8; 2] = [0x7E, 0x79];
13pub const DEFUALT_RECV_TIMEOUT: Duration = Duration::from_secs(3);
14
15#[derive(Debug)]
16pub enum SifliUartCommand<'a> {
17 Enter,
18 Exit,
19 MEMRead { addr: u32, len: u16 },
20 MEMWrite { addr: u32, data: &'a [u32] },
21}
22
23#[derive(Debug)]
24pub enum SifliUartResponse {
25 Enter,
26 Exit,
27 MEMRead { data: Vec<u8> },
28 MEMWrite,
29}
30
31#[derive(Debug)]
32pub enum RecvError {
33 Cancelled,
34 Timeout,
35 InvalidHeaderLength,
36 InvalidHeaderChannel,
37 ReadError(std::io::Error),
38 InvalidResponse(u8),
39}
40
41impl From<RecvError> for Error {
42 fn from(err: RecvError) -> Self {
43 match err {
44 RecvError::Cancelled => Error::Cancelled,
45 RecvError::Timeout => Error::timeout("receiving UART frame"),
46 RecvError::InvalidHeaderLength => Error::protocol("invalid frame length"),
47 RecvError::InvalidHeaderChannel => Error::protocol("invalid frame channel information"),
48 RecvError::ReadError(e) => Error::from(e),
49 RecvError::InvalidResponse(code) => {
50 Error::protocol(format!("invalid response code: {:#04X}", code))
51 }
52 }
53 }
54}
55
56impl fmt::Display for SifliUartCommand<'_> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 match self {
59 SifliUartCommand::Enter => write!(f, "Enter"),
60 SifliUartCommand::Exit => write!(f, "Exit"),
61 SifliUartCommand::MEMRead { addr, len } => {
62 write!(f, "MEMRead {{ addr: {:#X}, len: {:#X} }}", addr, len)
63 }
64 SifliUartCommand::MEMWrite { addr, data } => {
65 write!(f, "MEMWrite {{ addr: {:#X}, data: [", addr)?;
66 for (i, d) in data.iter().enumerate() {
67 if i > 0 {
68 write!(f, ", ")?;
69 }
70 write!(f, "{:#X}", d)?;
71 }
72 write!(f, "] }}")
73 }
74 }
75 }
76}
77
78impl fmt::Display for SifliUartResponse {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 match self {
81 SifliUartResponse::Enter => write!(f, "Enter"),
82 SifliUartResponse::Exit => write!(f, "Exit"),
83 SifliUartResponse::MEMRead { data } => {
84 write!(f, "MEMRead {{ data: [")?;
85 for (i, byte) in data.iter().enumerate() {
86 if i > 0 {
87 write!(f, ", ")?;
88 }
89 write!(f, "{:#04X}", byte)?;
90 }
91 write!(f, "] }}")
92 }
93 SifliUartResponse::MEMWrite => write!(f, "MEMWrite"),
94 }
95 }
96}
97
98memory_mapped_bitfield_register! {
99 pub struct Dcrsr(u32);
100 0xE000_EDF4, "DCRSR",
101 impl From;
102 pub _, set_regwnr: 16;
103 pub _, set_regsel: 6,0;
105}
106
107memory_mapped_bitfield_register! {
108 pub struct Dhcsr(u32);
109 0xE000_EDF0, "DHCSR",
110 impl From;
111 pub s_reset_st, _: 25;
112 pub s_retire_st, _: 24;
113 pub s_lockup, _: 19;
114 pub s_sleep, _: 18;
115 pub s_halt, _: 17;
116 pub s_regrdy, _: 16;
117 pub c_maskints, set_c_maskints: 3;
118 pub c_step, set_c_step: 2;
119 pub c_halt, set_c_halt: 1;
120 pub c_debugen, set_c_debugen: 0;
121}
122
123impl Dhcsr {
124 pub fn enable_write(&mut self) {
131 self.0 &= !(0xffff << 16);
132 self.0 |= 0xa05f << 16;
133 }
134}
135
136pub trait SifliDebug {
137 fn debug_command(&mut self, command: SifliUartCommand) -> Result<SifliUartResponse>;
138 fn debug_write_word32(&mut self, addr: u32, data: u32) -> Result<()>;
139 fn debug_read_word32(&mut self, addr: u32) -> Result<u32>;
140 fn debug_write_core_reg(&mut self, reg: u16, data: u32) -> Result<()>;
141 fn debug_write_memory(&mut self, addr: u32, data: &[u8]) -> Result<()>;
142 fn debug_run(&mut self) -> Result<()>;
143 fn debug_halt(&mut self) -> Result<()>;
144 fn debug_step(&mut self) -> Result<()>;
145}
146
147pub trait ChipFrameFormat {
149 fn create_header(len: u16) -> Vec<u8>;
151
152 fn parse_frame_header<R: Read>(
154 reader: &mut BufReader<R>,
155 ) -> std::result::Result<usize, RecvError>;
156
157 fn encode_command_data(command: &SifliUartCommand) -> Vec<u8>;
159
160 fn decode_response_data(data: &[u8]) -> u32;
162
163 fn map_address(addr: u32) -> u32 {
165 addr
166 }
167}
168
169pub fn send_command<F: ChipFrameFormat, W: Write>(
171 writer: &mut BufWriter<W>,
172 command: &SifliUartCommand,
173) -> Result<()> {
174 let send_data = F::encode_command_data(command);
175 let header = F::create_header(send_data.len() as u16);
176
177 writer.write_all(&header).map_err(|error| {
178 if is_cancelled_io_error(&error) {
179 Error::Cancelled
180 } else {
181 error.into()
182 }
183 })?;
184 writer.write_all(&send_data).map_err(|error| {
185 if is_cancelled_io_error(&error) {
186 Error::Cancelled
187 } else {
188 error.into()
189 }
190 })?;
191 writer.flush().map_err(|error| {
192 if is_cancelled_io_error(&error) {
193 Error::Cancelled
194 } else {
195 error.into()
196 }
197 })?;
198 Ok(())
199}
200
201pub fn recv_response<F: ChipFrameFormat, R: Read>(
202 reader: &mut BufReader<R>,
203) -> Result<SifliUartResponse> {
204 let start_time = Instant::now();
205 let mut temp: Vec<u8> = vec![];
206
207 tracing::debug!("Waiting for frame start marker...");
209 let mut buffer = vec![];
210
211 loop {
212 if start_time.elapsed() >= DEFUALT_RECV_TIMEOUT {
213 tracing::warn!(
214 "Receive timeout: {} seconds",
215 DEFUALT_RECV_TIMEOUT.as_secs()
216 );
217 return Err(RecvError::Timeout.into());
218 }
219
220 let mut byte = [0; 1];
221 match reader.read_exact(&mut byte) {
222 Ok(_) => {
223 if byte[0] == START_WORD[0] || (buffer.len() == 1 && byte[0] == START_WORD[1]) {
225 buffer.push(byte[0]);
226
227 if buffer.ends_with(&START_WORD) {
229 tracing::debug!("Frame start marker found: {:02X?}", START_WORD);
230 break;
231 }
232 } else {
233 buffer.clear();
235 }
236
237 if buffer.len() > 2 {
239 buffer.clear();
240 }
241 }
242 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
243 continue;
245 }
246 Err(e) if is_cancelled_io_error(&e) => {
247 return Err(RecvError::Cancelled.into());
248 }
249 Err(e) => {
250 tracing::error!("Error reading frame start marker: {}", e);
251 continue; }
253 }
254 }
255
256 temp.extend_from_slice(&buffer);
257
258 let payload_size = F::parse_frame_header(reader)?;
260 tracing::debug!("Received packet length: {} bytes", payload_size);
261
262 tracing::debug!("Reading payload data ({} bytes)...", payload_size);
264 let mut recv_data = vec![];
265
266 while recv_data.len() < payload_size {
267 let mut byte = [0; 1];
268 match reader.read_exact(&mut byte) {
269 Ok(_) => {
270 recv_data.push(byte[0]);
271 }
272 Err(e) if is_cancelled_io_error(&e) => {
273 return Err(RecvError::Cancelled.into());
274 }
275 Err(e) => {
276 tracing::error!("Failed to read payload data: {}", e);
277 return Err(RecvError::ReadError(e).into());
278 }
279 }
280 }
281
282 temp.extend_from_slice(&recv_data);
283
284 if recv_data.is_empty() {
286 tracing::error!("Received empty payload data");
287 return Err(RecvError::InvalidResponse(0).into());
288 }
289
290 let response_code = recv_data[0];
291 match response_code {
292 0xD1 => {
293 tracing::info!("Received Enter command response");
294 Ok(SifliUartResponse::Enter)
295 }
296 0xD0 => {
297 tracing::info!("Received Exit command response");
298 Ok(SifliUartResponse::Exit)
299 }
300 0xD2 => {
301 let data = if recv_data.len() > 1 {
303 recv_data[1..recv_data.len() - 1].to_vec()
304 } else {
305 Vec::new()
306 };
307 tracing::info!(
308 "Received memory read response, data length: {} bytes",
309 data.len()
310 );
311 Ok(SifliUartResponse::MEMRead { data })
312 }
313 0xD3 => {
314 tracing::info!("Received memory write response");
315 Ok(SifliUartResponse::MEMWrite)
316 }
317 _ => {
318 tracing::error!("Received unknown response code: {:#04X}", response_code);
319 Err(RecvError::InvalidResponse(response_code).into())
320 }
321 }
322}
323
324pub mod common_debug {
326 use super::*;
327
328 pub fn debug_command_impl<T: SifliTool, F: ChipFrameFormat>(
330 tool: &mut T,
331 command: SifliUartCommand,
332 ) -> Result<SifliUartResponse> {
333 tracing::info!("Command: {}", command);
334 let writer: CancelableWriter = {
335 let mut io = for_tool(tool);
336 io.try_clone_writer()?
337 };
338 let mut buf_writer = BufWriter::new(writer);
339
340 let reader: CancelableReader = {
341 let mut io = for_tool(tool);
342 io.try_clone_reader()?
343 };
344 let mut buf_reader = BufReader::new(reader);
345
346 let ret = send_command::<F, _>(&mut buf_writer, &command);
347 if let Err(e) = ret {
348 tracing::error!("Command send error: {:?}", e);
349 return Err(e);
350 }
351
352 match command {
353 SifliUartCommand::Exit => Ok(SifliUartResponse::Exit),
354 _ => recv_response::<F, _>(&mut buf_reader),
355 }
356 }
357
358 pub fn debug_read_word32_impl<T: SifliTool, F: ChipFrameFormat>(
360 tool: &mut T,
361 addr: u32,
362 ) -> Result<u32> {
363 let mapped_addr = F::map_address(addr);
364 let command = SifliUartCommand::MEMRead {
365 addr: mapped_addr,
366 len: 1,
367 };
368
369 match debug_command_impl::<T, F>(tool, command) {
371 Ok(SifliUartResponse::MEMRead { data }) => {
372 if data.len() != 4 {
373 return Err(Error::invalid_input("invalid response length"));
374 }
375 let value = F::decode_response_data(&data);
376 Ok(value)
377 }
378 Ok(_) => Err(Error::invalid_input("invalid response")),
379 Err(e) => Err(e),
380 }
381 }
382
383 pub fn debug_write_word32_impl<T: SifliTool, F: ChipFrameFormat>(
385 tool: &mut T,
386 addr: u32,
387 data: u32,
388 ) -> Result<()> {
389 let mapped_addr = F::map_address(addr);
390 let command = SifliUartCommand::MEMWrite {
391 addr: mapped_addr,
392 data: &[data],
393 };
394 match debug_command_impl::<T, F>(tool, command) {
395 Ok(SifliUartResponse::MEMWrite) => Ok(()),
396 Ok(_) => Err(Error::invalid_input("invalid response")),
397 Err(e) => Err(e),
398 }
399 }
400
401 pub fn debug_write_memory_impl<T: SifliTool, F: ChipFrameFormat>(
403 tool: &mut T,
404 address: u32,
405 data: &[u8],
406 ) -> Result<()> {
407 if data.is_empty() {
408 return Ok(());
409 }
410
411 let mut mapped_address = F::map_address(address);
413
414 mapped_address = if (mapped_address & 0xff000000) == 0x12000000 {
416 (mapped_address & 0x00ffffff) | 0x62000000
417 } else {
418 mapped_address
419 };
420
421 let addr_usize = mapped_address as usize;
422 let start_aligned = addr_usize - (addr_usize % 4);
424 let end_aligned = (addr_usize + data.len()).div_ceil(4) * 4;
425 let total_bytes = end_aligned - start_aligned;
426 let total_words = total_bytes / 4;
427
428 let mut buffer = vec![0u8; total_bytes];
429
430 for i in 0..total_words {
431 let block_addr = start_aligned + i * 4;
432 let block_end = block_addr + 4;
433
434 if block_addr >= addr_usize && block_end <= addr_usize + data.len() {
437 let offset_in_data = block_addr - addr_usize;
438 buffer[i * 4..i * 4 + 4].copy_from_slice(&data[offset_in_data..offset_in_data + 4]);
439 } else {
440 let resp = debug_command_impl::<T, F>(
443 tool,
444 SifliUartCommand::MEMRead {
445 addr: block_addr as u32,
446 len: 1,
447 },
448 )?;
449 let mut block: [u8; 4] = match resp {
450 SifliUartResponse::MEMRead { data: d } if d.len() == 4 => {
451 let value = F::decode_response_data(&d);
453 value.to_le_bytes()
454 }
455 _ => {
456 return Err(Error::invalid_input("invalid response length"));
457 }
458 };
459 let overlap_start = max(block_addr, addr_usize);
461 let overlap_end = min(block_end, addr_usize + data.len());
462 if overlap_start < overlap_end {
463 let in_block_offset = overlap_start - block_addr;
464 let in_data_offset = overlap_start - addr_usize;
465 let overlap_len = overlap_end - overlap_start;
466 block[in_block_offset..in_block_offset + overlap_len]
467 .copy_from_slice(&data[in_data_offset..in_data_offset + overlap_len]);
468 }
469 buffer[i * 4..i * 4 + 4].copy_from_slice(&block);
470 }
471 }
472
473 let words: Vec<u32> = buffer
474 .chunks_exact(4)
475 .map(|chunk| u32::from_le_bytes(chunk.try_into().expect("chunk length is 4")))
476 .collect();
477
478 debug_command_impl::<T, F>(
480 tool,
481 SifliUartCommand::MEMWrite {
482 addr: start_aligned as u32,
483 data: &words,
484 },
485 )?;
486
487 Ok(())
488 }
489
490 pub fn debug_write_core_reg_impl<T: SifliTool, F: ChipFrameFormat>(
492 tool: &mut T,
493 addr: u16,
494 value: u32,
495 ) -> Result<()> {
496 debug_write_word32_impl::<T, F>(tool, Dcrdr::get_mmio_address() as u32, value)?;
497
498 let mut dcrsr_val = Dcrsr(0);
499 dcrsr_val.set_regwnr(true); dcrsr_val.set_regsel(addr.into()); debug_write_word32_impl::<T, F>(tool, Dcrsr::get_mmio_address() as u32, dcrsr_val.into())?;
503
504 sleep_with_cancel(&tool.base().cancel_token, Duration::from_millis(10))?;
506 Ok(())
507 }
508
509 pub fn debug_step_impl<T: SifliTool, F: ChipFrameFormat>(tool: &mut T) -> Result<()> {
511 let mut value = Dhcsr(0);
513 value.set_c_step(true);
516 value.set_c_halt(false);
517 value.set_c_debugen(true);
518 value.set_c_maskints(true);
519 value.enable_write();
520
521 debug_write_word32_impl::<T, F>(tool, Dhcsr::get_mmio_address() as u32, value.into())?;
522
523 sleep_with_cancel(&tool.base().cancel_token, Duration::from_millis(10))?;
524 Ok(())
525 }
526
527 pub fn debug_run_impl<T: SifliTool, F: ChipFrameFormat>(tool: &mut T) -> Result<()> {
529 debug_step_impl::<T, F>(tool)?;
530 sleep_with_cancel(&tool.base().cancel_token, Duration::from_millis(100))?;
531 let mut value = Dhcsr(0);
532 value.set_c_halt(false);
533 value.set_c_debugen(true);
534 value.enable_write();
535
536 debug_write_word32_impl::<T, F>(tool, Dhcsr::get_mmio_address() as u32, value.into())?;
537
538 sleep_with_cancel(&tool.base().cancel_token, Duration::from_millis(100))?;
539 Ok(())
540 }
541
542 pub fn debug_halt_impl<T: SifliTool, F: ChipFrameFormat>(tool: &mut T) -> Result<()> {
544 let mut value = Dhcsr(0);
545 value.set_c_halt(true);
546 value.set_c_debugen(true);
547 value.enable_write();
548
549 debug_write_word32_impl::<T, F>(tool, Dhcsr::get_mmio_address() as u32, value.into())?;
550 sleep_with_cancel(&tool.base().cancel_token, Duration::from_millis(10))?;
551 Ok(())
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use super::{SifliUartCommand, common_debug};
558 use crate::common::serial_io::test_support::TestSerialPort;
559 use crate::progress::no_op_progress_sink;
560 use crate::{
561 BeforeOperation, CancelToken, EraseFlashParams, EraseFlashTrait, EraseRegionParams,
562 ReadFlashParams, ReadFlashTrait, Result, SifliTool, SifliToolBase, SifliToolTrait,
563 WriteFlashParams, WriteFlashTrait,
564 };
565 use serialport::SerialPort;
566 use std::sync::{Arc, Mutex};
567
568 struct TestTool {
569 base: SifliToolBase,
570 port: Box<dyn SerialPort>,
571 }
572
573 unsafe impl Send for TestTool {}
574 unsafe impl Sync for TestTool {}
575
576 impl SifliToolTrait for TestTool {
577 fn port(&mut self) -> &mut Box<dyn SerialPort> {
578 &mut self.port
579 }
580
581 fn base(&self) -> &SifliToolBase {
582 &self.base
583 }
584
585 fn set_speed(&mut self, _baud: u32) -> Result<()> {
586 Ok(())
587 }
588
589 fn soft_reset(&mut self) -> Result<()> {
590 Ok(())
591 }
592 }
593
594 impl WriteFlashTrait for TestTool {
595 fn write_flash(&mut self, _params: &WriteFlashParams) -> Result<()> {
596 Ok(())
597 }
598 }
599
600 impl ReadFlashTrait for TestTool {
601 fn read_flash(&mut self, _params: &ReadFlashParams) -> Result<()> {
602 Ok(())
603 }
604 }
605
606 impl EraseFlashTrait for TestTool {
607 fn erase_flash(&mut self, _params: &EraseFlashParams) -> Result<()> {
608 Ok(())
609 }
610
611 fn erase_region(&mut self, _params: &EraseRegionParams) -> Result<()> {
612 Ok(())
613 }
614 }
615
616 impl SifliTool for TestTool {
617 fn create_tool(_base_param: SifliToolBase) -> Box<dyn SifliTool>
618 where
619 Self: Sized,
620 {
621 panic!("not used in tests")
622 }
623 }
624
625 fn make_test_tool() -> (
626 TestTool,
627 Arc<Mutex<crate::common::serial_io::test_support::TestSerialPortState>>,
628 CancelToken,
629 ) {
630 let token = CancelToken::new();
631 let (port, state) = TestSerialPort::from_bytes(&[]);
632 let base = SifliToolBase::new_with_external_stub_and_cancel(
633 "test-port".to_string(),
634 BeforeOperation::NoReset,
635 "nor".to_string(),
636 1_000_000,
637 1,
638 false,
639 no_op_progress_sink(),
640 None,
641 token.clone(),
642 );
643 (
644 TestTool {
645 base,
646 port: Box::new(port),
647 },
648 state,
649 token,
650 )
651 }
652
653 #[test]
654 fn debug_command_impl_propagates_cancellation_from_cloned_streams() {
655 let (mut tool, state, token) = make_test_tool();
656 state.lock().unwrap().cancel_on_write_call = Some((1, token));
657
658 let result = common_debug::debug_command_impl::<
659 TestTool,
660 crate::sf32lb52::sifli_debug::SF32LB52FrameFormat,
661 >(&mut tool, SifliUartCommand::Enter);
662
663 assert!(matches!(result, Err(crate::Error::Cancelled)));
664 }
665}