1use crate::{Error, Result, SifliTool};
2use probe_rs::architecture::arm::armv8m::Dcrdr;
3use probe_rs::{MemoryMappedRegister, memory_mapped_bitfield_register};
4use std::cmp::{max, min};
5use std::fmt;
6use std::io::{BufReader, BufWriter, Read, Write};
7use std::time::{Duration, Instant};
8
9pub const START_WORD: [u8; 2] = [0x7E, 0x79];
10pub const DEFUALT_RECV_TIMEOUT: Duration = Duration::from_secs(3);
11
12#[derive(Debug)]
13pub enum SifliUartCommand<'a> {
14 Enter,
15 Exit,
16 MEMRead { addr: u32, len: u16 },
17 MEMWrite { addr: u32, data: &'a [u32] },
18}
19
20#[derive(Debug)]
21pub enum SifliUartResponse {
22 Enter,
23 Exit,
24 MEMRead { data: Vec<u8> },
25 MEMWrite,
26}
27
28#[derive(Debug)]
29pub enum RecvError {
30 Timeout,
31 InvalidHeaderLength,
32 InvalidHeaderChannel,
33 ReadError(std::io::Error),
34 InvalidResponse(u8),
35}
36
37impl From<RecvError> for Error {
38 fn from(err: RecvError) -> Self {
39 match err {
40 RecvError::Timeout => Error::timeout("receiving UART frame"),
41 RecvError::InvalidHeaderLength => Error::protocol("invalid frame length"),
42 RecvError::InvalidHeaderChannel => Error::protocol("invalid frame channel information"),
43 RecvError::ReadError(e) => Error::from(e),
44 RecvError::InvalidResponse(code) => {
45 Error::protocol(format!("invalid response code: {:#04X}", code))
46 }
47 }
48 }
49}
50
51impl fmt::Display for SifliUartCommand<'_> {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 SifliUartCommand::Enter => write!(f, "Enter"),
55 SifliUartCommand::Exit => write!(f, "Exit"),
56 SifliUartCommand::MEMRead { addr, len } => {
57 write!(f, "MEMRead {{ addr: {:#X}, len: {:#X} }}", addr, len)
58 }
59 SifliUartCommand::MEMWrite { addr, data } => {
60 write!(f, "MEMWrite {{ addr: {:#X}, data: [", addr)?;
61 for (i, d) in data.iter().enumerate() {
62 if i > 0 {
63 write!(f, ", ")?;
64 }
65 write!(f, "{:#X}", d)?;
66 }
67 write!(f, "] }}")
68 }
69 }
70 }
71}
72
73impl fmt::Display for SifliUartResponse {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 SifliUartResponse::Enter => write!(f, "Enter"),
77 SifliUartResponse::Exit => write!(f, "Exit"),
78 SifliUartResponse::MEMRead { data } => {
79 write!(f, "MEMRead {{ data: [")?;
80 for (i, byte) in data.iter().enumerate() {
81 if i > 0 {
82 write!(f, ", ")?;
83 }
84 write!(f, "{:#04X}", byte)?;
85 }
86 write!(f, "] }}")
87 }
88 SifliUartResponse::MEMWrite => write!(f, "MEMWrite"),
89 }
90 }
91}
92
93memory_mapped_bitfield_register! {
94 pub struct Dcrsr(u32);
95 0xE000_EDF4, "DCRSR",
96 impl From;
97 pub _, set_regwnr: 16;
98 pub _, set_regsel: 6,0;
100}
101
102memory_mapped_bitfield_register! {
103 pub struct Dhcsr(u32);
104 0xE000_EDF0, "DHCSR",
105 impl From;
106 pub s_reset_st, _: 25;
107 pub s_retire_st, _: 24;
108 pub s_lockup, _: 19;
109 pub s_sleep, _: 18;
110 pub s_halt, _: 17;
111 pub s_regrdy, _: 16;
112 pub c_maskints, set_c_maskints: 3;
113 pub c_step, set_c_step: 2;
114 pub c_halt, set_c_halt: 1;
115 pub c_debugen, set_c_debugen: 0;
116}
117
118impl Dhcsr {
119 pub fn enable_write(&mut self) {
126 self.0 &= !(0xffff << 16);
127 self.0 |= 0xa05f << 16;
128 }
129}
130
131pub trait SifliDebug {
132 fn debug_command(&mut self, command: SifliUartCommand) -> Result<SifliUartResponse>;
133 fn debug_write_word32(&mut self, addr: u32, data: u32) -> Result<()>;
134 fn debug_read_word32(&mut self, addr: u32) -> Result<u32>;
135 fn debug_write_core_reg(&mut self, reg: u16, data: u32) -> Result<()>;
136 fn debug_write_memory(&mut self, addr: u32, data: &[u8]) -> Result<()>;
137 fn debug_run(&mut self) -> Result<()>;
138 fn debug_halt(&mut self) -> Result<()>;
139 fn debug_step(&mut self) -> Result<()>;
140}
141
142pub trait ChipFrameFormat {
144 fn create_header(len: u16) -> Vec<u8>;
146
147 fn parse_frame_header(
149 reader: &mut BufReader<Box<dyn Read + Send>>,
150 ) -> std::result::Result<usize, RecvError>;
151
152 fn encode_command_data(command: &SifliUartCommand) -> Vec<u8>;
154
155 fn decode_response_data(data: &[u8]) -> u32;
157
158 fn map_address(addr: u32) -> u32 {
160 addr
161 }
162}
163
164pub fn send_command<F: ChipFrameFormat>(
166 writer: &mut BufWriter<Box<dyn Write + Send>>,
167 command: &SifliUartCommand,
168) -> Result<()> {
169 let send_data = F::encode_command_data(command);
170 let header = F::create_header(send_data.len() as u16);
171
172 writer.write_all(&header)?;
173 writer.write_all(&send_data)?;
174 writer.flush()?;
175 Ok(())
176}
177
178pub fn recv_response<F: ChipFrameFormat>(
179 reader: &mut BufReader<Box<dyn Read + Send>>,
180) -> Result<SifliUartResponse> {
181 let start_time = Instant::now();
182 let mut temp: Vec<u8> = vec![];
183
184 tracing::debug!("Waiting for frame start marker...");
186 let mut buffer = vec![];
187
188 loop {
189 if start_time.elapsed() >= DEFUALT_RECV_TIMEOUT {
190 tracing::warn!(
191 "Receive timeout: {} seconds",
192 DEFUALT_RECV_TIMEOUT.as_secs()
193 );
194 return Err(RecvError::Timeout.into());
195 }
196
197 let mut byte = [0; 1];
198 match reader.read_exact(&mut byte) {
199 Ok(_) => {
200 if byte[0] == START_WORD[0] || (buffer.len() == 1 && byte[0] == START_WORD[1]) {
202 buffer.push(byte[0]);
203
204 if buffer.ends_with(&START_WORD) {
206 tracing::debug!("Frame start marker found: {:02X?}", START_WORD);
207 break;
208 }
209 } else {
210 buffer.clear();
212 }
213
214 if buffer.len() > 2 {
216 buffer.clear();
217 }
218 }
219 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
220 continue;
222 }
223 Err(e) => {
224 tracing::error!("Error reading frame start marker: {}", e);
225 continue; }
227 }
228 }
229
230 temp.extend_from_slice(&buffer);
231
232 let payload_size = F::parse_frame_header(reader)?;
234 tracing::debug!("Received packet length: {} bytes", payload_size);
235
236 tracing::debug!("Reading payload data ({} bytes)...", payload_size);
238 let mut recv_data = vec![];
239
240 while recv_data.len() < payload_size {
241 let mut byte = [0; 1];
242 match reader.read_exact(&mut byte) {
243 Ok(_) => {
244 recv_data.push(byte[0]);
245 }
246 Err(e) => {
247 tracing::error!("Failed to read payload data: {}", e);
248 return Err(RecvError::ReadError(e).into());
249 }
250 }
251 }
252
253 temp.extend_from_slice(&recv_data);
254
255 if recv_data.is_empty() {
257 tracing::error!("Received empty payload data");
258 return Err(RecvError::InvalidResponse(0).into());
259 }
260
261 let response_code = recv_data[0];
262 match response_code {
263 0xD1 => {
264 tracing::info!("Received Enter command response");
265 Ok(SifliUartResponse::Enter)
266 }
267 0xD0 => {
268 tracing::info!("Received Exit command response");
269 Ok(SifliUartResponse::Exit)
270 }
271 0xD2 => {
272 let data = if recv_data.len() > 1 {
274 recv_data[1..recv_data.len() - 1].to_vec()
275 } else {
276 Vec::new()
277 };
278 tracing::info!(
279 "Received memory read response, data length: {} bytes",
280 data.len()
281 );
282 Ok(SifliUartResponse::MEMRead { data })
283 }
284 0xD3 => {
285 tracing::info!("Received memory write response");
286 Ok(SifliUartResponse::MEMWrite)
287 }
288 _ => {
289 tracing::error!("Received unknown response code: {:#04X}", response_code);
290 Err(RecvError::InvalidResponse(response_code).into())
291 }
292 }
293}
294
295pub mod common_debug {
297 use super::*;
298
299 pub fn debug_command_impl<T: SifliTool, F: ChipFrameFormat>(
301 tool: &mut T,
302 command: SifliUartCommand,
303 ) -> Result<SifliUartResponse> {
304 tracing::info!("Command: {}", command);
305 let writer: Box<dyn Write + Send> = tool.port().try_clone()?;
306 let mut buf_writer = BufWriter::new(writer);
307
308 let reader: Box<dyn Read + Send> = tool.port().try_clone()?;
309 let mut buf_reader = BufReader::new(reader);
310
311 let ret = send_command::<F>(&mut buf_writer, &command);
312 if let Err(e) = ret {
313 tracing::error!("Command send error: {:?}", e);
314 return Err(e);
315 }
316
317 match command {
318 SifliUartCommand::Exit => Ok(SifliUartResponse::Exit),
319 _ => recv_response::<F>(&mut buf_reader),
320 }
321 }
322
323 pub fn debug_read_word32_impl<T: SifliTool, F: ChipFrameFormat>(
325 tool: &mut T,
326 addr: u32,
327 ) -> Result<u32> {
328 let mapped_addr = F::map_address(addr);
329 let command = SifliUartCommand::MEMRead {
330 addr: mapped_addr,
331 len: 1,
332 };
333
334 match debug_command_impl::<T, F>(tool, command) {
336 Ok(SifliUartResponse::MEMRead { data }) => {
337 if data.len() != 4 {
338 return Err(Error::invalid_input("invalid response length"));
339 }
340 let value = F::decode_response_data(&data);
341 Ok(value)
342 }
343 Ok(_) => Err(Error::invalid_input("invalid response")),
344 Err(e) => Err(e),
345 }
346 }
347
348 pub fn debug_write_word32_impl<T: SifliTool, F: ChipFrameFormat>(
350 tool: &mut T,
351 addr: u32,
352 data: u32,
353 ) -> Result<()> {
354 let mapped_addr = F::map_address(addr);
355 let command = SifliUartCommand::MEMWrite {
356 addr: mapped_addr,
357 data: &[data],
358 };
359 match debug_command_impl::<T, F>(tool, command) {
360 Ok(SifliUartResponse::MEMWrite) => Ok(()),
361 Ok(_) => Err(Error::invalid_input("invalid response")),
362 Err(e) => Err(e),
363 }
364 }
365
366 pub fn debug_write_memory_impl<T: SifliTool, F: ChipFrameFormat>(
368 tool: &mut T,
369 address: u32,
370 data: &[u8],
371 ) -> Result<()> {
372 if data.is_empty() {
373 return Ok(());
374 }
375
376 let mut mapped_address = F::map_address(address);
378
379 mapped_address = if (mapped_address & 0xff000000) == 0x12000000 {
381 (mapped_address & 0x00ffffff) | 0x62000000
382 } else {
383 mapped_address
384 };
385
386 let addr_usize = mapped_address as usize;
387 let start_aligned = addr_usize - (addr_usize % 4);
389 let end_aligned = (addr_usize + data.len()).div_ceil(4) * 4;
390 let total_bytes = end_aligned - start_aligned;
391 let total_words = total_bytes / 4;
392
393 let mut buffer = vec![0u8; total_bytes];
394
395 for i in 0..total_words {
396 let block_addr = start_aligned + i * 4;
397 let block_end = block_addr + 4;
398
399 if block_addr >= addr_usize && block_end <= addr_usize + data.len() {
402 let offset_in_data = block_addr - addr_usize;
403 buffer[i * 4..i * 4 + 4].copy_from_slice(&data[offset_in_data..offset_in_data + 4]);
404 } else {
405 let resp = debug_command_impl::<T, F>(
408 tool,
409 SifliUartCommand::MEMRead {
410 addr: block_addr as u32,
411 len: 1,
412 },
413 )?;
414 let mut block: [u8; 4] = match resp {
415 SifliUartResponse::MEMRead { data: d } if d.len() == 4 => {
416 let value = F::decode_response_data(&d);
418 value.to_le_bytes()
419 }
420 _ => {
421 return Err(Error::invalid_input("invalid response length"));
422 }
423 };
424 let overlap_start = max(block_addr, addr_usize);
426 let overlap_end = min(block_end, addr_usize + data.len());
427 if overlap_start < overlap_end {
428 let in_block_offset = overlap_start - block_addr;
429 let in_data_offset = overlap_start - addr_usize;
430 let overlap_len = overlap_end - overlap_start;
431 block[in_block_offset..in_block_offset + overlap_len]
432 .copy_from_slice(&data[in_data_offset..in_data_offset + overlap_len]);
433 }
434 buffer[i * 4..i * 4 + 4].copy_from_slice(&block);
435 }
436 }
437
438 let words: Vec<u32> = buffer
439 .chunks_exact(4)
440 .map(|chunk| u32::from_le_bytes(chunk.try_into().expect("chunk length is 4")))
441 .collect();
442
443 debug_command_impl::<T, F>(
445 tool,
446 SifliUartCommand::MEMWrite {
447 addr: start_aligned as u32,
448 data: &words,
449 },
450 )?;
451
452 Ok(())
453 }
454
455 pub fn debug_write_core_reg_impl<T: SifliTool, F: ChipFrameFormat>(
457 tool: &mut T,
458 addr: u16,
459 value: u32,
460 ) -> Result<()> {
461 debug_write_word32_impl::<T, F>(tool, Dcrdr::get_mmio_address() as u32, value)?;
462
463 let mut dcrsr_val = Dcrsr(0);
464 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())?;
468
469 std::thread::sleep(Duration::from_millis(10));
471 Ok(())
472 }
473
474 pub fn debug_step_impl<T: SifliTool, F: ChipFrameFormat>(tool: &mut T) -> Result<()> {
476 let mut value = Dhcsr(0);
478 value.set_c_step(true);
481 value.set_c_halt(false);
482 value.set_c_debugen(true);
483 value.set_c_maskints(true);
484 value.enable_write();
485
486 debug_write_word32_impl::<T, F>(tool, Dhcsr::get_mmio_address() as u32, value.into())?;
487
488 std::thread::sleep(Duration::from_millis(10));
489 Ok(())
490 }
491
492 pub fn debug_run_impl<T: SifliTool, F: ChipFrameFormat>(tool: &mut T) -> Result<()> {
494 debug_step_impl::<T, F>(tool)?;
495 std::thread::sleep(Duration::from_millis(100));
496 let mut value = Dhcsr(0);
497 value.set_c_halt(false);
498 value.set_c_debugen(true);
499 value.enable_write();
500
501 debug_write_word32_impl::<T, F>(tool, Dhcsr::get_mmio_address() as u32, value.into())?;
502
503 std::thread::sleep(Duration::from_millis(100));
504 Ok(())
505 }
506
507 pub fn debug_halt_impl<T: SifliTool, F: ChipFrameFormat>(tool: &mut T) -> Result<()> {
509 let mut value = Dhcsr(0);
510 value.set_c_halt(true);
511 value.set_c_debugen(true);
512 value.enable_write();
513
514 debug_write_word32_impl::<T, F>(tool, Dhcsr::get_mmio_address() as u32, value.into())?;
515 std::thread::sleep(Duration::from_millis(10));
516 Ok(())
517 }
518}