1#![warn(missing_docs)]
2#![deny(unsafe_code)]
3
4use std::fmt::{self, Display};
9
10use bitfield::bitfield;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14#[non_exhaustive]
19#[derive(Debug, Clone, Copy, PartialEq)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21pub enum TlpMode {
22 NonFlit,
25
26 Flit,
30}
31
32#[derive(Debug, Clone, PartialEq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub enum TlpError {
36 InvalidFormat,
38 InvalidType,
40 UnsupportedCombination,
42 InvalidLength,
44 NotImplemented,
46 MissingMandatoryOhc,
49}
50
51impl fmt::Display for TlpError {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 TlpError::InvalidFormat => write!(f, "invalid TLP format field"),
55 TlpError::InvalidType => write!(f, "invalid TLP type field"),
56 TlpError::UnsupportedCombination => write!(f, "unsupported format/type combination"),
57 TlpError::InvalidLength => write!(f, "byte slice too short for expected TLP fields"),
58 TlpError::NotImplemented => write!(f, "feature not yet implemented"),
59 TlpError::MissingMandatoryOhc => {
60 write!(f, "mandatory OHC word missing for this TLP type")
61 }
62 }
63 }
64}
65
66impl std::error::Error for TlpError {}
67
68#[repr(u8)]
70#[derive(Debug, PartialEq, Copy, Clone)]
71#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
72pub enum TlpFmt {
73 NoDataHeader3DW = 0b000,
75 NoDataHeader4DW = 0b001,
77 WithDataHeader3DW = 0b010,
79 WithDataHeader4DW = 0b011,
81 TlpPrefix = 0b100,
83}
84
85impl Display for TlpFmt {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 let name = match self {
88 TlpFmt::NoDataHeader3DW => "3DW no Data Header",
89 TlpFmt::NoDataHeader4DW => "4DW no Data Header",
90 TlpFmt::WithDataHeader3DW => "3DW with Data Header",
91 TlpFmt::WithDataHeader4DW => "4DW with Data Header",
92 TlpFmt::TlpPrefix => "Tlp Prefix",
93 };
94 write!(f, "{name}")
95 }
96}
97
98impl TryFrom<u32> for TlpFmt {
99 type Error = TlpError;
100
101 fn try_from(v: u32) -> Result<Self, Self::Error> {
102 match v {
103 0b000 => Ok(TlpFmt::NoDataHeader3DW),
104 0b001 => Ok(TlpFmt::NoDataHeader4DW),
105 0b010 => Ok(TlpFmt::WithDataHeader3DW),
106 0b011 => Ok(TlpFmt::WithDataHeader4DW),
107 0b100 => Ok(TlpFmt::TlpPrefix),
108 _ => Err(TlpError::InvalidFormat),
109 }
110 }
111}
112
113#[derive(Debug, Copy, Clone, PartialEq)]
115#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
116pub enum AtomicOp {
117 FetchAdd,
119 Swap,
121 CompareSwap,
123}
124
125#[derive(Debug, Copy, Clone, PartialEq)]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128pub enum AtomicWidth {
129 W32,
131 W64,
133}
134
135#[derive(PartialEq)]
136pub(crate) enum TlpFormatEncodingType {
137 MemoryRequest = 0b00000,
138 MemoryLockRequest = 0b00001,
139 IORequest = 0b00010,
140 ConfigType0Request = 0b00100,
141 ConfigType1Request = 0b00101,
142 Completion = 0b01010,
143 CompletionLocked = 0b01011,
144 FetchAtomicOpRequest = 0b01100,
145 UnconSwapAtomicOpRequest = 0b01101,
146 CompSwapAtomicOpRequest = 0b01110,
147 DeferrableMemoryWriteRequest = 0b11011,
148 MessageRequest = 0b10000,
151}
152
153impl TryFrom<u32> for TlpFormatEncodingType {
154 type Error = TlpError;
155
156 fn try_from(v: u32) -> Result<Self, Self::Error> {
157 match v {
158 0b00000 => Ok(TlpFormatEncodingType::MemoryRequest),
159 0b00001 => Ok(TlpFormatEncodingType::MemoryLockRequest),
160 0b00010 => Ok(TlpFormatEncodingType::IORequest),
161 0b00100 => Ok(TlpFormatEncodingType::ConfigType0Request),
162 0b00101 => Ok(TlpFormatEncodingType::ConfigType1Request),
163 0b01010 => Ok(TlpFormatEncodingType::Completion),
164 0b01011 => Ok(TlpFormatEncodingType::CompletionLocked),
165 0b01100 => Ok(TlpFormatEncodingType::FetchAtomicOpRequest),
166 0b01101 => Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest),
167 0b01110 => Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest),
168 0b11011 => Ok(TlpFormatEncodingType::DeferrableMemoryWriteRequest),
169 0b10000..=0b10101 => Ok(TlpFormatEncodingType::MessageRequest),
172 _ => Err(TlpError::InvalidType),
173 }
174 }
175}
176
177#[derive(PartialEq, Debug)]
179#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
180pub enum TlpType {
181 MemReadReq,
183 MemReadLockReq,
185 MemWriteReq,
187 IOReadReq,
189 IOWriteReq,
191 ConfType0ReadReq,
193 ConfType0WriteReq,
195 ConfType1ReadReq,
197 ConfType1WriteReq,
199 MsgReq,
201 MsgReqData,
203 Cpl,
205 CplData,
207 CplLocked,
209 CplDataLocked,
211 FetchAddAtomicOpReq,
213 SwapAtomicOpReq,
215 CompareSwapAtomicOpReq,
217 DeferrableMemWriteReq,
219 LocalTlpPrefix,
221 EndToEndTlpPrefix,
223}
224
225impl Display for TlpType {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 let name = match self {
228 TlpType::MemReadReq => "Memory Read Request",
229 TlpType::MemReadLockReq => "Locked Memory Read Request",
230 TlpType::MemWriteReq => "Memory Write Request",
231 TlpType::IOReadReq => "IO Read Request",
232 TlpType::IOWriteReq => "IO Write Request",
233 TlpType::ConfType0ReadReq => "Type 0 Config Read Request",
234 TlpType::ConfType0WriteReq => "Type 0 Config Write Request",
235 TlpType::ConfType1ReadReq => "Type 1 Config Read Request",
236 TlpType::ConfType1WriteReq => "Type 1 Config Write Request",
237 TlpType::MsgReq => "Message Request",
238 TlpType::MsgReqData => "Message with Data Request",
239 TlpType::Cpl => "Completion",
240 TlpType::CplData => "Completion with Data",
241 TlpType::CplLocked => "Locked Completion",
242 TlpType::CplDataLocked => "Locked Completion with Data",
243 TlpType::FetchAddAtomicOpReq => "Fetch Add Atomic Op Request",
244 TlpType::SwapAtomicOpReq => "Swap Atomic Op Request",
245 TlpType::CompareSwapAtomicOpReq => "Compare Swap Atomic Op Request",
246 TlpType::DeferrableMemWriteReq => "Deferrable Memory Write Request",
247 TlpType::LocalTlpPrefix => "Local Tlp Prefix",
248 TlpType::EndToEndTlpPrefix => "End To End Tlp Prefix",
249 };
250 write!(f, "{name}")
251 }
252}
253
254impl TlpType {
255 pub fn is_non_posted(&self) -> bool {
260 matches!(
261 self,
262 TlpType::MemReadReq
263 | TlpType::MemReadLockReq
264 | TlpType::IOReadReq
265 | TlpType::IOWriteReq
266 | TlpType::ConfType0ReadReq
267 | TlpType::ConfType0WriteReq
268 | TlpType::ConfType1ReadReq
269 | TlpType::ConfType1WriteReq
270 | TlpType::FetchAddAtomicOpReq
271 | TlpType::SwapAtomicOpReq
272 | TlpType::CompareSwapAtomicOpReq
273 | TlpType::DeferrableMemWriteReq
274 )
275 }
276
277 pub fn is_posted(&self) -> bool {
291 !self.is_non_posted()
292 }
293}
294
295bitfield! {
296 struct TlpHeader(MSB0 [u8]);
297 u32;
298 get_format, _: 2, 0;
299 get_type, _: 7, 3;
300 get_t9, _: 8, 8;
301 get_tc, _: 11, 9;
302 get_t8, _: 12, 12;
303 get_attr_b2, _: 13, 13;
304 get_ln, _: 14, 14;
305 get_th, _: 15, 15;
306 get_td, _: 16, 16;
307 get_ep, _: 17, 17;
308 get_attr, _: 19, 18;
309 get_at, _: 21, 20;
310 get_length, _: 31, 22;
311}
312
313impl<T: AsRef<[u8]>> TlpHeader<T> {
314 fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
315 let tlp_type = self.get_type();
316 let tlp_fmt = self.get_format();
317
318 if let Ok(TlpFmt::TlpPrefix) = TlpFmt::try_from(tlp_fmt) {
321 return if tlp_type & 0b10000 != 0 {
322 Ok(TlpType::EndToEndTlpPrefix)
323 } else {
324 Ok(TlpType::LocalTlpPrefix)
325 };
326 }
327
328 match TlpFormatEncodingType::try_from(tlp_type) {
329 Ok(TlpFormatEncodingType::MemoryRequest) => match TlpFmt::try_from(tlp_fmt) {
330 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadReq),
331 Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadReq),
332 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::MemWriteReq),
333 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::MemWriteReq),
334 Ok(_) => Err(TlpError::UnsupportedCombination),
335 Err(e) => Err(e),
336 },
337 Ok(TlpFormatEncodingType::MemoryLockRequest) => match TlpFmt::try_from(tlp_fmt) {
338 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadLockReq),
339 Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadLockReq),
340 Ok(_) => Err(TlpError::UnsupportedCombination),
341 Err(e) => Err(e),
342 },
343 Ok(TlpFormatEncodingType::IORequest) => match TlpFmt::try_from(tlp_fmt) {
344 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::IOReadReq),
345 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::IOWriteReq),
346 Ok(_) => Err(TlpError::UnsupportedCombination),
347 Err(e) => Err(e),
348 },
349 Ok(TlpFormatEncodingType::ConfigType0Request) => match TlpFmt::try_from(tlp_fmt) {
350 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType0ReadReq),
351 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType0WriteReq),
352 Ok(_) => Err(TlpError::UnsupportedCombination),
353 Err(e) => Err(e),
354 },
355 Ok(TlpFormatEncodingType::ConfigType1Request) => match TlpFmt::try_from(tlp_fmt) {
356 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType1ReadReq),
357 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType1WriteReq),
358 Ok(_) => Err(TlpError::UnsupportedCombination),
359 Err(e) => Err(e),
360 },
361 Ok(TlpFormatEncodingType::Completion) => match TlpFmt::try_from(tlp_fmt) {
362 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::Cpl),
363 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplData),
364 Ok(_) => Err(TlpError::UnsupportedCombination),
365 Err(e) => Err(e),
366 },
367 Ok(TlpFormatEncodingType::CompletionLocked) => match TlpFmt::try_from(tlp_fmt) {
368 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::CplLocked),
369 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplDataLocked),
370 Ok(_) => Err(TlpError::UnsupportedCombination),
371 Err(e) => Err(e),
372 },
373 Ok(TlpFormatEncodingType::FetchAtomicOpRequest) => match TlpFmt::try_from(tlp_fmt) {
374 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::FetchAddAtomicOpReq),
375 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::FetchAddAtomicOpReq),
376 Ok(_) => Err(TlpError::UnsupportedCombination),
377 Err(e) => Err(e),
378 },
379 Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest) => {
380 match TlpFmt::try_from(tlp_fmt) {
381 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::SwapAtomicOpReq),
382 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::SwapAtomicOpReq),
383 Ok(_) => Err(TlpError::UnsupportedCombination),
384 Err(e) => Err(e),
385 }
386 }
387 Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest) => match TlpFmt::try_from(tlp_fmt) {
388 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CompareSwapAtomicOpReq),
389 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::CompareSwapAtomicOpReq),
390 Ok(_) => Err(TlpError::UnsupportedCombination),
391 Err(e) => Err(e),
392 },
393 Ok(TlpFormatEncodingType::DeferrableMemoryWriteRequest) => {
394 match TlpFmt::try_from(tlp_fmt) {
395 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::DeferrableMemWriteReq),
396 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::DeferrableMemWriteReq),
397 Ok(_) => Err(TlpError::UnsupportedCombination),
398 Err(e) => Err(e),
399 }
400 }
401 Ok(TlpFormatEncodingType::MessageRequest) => match TlpFmt::try_from(tlp_fmt) {
404 Ok(TlpFmt::NoDataHeader3DW) | Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MsgReq),
405 Ok(TlpFmt::WithDataHeader3DW) | Ok(TlpFmt::WithDataHeader4DW) => {
406 Ok(TlpType::MsgReqData)
407 }
408 Ok(_) => Err(TlpError::UnsupportedCombination),
409 Err(e) => Err(e),
410 },
411 Err(e) => Err(e),
412 }
413 }
414}
415
416pub trait MemRequest {
423 fn address(&self) -> u64;
425 fn req_id(&self) -> u16;
427 fn tag(&self) -> u8;
429 fn ldwbe(&self) -> u8;
431 fn fdwbe(&self) -> u8;
433}
434
435bitfield! {
438 #[allow(missing_docs)]
439 pub struct MemRequest3DW(MSB0 [u8]);
440 u32;
441 pub get_requester_id, _: 15, 0;
443 pub get_tag, _: 23, 16;
445 pub get_last_dw_be, _: 27, 24;
447 pub get_first_dw_be, _: 31, 28;
449 pub get_address32, _: 63, 32;
451}
452
453bitfield! {
455 #[allow(missing_docs)]
456 pub struct MemRequest4DW(MSB0 [u8]);
457 u64;
458 pub get_requester_id, _: 15, 0;
460 pub get_tag, _: 23, 16;
462 pub get_last_dw_be, _: 27, 24;
464 pub get_first_dw_be, _: 31, 28;
466 pub get_address64, _: 95, 32;
468}
469
470impl<T: AsRef<[u8]>> MemRequest for MemRequest3DW<T> {
471 fn address(&self) -> u64 {
472 self.get_address32().into()
473 }
474 fn req_id(&self) -> u16 {
475 self.get_requester_id() as u16
476 }
477 fn tag(&self) -> u8 {
478 self.get_tag() as u8
479 }
480 fn ldwbe(&self) -> u8 {
481 self.get_last_dw_be() as u8
482 }
483 fn fdwbe(&self) -> u8 {
484 self.get_first_dw_be() as u8
485 }
486}
487
488impl<T: AsRef<[u8]>> MemRequest for MemRequest4DW<T> {
489 fn address(&self) -> u64 {
490 self.get_address64()
491 }
492 fn req_id(&self) -> u16 {
493 self.get_requester_id() as u16
494 }
495 fn tag(&self) -> u8 {
496 self.get_tag() as u8
497 }
498 fn ldwbe(&self) -> u8 {
499 self.get_last_dw_be() as u8
500 }
501 fn fdwbe(&self) -> u8 {
502 self.get_first_dw_be() as u8
503 }
504}
505
506pub fn new_mem_req(
546 bytes: impl Into<Vec<u8>>,
547 format: &TlpFmt,
548) -> Result<Box<dyn MemRequest>, TlpError> {
549 let bytes = bytes.into();
550 match format {
551 TlpFmt::NoDataHeader3DW | TlpFmt::WithDataHeader3DW => {
552 if bytes.len() < 8 {
553 return Err(TlpError::InvalidLength);
554 }
555 Ok(Box::new(MemRequest3DW(bytes)))
556 }
557 TlpFmt::NoDataHeader4DW | TlpFmt::WithDataHeader4DW => {
558 if bytes.len() < 12 {
559 return Err(TlpError::InvalidLength);
560 }
561 Ok(Box::new(MemRequest4DW(bytes)))
562 }
563 TlpFmt::TlpPrefix => Err(TlpError::UnsupportedCombination),
564 }
565}
566
567pub trait ConfigurationRequest {
571 fn req_id(&self) -> u16;
573 fn tag(&self) -> u8;
575 fn bus_nr(&self) -> u8;
577 fn dev_nr(&self) -> u8;
579 fn func_nr(&self) -> u8;
581 fn ext_reg_nr(&self) -> u8;
583 fn reg_nr(&self) -> u8;
585}
586
587pub fn new_conf_req(bytes: impl Into<Vec<u8>>) -> Result<Box<dyn ConfigurationRequest>, TlpError> {
619 let bytes = bytes.into();
620 if bytes.len() < 8 {
621 return Err(TlpError::InvalidLength);
622 }
623 Ok(Box::new(ConfigRequest(bytes)))
624}
625
626bitfield! {
628 #[allow(missing_docs)]
629 pub struct ConfigRequest(MSB0 [u8]);
630 u32;
631 pub get_requester_id, _: 15, 0;
633 pub get_tag, _: 23, 16;
635 pub get_last_dw_be, _: 27, 24;
637 pub get_first_dw_be, _: 31, 28;
639 pub get_bus_nr, _: 39, 32;
641 pub get_dev_nr, _: 44, 40;
643 pub get_func_nr, _: 47, 45;
645 pub rsvd, _: 51, 48;
647 pub get_ext_reg_nr, _: 55, 52;
649 pub get_register_nr, _: 61, 56;
651 r, _: 63, 62;
652}
653
654impl<T: AsRef<[u8]>> ConfigurationRequest for ConfigRequest<T> {
655 fn req_id(&self) -> u16 {
656 self.get_requester_id() as u16
657 }
658 fn tag(&self) -> u8 {
659 self.get_tag() as u8
660 }
661 fn bus_nr(&self) -> u8 {
662 self.get_bus_nr() as u8
663 }
664 fn dev_nr(&self) -> u8 {
665 self.get_dev_nr() as u8
666 }
667 fn func_nr(&self) -> u8 {
668 self.get_func_nr() as u8
669 }
670 fn ext_reg_nr(&self) -> u8 {
671 self.get_ext_reg_nr() as u8
672 }
673 fn reg_nr(&self) -> u8 {
674 self.get_register_nr() as u8
675 }
676}
677
678pub trait CompletionRequest {
684 fn cmpl_id(&self) -> u16;
686 fn cmpl_stat(&self) -> u8;
688 fn bcm(&self) -> u8;
690 fn byte_cnt(&self) -> u16;
692 fn req_id(&self) -> u16;
694 fn tag(&self) -> u8;
696 fn laddr(&self) -> u8;
698}
699
700bitfield! {
702 #[allow(missing_docs)]
703 pub struct CompletionReqDW23(MSB0 [u8]);
704 u16;
705 pub get_completer_id, _: 15, 0;
707 pub get_cmpl_stat, _: 18, 16;
709 pub get_bcm, _: 19, 19;
711 pub get_byte_cnt, _: 31, 20;
713 pub get_req_id, _: 47, 32;
715 pub get_tag, _: 55, 48;
717 r, _: 56, 56;
718 pub get_laddr, _: 63, 57;
720}
721
722impl<T: AsRef<[u8]>> CompletionRequest for CompletionReqDW23<T> {
723 fn cmpl_id(&self) -> u16 {
724 self.get_completer_id()
725 }
726 fn cmpl_stat(&self) -> u8 {
727 self.get_cmpl_stat() as u8
728 }
729 fn bcm(&self) -> u8 {
730 self.get_bcm() as u8
731 }
732 fn byte_cnt(&self) -> u16 {
733 self.get_byte_cnt()
734 }
735 fn req_id(&self) -> u16 {
736 self.get_req_id()
737 }
738 fn tag(&self) -> u8 {
739 self.get_tag() as u8
740 }
741 fn laddr(&self) -> u8 {
742 self.get_laddr() as u8
743 }
744}
745
746pub fn new_cmpl_req(bytes: impl Into<Vec<u8>>) -> Result<Box<dyn CompletionRequest>, TlpError> {
768 let bytes = bytes.into();
769 if bytes.len() < 8 {
770 return Err(TlpError::InvalidLength);
771 }
772 Ok(Box::new(CompletionReqDW23(bytes)))
773}
774
775pub trait MessageRequest {
778 fn req_id(&self) -> u16;
780 fn tag(&self) -> u8;
782 fn msg_code(&self) -> u8;
784 fn dw3(&self) -> u32;
786 fn dw4(&self) -> u32;
788}
789
790bitfield! {
792 #[allow(missing_docs)]
793 pub struct MessageReqDW24(MSB0 [u8]);
794 u32;
795 pub get_requester_id, _: 15, 0;
797 pub get_tag, _: 23, 16;
799 pub get_msg_code, _: 31, 24;
801 pub get_dw3, _: 63, 32;
803 pub get_dw4, _: 95, 64;
805}
806
807impl<T: AsRef<[u8]>> MessageRequest for MessageReqDW24<T> {
808 fn req_id(&self) -> u16 {
809 self.get_requester_id() as u16
810 }
811 fn tag(&self) -> u8 {
812 self.get_tag() as u8
813 }
814 fn msg_code(&self) -> u8 {
815 self.get_msg_code() as u8
816 }
817 fn dw3(&self) -> u32 {
818 self.get_dw3()
819 }
820 fn dw4(&self) -> u32 {
821 self.get_dw4()
822 }
823 }
825
826pub fn new_msg_req(bytes: impl Into<Vec<u8>>) -> Result<Box<dyn MessageRequest>, TlpError> {
847 let bytes = bytes.into();
848 if bytes.len() < 12 {
849 return Err(TlpError::InvalidLength);
850 }
851 Ok(Box::new(MessageReqDW24(bytes)))
852}
853
854pub trait AtomicRequest: std::fmt::Debug {
857 fn op(&self) -> AtomicOp;
859 fn width(&self) -> AtomicWidth;
861 fn req_id(&self) -> u16;
863 fn tag(&self) -> u8;
865 fn address(&self) -> u64;
867 fn operand0(&self) -> u64;
869 fn operand1(&self) -> Option<u64>;
871}
872
873#[derive(Debug)]
874struct AtomicReq {
875 op: AtomicOp,
876 width: AtomicWidth,
877 req_id: u16,
878 tag: u8,
879 address: u64,
880 operand0: u64,
881 operand1: Option<u64>,
882}
883
884impl AtomicRequest for AtomicReq {
885 fn op(&self) -> AtomicOp {
886 self.op
887 }
888 fn width(&self) -> AtomicWidth {
889 self.width
890 }
891 fn req_id(&self) -> u16 {
892 self.req_id
893 }
894 fn tag(&self) -> u8 {
895 self.tag
896 }
897 fn address(&self) -> u64 {
898 self.address
899 }
900 fn operand0(&self) -> u64 {
901 self.operand0
902 }
903 fn operand1(&self) -> Option<u64> {
904 self.operand1
905 }
906}
907
908fn read_operand_be(b: &[u8], off: usize, width: AtomicWidth) -> u64 {
909 match width {
910 AtomicWidth::W32 => u32::from_be_bytes([b[off], b[off + 1], b[off + 2], b[off + 3]]) as u64,
911 AtomicWidth::W64 => u64::from_be_bytes([
912 b[off],
913 b[off + 1],
914 b[off + 2],
915 b[off + 3],
916 b[off + 4],
917 b[off + 5],
918 b[off + 6],
919 b[off + 7],
920 ]),
921 }
922}
923
924pub fn new_atomic_req(pkt: &TlpPacket) -> Result<Box<dyn AtomicRequest>, TlpError> {
954 let tlp_type = pkt.tlp_type()?;
955 let format = pkt.tlp_format()?;
956 let bytes = pkt.data();
957
958 let op = match tlp_type {
959 TlpType::FetchAddAtomicOpReq => AtomicOp::FetchAdd,
960 TlpType::SwapAtomicOpReq => AtomicOp::Swap,
961 TlpType::CompareSwapAtomicOpReq => AtomicOp::CompareSwap,
962 _ => return Err(TlpError::UnsupportedCombination),
963 };
964 let (width, hdr_len) = match format {
965 TlpFmt::WithDataHeader3DW => (AtomicWidth::W32, 8usize),
966 TlpFmt::WithDataHeader4DW => (AtomicWidth::W64, 12usize),
967 _ => return Err(TlpError::UnsupportedCombination),
968 };
969
970 let op_size = match width {
971 AtomicWidth::W32 => 4usize,
972 AtomicWidth::W64 => 8usize,
973 };
974 let num_ops = if matches!(op, AtomicOp::CompareSwap) {
975 2
976 } else {
977 1
978 };
979 let needed = hdr_len + op_size * num_ops;
980 if bytes.len() != needed {
981 return Err(TlpError::InvalidLength);
982 }
983
984 let req_id = u16::from_be_bytes([bytes[0], bytes[1]]);
985 let tag = bytes[2];
986 let address = match width {
987 AtomicWidth::W32 => u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64,
988 AtomicWidth::W64 => u64::from_be_bytes([
989 bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11],
990 ]),
991 };
992
993 let operand0 = read_operand_be(bytes, hdr_len, width);
994 let operand1 = if matches!(op, AtomicOp::CompareSwap) {
995 Some(read_operand_be(bytes, hdr_len + op_size, width))
996 } else {
997 None
998 };
999
1000 Ok(Box::new(AtomicReq {
1001 op,
1002 width,
1003 req_id,
1004 tag,
1005 address,
1006 operand0,
1007 operand1,
1008 }))
1009}
1010
1011#[non_exhaustive]
1024#[derive(Debug, Clone, Copy, PartialEq)]
1025#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1026pub enum FlitTlpType {
1027 Nop,
1029 MemRead32,
1031 UioMemRead,
1033 MsgToRc,
1035 MemWrite32,
1037 IoWrite,
1039 CfgWrite0,
1041 FetchAdd32,
1043 CompareSwap32,
1045 DeferrableMemWrite32,
1047 UioMemWrite,
1049 MsgDToRc,
1051 LocalTlpPrefix,
1053}
1054
1055impl FlitTlpType {
1056 pub fn base_header_dw(&self) -> u8 {
1062 match self {
1063 FlitTlpType::Nop | FlitTlpType::LocalTlpPrefix => 1,
1064 FlitTlpType::UioMemRead | FlitTlpType::UioMemWrite => 4,
1065 _ => 3,
1066 }
1067 }
1068
1069 pub fn is_read_request(&self) -> bool {
1072 matches!(self, FlitTlpType::MemRead32 | FlitTlpType::UioMemRead)
1073 }
1074
1075 pub fn has_data_payload(&self) -> bool {
1083 matches!(
1084 self,
1085 FlitTlpType::MemWrite32
1086 | FlitTlpType::UioMemWrite
1087 | FlitTlpType::IoWrite
1088 | FlitTlpType::CfgWrite0
1089 | FlitTlpType::FetchAdd32
1090 | FlitTlpType::CompareSwap32
1091 | FlitTlpType::DeferrableMemWrite32
1092 | FlitTlpType::MsgDToRc
1093 )
1094 }
1095}
1096
1097impl Display for FlitTlpType {
1098 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1099 let name = match self {
1100 FlitTlpType::Nop => "NOP",
1101 FlitTlpType::MemRead32 => "Memory Read (32-bit)",
1102 FlitTlpType::UioMemRead => "UIO Memory Read (64-bit)",
1103 FlitTlpType::MsgToRc => "Message routed to RC",
1104 FlitTlpType::MemWrite32 => "Memory Write (32-bit)",
1105 FlitTlpType::IoWrite => "I/O Write",
1106 FlitTlpType::CfgWrite0 => "Config Type 0 Write",
1107 FlitTlpType::FetchAdd32 => "FetchAdd AtomicOp (32-bit)",
1108 FlitTlpType::CompareSwap32 => "CompareSwap AtomicOp (32-bit)",
1109 FlitTlpType::DeferrableMemWrite32 => "Deferrable Memory Write (32-bit)",
1110 FlitTlpType::UioMemWrite => "UIO Memory Write (64-bit)",
1111 FlitTlpType::MsgDToRc => "Message with Data routed to RC",
1112 FlitTlpType::LocalTlpPrefix => "Local TLP Prefix",
1113 };
1114 write!(f, "{name}")
1115 }
1116}
1117
1118impl TryFrom<u8> for FlitTlpType {
1119 type Error = TlpError;
1120
1121 fn try_from(v: u8) -> Result<Self, Self::Error> {
1122 match v {
1123 0x00 => Ok(FlitTlpType::Nop),
1124 0x03 => Ok(FlitTlpType::MemRead32),
1125 0x22 => Ok(FlitTlpType::UioMemRead),
1126 0x30 => Ok(FlitTlpType::MsgToRc),
1127 0x40 => Ok(FlitTlpType::MemWrite32),
1128 0x42 => Ok(FlitTlpType::IoWrite),
1129 0x44 => Ok(FlitTlpType::CfgWrite0),
1130 0x4C => Ok(FlitTlpType::FetchAdd32),
1131 0x4E => Ok(FlitTlpType::CompareSwap32),
1132 0x5B => Ok(FlitTlpType::DeferrableMemWrite32),
1133 0x61 => Ok(FlitTlpType::UioMemWrite),
1134 0x70 => Ok(FlitTlpType::MsgDToRc),
1135 0x8D => Ok(FlitTlpType::LocalTlpPrefix),
1136 _ => Err(TlpError::InvalidType),
1137 }
1138 }
1139}
1140
1141#[derive(Debug, Clone, Copy, PartialEq)]
1154#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1155pub struct FlitDW0 {
1156 pub tlp_type: FlitTlpType,
1158 pub tc: u8,
1160 pub ohc: u8,
1164 pub ts: u8,
1166 pub attr: u8,
1168 pub length: u16,
1170}
1171
1172impl FlitDW0 {
1173 pub fn from_dw0(b: &[u8]) -> Result<Self, TlpError> {
1178 if b.len() < 4 {
1179 return Err(TlpError::InvalidLength);
1180 }
1181 let tlp_type = FlitTlpType::try_from(b[0])?;
1182 let tc = (b[1] >> 5) & 0x07;
1183 let ohc = b[1] & 0x1F;
1184 let ts = (b[2] >> 5) & 0x07;
1185 let attr = (b[2] >> 2) & 0x07;
1186 let length = (((b[2] & 0x03) as u16) << 8) | (b[3] as u16);
1187 Ok(FlitDW0 {
1188 tlp_type,
1189 tc,
1190 ohc,
1191 ts,
1192 attr,
1193 length,
1194 })
1195 }
1196
1197 pub fn ohc_count(&self) -> u8 {
1199 self.ohc.count_ones() as u8
1200 }
1201
1202 pub fn total_bytes(&self) -> usize {
1210 let header_bytes =
1211 (self.tlp_type.base_header_dw() as usize + self.ohc_count() as usize) * 4;
1212 let payload_bytes = if !self.tlp_type.has_data_payload() {
1213 0
1214 } else {
1215 let dw_count = if self.length == 0 {
1216 1024
1217 } else {
1218 self.length as usize
1219 };
1220 dw_count * 4
1221 };
1222 header_bytes + payload_bytes
1223 }
1224}
1225
1226#[derive(Debug, Clone, Copy, PartialEq)]
1240#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1241pub struct FlitOhcA {
1242 pub pasid: u32,
1244 pub fdwbe: u8,
1246 pub ldwbe: u8,
1248}
1249
1250impl FlitOhcA {
1251 pub fn from_bytes(b: &[u8]) -> Result<Self, TlpError> {
1255 if b.len() < 4 {
1256 return Err(TlpError::InvalidLength);
1257 }
1258 let pasid = ((b[0] as u32 & 0x0F) << 16) | ((b[1] as u32) << 8) | (b[2] as u32);
1259 let fdwbe = b[3] & 0x0F;
1260 let ldwbe = (b[3] >> 4) & 0x0F;
1261 Ok(FlitOhcA {
1262 pasid,
1263 fdwbe,
1264 ldwbe,
1265 })
1266 }
1267}
1268
1269impl FlitDW0 {
1270 pub fn validate_mandatory_ohc(&self) -> Result<(), TlpError> {
1278 match self.tlp_type {
1279 FlitTlpType::IoWrite | FlitTlpType::CfgWrite0 => {
1280 if self.ohc & 0x01 == 0 {
1281 return Err(TlpError::MissingMandatoryOhc);
1282 }
1283 Ok(())
1284 }
1285 _ => Ok(()),
1286 }
1287 }
1288}
1289
1290pub struct FlitStreamWalker<'a> {
1311 data: &'a [u8],
1312 pos: usize,
1313 errored: bool,
1314}
1315
1316impl<'a> FlitStreamWalker<'a> {
1317 pub fn new(data: &'a [u8]) -> Self {
1319 FlitStreamWalker {
1320 data,
1321 pos: 0,
1322 errored: false,
1323 }
1324 }
1325}
1326
1327impl Iterator for FlitStreamWalker<'_> {
1328 type Item = Result<(usize, FlitTlpType, usize), TlpError>;
1329
1330 fn next(&mut self) -> Option<Self::Item> {
1331 if self.errored || self.pos >= self.data.len() {
1332 return None;
1333 }
1334 let offset = self.pos;
1335 let dw0 = match FlitDW0::from_dw0(&self.data[self.pos..]) {
1336 Ok(d) => d,
1337 Err(e) => {
1338 self.errored = true;
1339 return Some(Err(e));
1340 }
1341 };
1342 let total = dw0.total_bytes();
1343 if self.pos + total > self.data.len() {
1344 self.errored = true;
1345 return Some(Err(TlpError::InvalidLength));
1346 }
1347 self.pos += total;
1348 Some(Ok((offset, dw0.tlp_type, total)))
1349 }
1350}
1351
1352pub struct TlpPacketHeader {
1359 header: TlpHeader<Vec<u8>>,
1360}
1361
1362impl fmt::Debug for TlpPacketHeader {
1363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1364 f.debug_struct("TlpPacketHeader")
1365 .field("format", &self.get_format())
1366 .field("type", &self.get_type())
1367 .field("tc", &self.get_tc())
1368 .field("t9", &self.get_t9())
1369 .field("t8", &self.get_t8())
1370 .field("attr_b2", &self.get_attr_b2())
1371 .field("ln", &self.get_ln())
1372 .field("th", &self.get_th())
1373 .field("td", &self.get_td())
1374 .field("ep", &self.get_ep())
1375 .field("attr", &self.get_attr())
1376 .field("at", &self.get_at())
1377 .field("length", &self.get_length())
1378 .finish()
1379 }
1380}
1381
1382impl TlpPacketHeader {
1383 pub fn new(bytes: Vec<u8>, mode: TlpMode) -> Result<TlpPacketHeader, TlpError> {
1394 match mode {
1395 TlpMode::NonFlit => Self::new_non_flit(bytes),
1396 TlpMode::Flit => Err(TlpError::NotImplemented),
1397 }
1398 }
1399
1400 fn new_non_flit(bytes: Vec<u8>) -> Result<TlpPacketHeader, TlpError> {
1401 if bytes.len() < 4 {
1402 return Err(TlpError::InvalidLength);
1403 }
1404 let mut dw0 = vec![0; 4];
1405 dw0[..4].clone_from_slice(&bytes[0..4]);
1406
1407 Ok(TlpPacketHeader {
1408 header: TlpHeader(dw0),
1409 })
1410 }
1411
1412 pub fn tlp_type(&self) -> Result<TlpType, TlpError> {
1421 self.header.get_tlp_type()
1422 }
1423
1424 #[deprecated(since = "0.5.0", note = "use tlp_type() instead")]
1430 pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
1431 self.tlp_type()
1432 }
1433
1434 pub fn get_tc(&self) -> u32 {
1436 self.header.get_tc()
1437 }
1438
1439 pub(crate) fn get_format(&self) -> u32 {
1441 self.header.get_format()
1442 }
1443 pub(crate) fn get_type(&self) -> u32 {
1444 self.header.get_type()
1445 }
1446 pub(crate) fn get_t9(&self) -> u32 {
1447 self.header.get_t9()
1448 }
1449 pub(crate) fn get_t8(&self) -> u32 {
1450 self.header.get_t8()
1451 }
1452 pub(crate) fn get_attr_b2(&self) -> u32 {
1453 self.header.get_attr_b2()
1454 }
1455 pub(crate) fn get_ln(&self) -> u32 {
1456 self.header.get_ln()
1457 }
1458 pub(crate) fn get_th(&self) -> u32 {
1459 self.header.get_th()
1460 }
1461 pub(crate) fn get_td(&self) -> u32 {
1462 self.header.get_td()
1463 }
1464 pub(crate) fn get_ep(&self) -> u32 {
1465 self.header.get_ep()
1466 }
1467 pub(crate) fn get_attr(&self) -> u32 {
1468 self.header.get_attr()
1469 }
1470 pub(crate) fn get_at(&self) -> u32 {
1471 self.header.get_at()
1472 }
1473 pub(crate) fn get_length(&self) -> u32 {
1474 self.header.get_length()
1475 }
1476}
1477
1478pub struct TlpPacket {
1528 header: TlpPacketHeader,
1529 flit_dw0: Option<FlitDW0>,
1532 data: Vec<u8>,
1533}
1534
1535impl fmt::Debug for TlpPacket {
1536 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1537 f.debug_struct("TlpPacket")
1538 .field("header", &self.header)
1539 .field("flit_dw0", &self.flit_dw0)
1540 .field("data_len", &self.data.len())
1541 .finish()
1542 }
1543}
1544
1545impl TlpPacket {
1546 pub fn new(bytes: Vec<u8>, mode: TlpMode) -> Result<TlpPacket, TlpError> {
1557 match mode {
1558 TlpMode::NonFlit => Self::new_non_flit(bytes),
1559 TlpMode::Flit => Self::new_flit(bytes),
1560 }
1561 }
1562
1563 fn new_non_flit(mut bytes: Vec<u8>) -> Result<TlpPacket, TlpError> {
1564 if bytes.len() < 4 {
1565 return Err(TlpError::InvalidLength);
1566 }
1567 let mut header = vec![0; 4];
1568 header.clone_from_slice(&bytes[0..4]);
1569 let data = bytes.drain(4..).collect();
1570 Ok(TlpPacket {
1571 header: TlpPacketHeader::new_non_flit(header)?,
1572 flit_dw0: None,
1573 data,
1574 })
1575 }
1576
1577 fn new_flit(bytes: Vec<u8>) -> Result<TlpPacket, TlpError> {
1578 if bytes.len() < 4 {
1579 return Err(TlpError::InvalidLength);
1580 }
1581 let dw0 = FlitDW0::from_dw0(&bytes)?;
1582 dw0.validate_mandatory_ohc()?;
1583
1584 let hdr_bytes = (dw0.tlp_type.base_header_dw() as usize + dw0.ohc_count() as usize) * 4;
1585 if bytes.len() < hdr_bytes {
1586 return Err(TlpError::InvalidLength);
1587 }
1588 let payload = bytes[hdr_bytes..].to_vec();
1589
1590 let dummy = TlpPacketHeader::new_non_flit(vec![0u8; 4])?;
1592 Ok(TlpPacket {
1593 header: dummy,
1594 flit_dw0: Some(dw0),
1595 data: payload,
1596 })
1597 }
1598
1599 pub fn header(&self) -> &TlpPacketHeader {
1609 &self.header
1610 }
1611
1612 pub fn data(&self) -> &[u8] {
1616 &self.data
1617 }
1618
1619 pub fn tlp_type(&self) -> Result<TlpType, TlpError> {
1630 if self.flit_dw0.is_some() {
1631 return Err(TlpError::NotImplemented);
1632 }
1633 self.header.tlp_type()
1634 }
1635
1636 pub fn tlp_format(&self) -> Result<TlpFmt, TlpError> {
1645 if self.flit_dw0.is_some() {
1646 return Err(TlpError::NotImplemented);
1647 }
1648 TlpFmt::try_from(self.header.get_format())
1649 }
1650
1651 pub fn flit_type(&self) -> Option<FlitTlpType> {
1654 self.flit_dw0.map(|d| d.tlp_type)
1655 }
1656
1657 pub fn mode(&self) -> TlpMode {
1676 if self.flit_dw0.is_some() {
1677 TlpMode::Flit
1678 } else {
1679 TlpMode::NonFlit
1680 }
1681 }
1682
1683 #[deprecated(since = "0.5.0", note = "use header() instead")]
1693 pub fn get_header(&self) -> &TlpPacketHeader {
1694 self.header()
1695 }
1696
1697 #[deprecated(since = "0.5.0", note = "use data() which returns &[u8] instead")]
1703 pub fn get_data(&self) -> Vec<u8> {
1704 self.data.clone()
1705 }
1706
1707 #[deprecated(since = "0.5.0", note = "use tlp_type() instead")]
1713 pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
1714 self.tlp_type()
1715 }
1716
1717 #[deprecated(since = "0.5.0", note = "use tlp_format() instead")]
1723 pub fn get_tlp_format(&self) -> Result<TlpFmt, TlpError> {
1724 self.tlp_format()
1725 }
1726
1727 #[deprecated(since = "0.5.0", note = "use flit_type() instead")]
1733 pub fn get_flit_type(&self) -> Option<FlitTlpType> {
1734 self.flit_type()
1735 }
1736}
1737
1738fn non_flit_short_name(tlp_type: &TlpType, fmt: &TlpFmt) -> &'static str {
1744 match tlp_type {
1745 TlpType::MemReadReq => match fmt {
1750 TlpFmt::NoDataHeader4DW => "MRd64",
1751 _ => "MRd32",
1752 },
1753 TlpType::MemReadLockReq => "MRdLk",
1754 TlpType::MemWriteReq => match fmt {
1756 TlpFmt::WithDataHeader4DW => "MWr64",
1757 _ => "MWr32",
1758 },
1759 TlpType::IOReadReq => "IORd",
1760 TlpType::IOWriteReq => "IOWr",
1761 TlpType::ConfType0ReadReq => "CfgRd0",
1762 TlpType::ConfType0WriteReq => "CfgWr0",
1763 TlpType::ConfType1ReadReq => "CfgRd1",
1764 TlpType::ConfType1WriteReq => "CfgWr1",
1765 TlpType::MsgReq => "Msg",
1766 TlpType::MsgReqData => "MsgD",
1767 TlpType::Cpl => "Cpl",
1768 TlpType::CplData => "CplD",
1769 TlpType::CplLocked => "CplLk",
1770 TlpType::CplDataLocked => "CplDLk",
1771 TlpType::FetchAddAtomicOpReq => "FAdd",
1772 TlpType::SwapAtomicOpReq => "Swap",
1773 TlpType::CompareSwapAtomicOpReq => "CAS",
1774 TlpType::DeferrableMemWriteReq => match fmt {
1776 TlpFmt::WithDataHeader4DW => "DMWr64",
1777 _ => "DMWr32",
1778 },
1779 TlpType::LocalTlpPrefix => "LPfx",
1780 TlpType::EndToEndTlpPrefix => "E2EPfx",
1781 }
1782}
1783
1784fn flit_short_name(flit_type: &FlitTlpType) -> &'static str {
1786 match flit_type {
1787 FlitTlpType::Nop => "NOP",
1788 FlitTlpType::MemRead32 => "MRd32",
1789 FlitTlpType::UioMemRead => "UMRd64",
1790 FlitTlpType::MsgToRc => "Msg",
1791 FlitTlpType::MemWrite32 => "MWr32",
1792 FlitTlpType::IoWrite => "IOWr",
1793 FlitTlpType::CfgWrite0 => "CfgWr0",
1794 FlitTlpType::FetchAdd32 => "FAdd32",
1795 FlitTlpType::CompareSwap32 => "CAS32",
1796 FlitTlpType::DeferrableMemWrite32 => "DMWr32",
1797 FlitTlpType::UioMemWrite => "UMWr64",
1798 FlitTlpType::MsgDToRc => "MsgD",
1799 FlitTlpType::LocalTlpPrefix => "LPfx",
1800 }
1801}
1802
1803impl fmt::Display for TlpPacketHeader {
1804 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1805 match self.tlp_type() {
1806 Ok(t) => {
1807 let fm = match TlpFmt::try_from(self.get_format()) {
1812 Ok(fm) => fm,
1813 Err(_) => {
1814 return write!(
1815 f,
1816 "??? fmt={:#05b} type={:#07b} len={}",
1817 self.get_format(),
1818 self.get_type(),
1819 self.get_length()
1820 );
1821 }
1822 };
1823 let short = non_flit_short_name(&t, &fm);
1824 write!(
1825 f,
1826 "{short} len={} tc={} td={} ep={}",
1827 self.get_length(),
1828 self.get_tc(),
1829 self.get_td(),
1830 self.get_ep()
1831 )
1832 }
1833 Err(_) => write!(
1834 f,
1835 "??? fmt={:#05b} type={:#07b} len={}",
1836 self.get_format(),
1837 self.get_type(),
1838 self.get_length()
1839 ),
1840 }
1841 }
1842}
1843
1844impl fmt::Display for TlpPacket {
1845 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1864 match self.mode() {
1865 TlpMode::Flit => {
1866 if let Some(dw0) = &self.flit_dw0 {
1867 let short = flit_short_name(&dw0.tlp_type);
1868 write!(f, "Flit:{short}")?;
1869
1870 if matches!(dw0.tlp_type, FlitTlpType::Nop | FlitTlpType::LocalTlpPrefix) {
1872 return Ok(());
1873 }
1874
1875 write!(f, " len={} tc={}", dw0.length, dw0.tc)?;
1876
1877 let ohc = dw0.ohc_count();
1878 if ohc > 0 {
1879 write!(f, " ohc={}", ohc)?;
1880 }
1881 if dw0.attr != 0 {
1882 write!(f, " attr={}", dw0.attr)?;
1883 }
1884 if dw0.ts != 0 {
1885 write!(f, " ts={}", dw0.ts)?;
1886 }
1887
1888 Ok(())
1892 } else {
1893 write!(f, "Flit:???")
1898 }
1899 }
1900 TlpMode::NonFlit => {
1901 let tlp_type = match self.tlp_type() {
1902 Ok(t) => t,
1903 Err(_) => return write!(f, "??? data={}B", self.data.len()),
1904 };
1905 let fmt = match self.tlp_format() {
1906 Ok(fm) => fm,
1907 Err(_) => return write!(f, "{tlp_type:?} data={}B", self.data.len()),
1908 };
1909
1910 let short_name = non_flit_short_name(&tlp_type, &fmt);
1911 let length = self.header.get_length();
1912 let data = self.data();
1913
1914 match tlp_type {
1915 TlpType::MemReadReq
1917 | TlpType::MemReadLockReq
1918 | TlpType::MemWriteReq
1919 | TlpType::DeferrableMemWriteReq
1920 | TlpType::IOReadReq
1921 | TlpType::IOWriteReq => {
1922 let header_len = core::cmp::min(data.len(), 12);
1923 if let Ok(mr) = new_mem_req(data[..header_len].to_vec(), &fmt) {
1924 write!(
1925 f,
1926 "{short_name} len={length} req={:04X} tag={:02X} addr={:X}",
1927 mr.req_id(),
1928 mr.tag(),
1929 mr.address()
1930 )
1931 } else {
1932 write!(f, "{short_name} len={length}")
1933 }
1934 }
1935 TlpType::ConfType0ReadReq
1937 | TlpType::ConfType0WriteReq
1938 | TlpType::ConfType1ReadReq
1939 | TlpType::ConfType1WriteReq => {
1940 let header_bytes = if data.len() >= 8 { &data[..8] } else { data };
1941 if let Ok(cr) = new_conf_req(header_bytes.to_vec()) {
1942 write!(
1943 f,
1944 "{short_name} len={length} req={:04X} tag={:02X} bus={:02X} dev={:02X} fn={} reg={:02X}",
1945 cr.req_id(),
1946 cr.tag(),
1947 cr.bus_nr(),
1948 cr.dev_nr(),
1949 cr.func_nr(),
1950 cr.reg_nr()
1951 )
1952 } else {
1953 write!(f, "{short_name} len={length}")
1954 }
1955 }
1956 TlpType::Cpl
1958 | TlpType::CplData
1959 | TlpType::CplLocked
1960 | TlpType::CplDataLocked => {
1961 let header_bytes = if data.len() >= 12 { &data[..12] } else { data };
1962 if let Ok(cpl) = new_cmpl_req(header_bytes.to_vec()) {
1963 write!(
1964 f,
1965 "{short_name} len={length} cpl={:04X} req={:04X} tag={:02X} stat={} bc={}",
1966 cpl.cmpl_id(),
1967 cpl.req_id(),
1968 cpl.tag(),
1969 cpl.cmpl_stat(),
1970 cpl.byte_cnt()
1971 )
1972 } else {
1973 write!(f, "{short_name} len={length}")
1974 }
1975 }
1976 TlpType::MsgReq | TlpType::MsgReqData => {
1978 let header_bytes = if data.len() > 12 { &data[..12] } else { data };
1979 if let Ok(msg) = new_msg_req(header_bytes.to_vec()) {
1980 write!(
1981 f,
1982 "{short_name} len={length} req={:04X} tag={:02X} code={:02X}",
1983 msg.req_id(),
1984 msg.tag(),
1985 msg.msg_code()
1986 )
1987 } else {
1988 write!(f, "{short_name} len={length}")
1989 }
1990 }
1991 TlpType::FetchAddAtomicOpReq
1993 | TlpType::SwapAtomicOpReq
1994 | TlpType::CompareSwapAtomicOpReq => {
1995 if let Ok(ar) = new_atomic_req(self) {
1996 write!(
1997 f,
1998 "{short_name} len={length} req={:04X} tag={:02X} addr={:X}",
1999 ar.req_id(),
2000 ar.tag(),
2001 ar.address()
2002 )
2003 } else {
2004 write!(f, "{short_name} len={length}")
2005 }
2006 }
2007 TlpType::LocalTlpPrefix | TlpType::EndToEndTlpPrefix => {
2009 write!(f, "{short_name} len={length}")
2010 }
2011 }
2012 }
2013 #[allow(unreachable_patterns)]
2015 _ => write!(f, "???"),
2016 }
2017 }
2018}
2019
2020#[cfg(test)]
2021mod tests {
2022 use super::*;
2023
2024 #[test]
2025 fn tlp_header_type() {
2026 let memread = TlpHeader([0x0, 0x0, 0x0, 0x0]);
2028 assert_eq!(memread.get_tlp_type().unwrap(), TlpType::MemReadReq);
2029
2030 let memread32 = TlpHeader([0x00, 0x00, 0x20, 0x01]);
2032 assert_eq!(memread32.get_tlp_type().unwrap(), TlpType::MemReadReq);
2033
2034 let memwrite32 = TlpHeader([0x40, 0x00, 0x00, 0x01]);
2036 assert_eq!(memwrite32.get_tlp_type().unwrap(), TlpType::MemWriteReq);
2037
2038 let cpl_no_data = TlpHeader([0x0a, 0x00, 0x10, 0x00]);
2040 assert_eq!(cpl_no_data.get_tlp_type().unwrap(), TlpType::Cpl);
2041
2042 let cpl_with_data = TlpHeader([0x4a, 0x00, 0x20, 0x40]);
2044 assert_eq!(cpl_with_data.get_tlp_type().unwrap(), TlpType::CplData);
2045
2046 let memread_4dw = TlpHeader([0x20, 0x00, 0x20, 0x40]);
2048 assert_eq!(memread_4dw.get_tlp_type().unwrap(), TlpType::MemReadReq);
2049
2050 let conf_t0_read = TlpHeader([0x04, 0x00, 0x00, 0x01]);
2052 assert_eq!(
2053 conf_t0_read.get_tlp_type().unwrap(),
2054 TlpType::ConfType0ReadReq
2055 );
2056
2057 let conf_t0_write = TlpHeader([0x44, 0x00, 0x00, 0x01]);
2059 assert_eq!(
2060 conf_t0_write.get_tlp_type().unwrap(),
2061 TlpType::ConfType0WriteReq
2062 );
2063
2064 let conf_t1_read = TlpHeader([0x05, 0x88, 0x80, 0x01]);
2066 assert_eq!(
2067 conf_t1_read.get_tlp_type().unwrap(),
2068 TlpType::ConfType1ReadReq
2069 );
2070
2071 let conf_t1_write = TlpHeader([0x45, 0x88, 0x80, 0x01]);
2073 assert_eq!(
2074 conf_t1_write.get_tlp_type().unwrap(),
2075 TlpType::ConfType1WriteReq
2076 );
2077
2078 let memwrite64 = TlpHeader([0x60, 0x00, 0x90, 0x01]);
2081 assert_eq!(memwrite64.get_tlp_type().unwrap(), TlpType::MemWriteReq);
2082 }
2083
2084 #[test]
2085 fn tlp_header_works_all_zeros() {
2086 let bits_locations = TlpHeader([0x0, 0x0, 0x0, 0x0]);
2087
2088 assert_eq!(bits_locations.get_format(), 0);
2089 assert_eq!(bits_locations.get_type(), 0);
2090 assert_eq!(bits_locations.get_t9(), 0);
2091 assert_eq!(bits_locations.get_tc(), 0);
2092 assert_eq!(bits_locations.get_t8(), 0);
2093 assert_eq!(bits_locations.get_attr_b2(), 0);
2094 assert_eq!(bits_locations.get_ln(), 0);
2095 assert_eq!(bits_locations.get_th(), 0);
2096 assert_eq!(bits_locations.get_td(), 0);
2097 assert_eq!(bits_locations.get_ep(), 0);
2098 assert_eq!(bits_locations.get_attr(), 0);
2099 assert_eq!(bits_locations.get_at(), 0);
2100 assert_eq!(bits_locations.get_length(), 0);
2101 }
2102
2103 #[test]
2104 fn tlp_header_works_all_ones() {
2105 let bits_locations = TlpHeader([0xff, 0xff, 0xff, 0xff]);
2106
2107 assert_eq!(bits_locations.get_format(), 0x7);
2108 assert_eq!(bits_locations.get_type(), 0x1f);
2109 assert_eq!(bits_locations.get_t9(), 0x1);
2110 assert_eq!(bits_locations.get_tc(), 0x7);
2111 assert_eq!(bits_locations.get_t8(), 0x1);
2112 assert_eq!(bits_locations.get_attr_b2(), 0x1);
2113 assert_eq!(bits_locations.get_ln(), 0x1);
2114 assert_eq!(bits_locations.get_th(), 0x1);
2115 assert_eq!(bits_locations.get_td(), 0x1);
2116 assert_eq!(bits_locations.get_ep(), 0x1);
2117 assert_eq!(bits_locations.get_attr(), 0x3);
2118 assert_eq!(bits_locations.get_at(), 0x3);
2119 assert_eq!(bits_locations.get_length(), 0x3ff);
2120 }
2121
2122 #[test]
2123 fn test_invalid_format_error() {
2124 let invalid_fmt_101 = TlpHeader([0xa0, 0x00, 0x00, 0x01]);
2128 assert_eq!(
2129 invalid_fmt_101.get_tlp_type().unwrap_err(),
2130 TlpError::InvalidFormat
2131 );
2132
2133 let invalid_fmt_110 = TlpHeader([0xc0, 0x00, 0x00, 0x01]);
2135 assert_eq!(
2136 invalid_fmt_110.get_tlp_type().unwrap_err(),
2137 TlpError::InvalidFormat
2138 );
2139
2140 let invalid_fmt_111 = TlpHeader([0xe0, 0x00, 0x00, 0x01]);
2142 assert_eq!(
2143 invalid_fmt_111.get_tlp_type().unwrap_err(),
2144 TlpError::InvalidFormat
2145 );
2146 }
2147
2148 #[test]
2149 fn test_invalid_type_error() {
2150 let invalid_type = TlpHeader([0x0f, 0x00, 0x00, 0x01]); let result = invalid_type.get_tlp_type();
2153 assert!(result.is_err());
2154 assert_eq!(result.unwrap_err(), TlpError::InvalidType);
2155 }
2156
2157 #[test]
2158 fn test_unsupported_combination_error() {
2159 let invalid_combo = TlpHeader([0x22, 0x00, 0x00, 0x01]); let result = invalid_combo.get_tlp_type();
2163 assert!(result.is_err());
2164 assert_eq!(result.unwrap_err(), TlpError::UnsupportedCombination);
2165 }
2166
2167 #[test]
2170 fn mem_req_rejects_tlp_prefix() {
2171 let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
2172 let result = new_mem_req(bytes, &TlpFmt::TlpPrefix);
2173 assert!(matches!(result, Err(TlpError::UnsupportedCombination)));
2174 }
2175
2176 #[test]
2179 fn packet_new_rejects_empty_input() {
2180 assert!(matches!(
2181 TlpPacket::new(vec![], TlpMode::NonFlit),
2182 Err(TlpError::InvalidLength)
2183 ));
2184 }
2185
2186 #[test]
2187 fn packet_new_rejects_3_bytes() {
2188 assert!(matches!(
2189 TlpPacket::new(vec![0x00, 0x00, 0x00], TlpMode::NonFlit),
2190 Err(TlpError::InvalidLength)
2191 ));
2192 }
2193
2194 #[test]
2195 fn packet_new_accepts_4_bytes() {
2196 assert!(TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::NonFlit).is_ok());
2198 }
2199
2200 #[test]
2201 fn packet_header_new_rejects_short_input() {
2202 assert!(matches!(
2203 TlpPacketHeader::new(vec![0x00, 0x00], TlpMode::NonFlit),
2204 Err(TlpError::InvalidLength)
2205 ));
2206 }
2207
2208 #[test]
2211 fn packet_new_flit_succeeds_for_valid_nop() {
2212 let bytes = vec![0x00, 0x00, 0x00, 0x00];
2214 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
2215 assert_eq!(pkt.flit_type(), Some(FlitTlpType::Nop));
2216 assert!(pkt.data().is_empty());
2217 }
2218
2219 #[test]
2220 fn packet_new_flit_mrd32_has_no_payload() {
2221 let bytes = vec![
2223 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2224 ];
2225 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
2226 assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemRead32));
2227 assert!(pkt.data().is_empty()); }
2229
2230 #[test]
2231 fn packet_new_flit_mwr32_has_payload() {
2232 let bytes = vec![
2234 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, ];
2239 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
2240 assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemWrite32));
2241 assert_eq!(pkt.data(), [0xDE, 0xAD, 0xBE, 0xEF]);
2242 }
2243
2244 #[test]
2245 fn packet_new_flit_nonflit_returns_none_for_flit_type() {
2246 let pkt = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::NonFlit).unwrap();
2248 assert_eq!(pkt.flit_type(), None);
2249 }
2250
2251 #[test]
2252 fn packet_header_new_flit_returns_not_implemented() {
2253 let bytes = vec![0x00, 0x00, 0x00, 0x00];
2255 assert_eq!(
2256 TlpPacketHeader::new(bytes, TlpMode::Flit).err().unwrap(),
2257 TlpError::NotImplemented
2258 );
2259 }
2260
2261 #[test]
2264 fn tlp_mode_debug_and_partialeq() {
2265 assert_eq!(TlpMode::NonFlit, TlpMode::NonFlit);
2266 assert_ne!(TlpMode::NonFlit, TlpMode::Flit);
2267 let s = format!("{:?}", TlpMode::NonFlit);
2268 assert!(s.contains("NonFlit"));
2269 let s2 = format!("{:?}", TlpMode::Flit);
2270 assert!(s2.contains("Flit"));
2271 }
2272
2273 #[test]
2274 #[allow(clippy::clone_on_copy)]
2275 fn tlp_mode_copy_and_clone() {
2276 let m = TlpMode::NonFlit;
2277 let m2 = m; let m3 = m.clone(); assert_eq!(m2, TlpMode::NonFlit);
2280 assert_eq!(m3, TlpMode::NonFlit);
2281 }
2282
2283 #[test]
2286 fn not_implemented_error_is_distinct() {
2287 let e = TlpError::NotImplemented;
2288 assert_ne!(e, TlpError::InvalidFormat);
2289 assert_ne!(e, TlpError::InvalidType);
2290 assert_ne!(e, TlpError::UnsupportedCombination);
2291 assert_ne!(e, TlpError::InvalidLength);
2292 assert_eq!(e, TlpError::NotImplemented);
2293 let s = format!("{:?}", e);
2294 assert!(s.contains("NotImplemented"));
2295 }
2296
2297 fn dw0(fmt: u8, typ: u8) -> TlpHeader<[u8; 4]> {
2302 TlpHeader([(fmt << 5) | (typ & 0x1f), 0x00, 0x00, 0x00])
2303 }
2304
2305 fn mk_tlp(fmt: u8, typ: u8, rest: &[u8]) -> Vec<u8> {
2308 let mut v = Vec::with_capacity(4 + rest.len());
2309 v.push((fmt << 5) | (typ & 0x1f));
2310 v.push(0x00); v.push(0x00); v.push(0x00); v.extend_from_slice(rest);
2314 v
2315 }
2316
2317 #[test]
2320 fn header_decode_supported_pairs() {
2321 const FMT_3DW_NO_DATA: u8 = 0b000;
2322 const FMT_4DW_NO_DATA: u8 = 0b001;
2323 const FMT_3DW_WITH_DATA: u8 = 0b010;
2324 const FMT_4DW_WITH_DATA: u8 = 0b011;
2325
2326 const TY_MEM: u8 = 0b00000;
2327 const TY_MEM_LK: u8 = 0b00001;
2328 const TY_IO: u8 = 0b00010;
2329 const TY_CFG0: u8 = 0b00100;
2330 const TY_CFG1: u8 = 0b00101;
2331 const TY_CPL: u8 = 0b01010;
2332 const TY_CPL_LK: u8 = 0b01011;
2333 const TY_ATOM_FETCH: u8 = 0b01100;
2334 const TY_ATOM_SWAP: u8 = 0b01101;
2335 const TY_ATOM_CAS: u8 = 0b01110;
2336 const TY_DMWR: u8 = 0b11011;
2337
2338 assert_eq!(
2340 dw0(FMT_3DW_NO_DATA, TY_MEM).get_tlp_type().unwrap(),
2341 TlpType::MemReadReq
2342 );
2343 assert_eq!(
2344 dw0(FMT_4DW_NO_DATA, TY_MEM).get_tlp_type().unwrap(),
2345 TlpType::MemReadReq
2346 );
2347 assert_eq!(
2348 dw0(FMT_3DW_WITH_DATA, TY_MEM).get_tlp_type().unwrap(),
2349 TlpType::MemWriteReq
2350 );
2351 assert_eq!(
2352 dw0(FMT_4DW_WITH_DATA, TY_MEM).get_tlp_type().unwrap(),
2353 TlpType::MemWriteReq
2354 );
2355
2356 assert_eq!(
2358 dw0(FMT_3DW_NO_DATA, TY_MEM_LK).get_tlp_type().unwrap(),
2359 TlpType::MemReadLockReq
2360 );
2361 assert_eq!(
2362 dw0(FMT_4DW_NO_DATA, TY_MEM_LK).get_tlp_type().unwrap(),
2363 TlpType::MemReadLockReq
2364 );
2365
2366 assert_eq!(
2368 dw0(FMT_3DW_NO_DATA, TY_IO).get_tlp_type().unwrap(),
2369 TlpType::IOReadReq
2370 );
2371 assert_eq!(
2372 dw0(FMT_3DW_WITH_DATA, TY_IO).get_tlp_type().unwrap(),
2373 TlpType::IOWriteReq
2374 );
2375
2376 assert_eq!(
2378 dw0(FMT_3DW_NO_DATA, TY_CFG0).get_tlp_type().unwrap(),
2379 TlpType::ConfType0ReadReq
2380 );
2381 assert_eq!(
2382 dw0(FMT_3DW_WITH_DATA, TY_CFG0).get_tlp_type().unwrap(),
2383 TlpType::ConfType0WriteReq
2384 );
2385
2386 assert_eq!(
2388 dw0(FMT_3DW_NO_DATA, TY_CFG1).get_tlp_type().unwrap(),
2389 TlpType::ConfType1ReadReq
2390 );
2391 assert_eq!(
2392 dw0(FMT_3DW_WITH_DATA, TY_CFG1).get_tlp_type().unwrap(),
2393 TlpType::ConfType1WriteReq
2394 );
2395
2396 assert_eq!(
2398 dw0(FMT_3DW_NO_DATA, TY_CPL).get_tlp_type().unwrap(),
2399 TlpType::Cpl
2400 );
2401 assert_eq!(
2402 dw0(FMT_3DW_WITH_DATA, TY_CPL).get_tlp_type().unwrap(),
2403 TlpType::CplData
2404 );
2405
2406 assert_eq!(
2408 dw0(FMT_3DW_NO_DATA, TY_CPL_LK).get_tlp_type().unwrap(),
2409 TlpType::CplLocked
2410 );
2411 assert_eq!(
2412 dw0(FMT_3DW_WITH_DATA, TY_CPL_LK).get_tlp_type().unwrap(),
2413 TlpType::CplDataLocked
2414 );
2415
2416 assert_eq!(
2418 dw0(FMT_3DW_WITH_DATA, TY_ATOM_FETCH)
2419 .get_tlp_type()
2420 .unwrap(),
2421 TlpType::FetchAddAtomicOpReq
2422 );
2423 assert_eq!(
2424 dw0(FMT_4DW_WITH_DATA, TY_ATOM_FETCH)
2425 .get_tlp_type()
2426 .unwrap(),
2427 TlpType::FetchAddAtomicOpReq
2428 );
2429
2430 assert_eq!(
2431 dw0(FMT_3DW_WITH_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap(),
2432 TlpType::SwapAtomicOpReq
2433 );
2434 assert_eq!(
2435 dw0(FMT_4DW_WITH_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap(),
2436 TlpType::SwapAtomicOpReq
2437 );
2438
2439 assert_eq!(
2440 dw0(FMT_3DW_WITH_DATA, TY_ATOM_CAS).get_tlp_type().unwrap(),
2441 TlpType::CompareSwapAtomicOpReq
2442 );
2443 assert_eq!(
2444 dw0(FMT_4DW_WITH_DATA, TY_ATOM_CAS).get_tlp_type().unwrap(),
2445 TlpType::CompareSwapAtomicOpReq
2446 );
2447
2448 assert_eq!(
2450 dw0(FMT_3DW_WITH_DATA, TY_DMWR).get_tlp_type().unwrap(),
2451 TlpType::DeferrableMemWriteReq
2452 );
2453 assert_eq!(
2454 dw0(FMT_4DW_WITH_DATA, TY_DMWR).get_tlp_type().unwrap(),
2455 TlpType::DeferrableMemWriteReq
2456 );
2457
2458 for routing in 0b10000u8..=0b10101u8 {
2462 assert_eq!(
2463 dw0(FMT_3DW_NO_DATA, routing).get_tlp_type().unwrap(),
2464 TlpType::MsgReq,
2465 "Fmt=000 Type={:#07b} should be MsgReq",
2466 routing
2467 );
2468 assert_eq!(
2469 dw0(FMT_4DW_NO_DATA, routing).get_tlp_type().unwrap(),
2470 TlpType::MsgReq,
2471 "Fmt=001 Type={:#07b} should be MsgReq",
2472 routing
2473 );
2474 assert_eq!(
2475 dw0(FMT_3DW_WITH_DATA, routing).get_tlp_type().unwrap(),
2476 TlpType::MsgReqData,
2477 "Fmt=010 Type={:#07b} should be MsgReqData",
2478 routing
2479 );
2480 assert_eq!(
2481 dw0(FMT_4DW_WITH_DATA, routing).get_tlp_type().unwrap(),
2482 TlpType::MsgReqData,
2483 "Fmt=011 Type={:#07b} should be MsgReqData",
2484 routing
2485 );
2486 }
2487 }
2488
2489 #[test]
2492 fn header_decode_rejects_unsupported_combinations() {
2493 const FMT_3DW_NO_DATA: u8 = 0b000;
2494 const FMT_4DW_NO_DATA: u8 = 0b001;
2495 const FMT_3DW_WITH_DATA: u8 = 0b010;
2496 const FMT_4DW_WITH_DATA: u8 = 0b011;
2497
2498 const TY_MEM_LK: u8 = 0b00001;
2499 const TY_IO: u8 = 0b00010;
2500 const TY_CFG0: u8 = 0b00100;
2501 const TY_CFG1: u8 = 0b00101;
2502 const TY_CPL: u8 = 0b01010;
2503 const TY_CPL_LK: u8 = 0b01011;
2504 const TY_ATOM_FETCH: u8 = 0b01100;
2505 const TY_ATOM_SWAP: u8 = 0b01101;
2506 const TY_ATOM_CAS: u8 = 0b01110;
2507 const TY_DMWR: u8 = 0b11011;
2508
2509 assert_eq!(
2511 dw0(FMT_4DW_NO_DATA, TY_IO).get_tlp_type().unwrap_err(),
2512 TlpError::UnsupportedCombination
2513 );
2514 assert_eq!(
2515 dw0(FMT_4DW_WITH_DATA, TY_IO).get_tlp_type().unwrap_err(),
2516 TlpError::UnsupportedCombination
2517 );
2518
2519 assert_eq!(
2521 dw0(FMT_4DW_NO_DATA, TY_CFG0).get_tlp_type().unwrap_err(),
2522 TlpError::UnsupportedCombination
2523 );
2524 assert_eq!(
2525 dw0(FMT_4DW_WITH_DATA, TY_CFG0).get_tlp_type().unwrap_err(),
2526 TlpError::UnsupportedCombination
2527 );
2528 assert_eq!(
2529 dw0(FMT_4DW_NO_DATA, TY_CFG1).get_tlp_type().unwrap_err(),
2530 TlpError::UnsupportedCombination
2531 );
2532 assert_eq!(
2533 dw0(FMT_4DW_WITH_DATA, TY_CFG1).get_tlp_type().unwrap_err(),
2534 TlpError::UnsupportedCombination
2535 );
2536
2537 assert_eq!(
2539 dw0(FMT_4DW_NO_DATA, TY_CPL).get_tlp_type().unwrap_err(),
2540 TlpError::UnsupportedCombination
2541 );
2542 assert_eq!(
2543 dw0(FMT_4DW_WITH_DATA, TY_CPL).get_tlp_type().unwrap_err(),
2544 TlpError::UnsupportedCombination
2545 );
2546 assert_eq!(
2547 dw0(FMT_4DW_NO_DATA, TY_CPL_LK).get_tlp_type().unwrap_err(),
2548 TlpError::UnsupportedCombination
2549 );
2550 assert_eq!(
2551 dw0(FMT_4DW_WITH_DATA, TY_CPL_LK)
2552 .get_tlp_type()
2553 .unwrap_err(),
2554 TlpError::UnsupportedCombination
2555 );
2556
2557 assert_eq!(
2559 dw0(FMT_3DW_NO_DATA, TY_ATOM_FETCH)
2560 .get_tlp_type()
2561 .unwrap_err(),
2562 TlpError::UnsupportedCombination
2563 );
2564 assert_eq!(
2565 dw0(FMT_4DW_NO_DATA, TY_ATOM_FETCH)
2566 .get_tlp_type()
2567 .unwrap_err(),
2568 TlpError::UnsupportedCombination
2569 );
2570 assert_eq!(
2571 dw0(FMT_3DW_NO_DATA, TY_ATOM_SWAP)
2572 .get_tlp_type()
2573 .unwrap_err(),
2574 TlpError::UnsupportedCombination
2575 );
2576 assert_eq!(
2577 dw0(FMT_4DW_NO_DATA, TY_ATOM_SWAP)
2578 .get_tlp_type()
2579 .unwrap_err(),
2580 TlpError::UnsupportedCombination
2581 );
2582 assert_eq!(
2583 dw0(FMT_3DW_NO_DATA, TY_ATOM_CAS)
2584 .get_tlp_type()
2585 .unwrap_err(),
2586 TlpError::UnsupportedCombination
2587 );
2588 assert_eq!(
2589 dw0(FMT_4DW_NO_DATA, TY_ATOM_CAS)
2590 .get_tlp_type()
2591 .unwrap_err(),
2592 TlpError::UnsupportedCombination
2593 );
2594
2595 assert_eq!(
2597 dw0(FMT_3DW_WITH_DATA, TY_MEM_LK)
2598 .get_tlp_type()
2599 .unwrap_err(),
2600 TlpError::UnsupportedCombination
2601 );
2602 assert_eq!(
2603 dw0(FMT_4DW_WITH_DATA, TY_MEM_LK)
2604 .get_tlp_type()
2605 .unwrap_err(),
2606 TlpError::UnsupportedCombination
2607 );
2608
2609 assert_eq!(
2614 dw0(FMT_3DW_NO_DATA, TY_DMWR).get_tlp_type().unwrap_err(),
2615 TlpError::UnsupportedCombination
2616 );
2617 assert_eq!(
2618 dw0(FMT_4DW_NO_DATA, TY_DMWR).get_tlp_type().unwrap_err(),
2619 TlpError::UnsupportedCombination
2620 );
2621 }
2623
2624 #[test]
2627 fn tlp_header_dmwr32_decode() {
2628 let dmwr32 = TlpHeader([0x5B, 0x00, 0x00, 0x00]);
2630 assert_eq!(
2631 dmwr32.get_tlp_type().unwrap(),
2632 TlpType::DeferrableMemWriteReq
2633 );
2634 }
2635
2636 #[test]
2637 fn tlp_header_dmwr64_decode() {
2638 let dmwr64 = TlpHeader([0x7B, 0x00, 0x00, 0x00]);
2640 assert_eq!(
2641 dmwr64.get_tlp_type().unwrap(),
2642 TlpType::DeferrableMemWriteReq
2643 );
2644 }
2645
2646 #[test]
2647 fn tlp_header_dmwr_rejects_nodata_formats() {
2648 let dmwr_bad_3dw_nodata = TlpHeader([0x1B, 0x00, 0x00, 0x00]);
2650 assert_eq!(
2651 dmwr_bad_3dw_nodata.get_tlp_type().unwrap_err(),
2652 TlpError::UnsupportedCombination
2653 );
2654
2655 let dmwr_bad_4dw_nodata = TlpHeader([0x3B, 0x00, 0x00, 0x00]);
2657 assert_eq!(
2658 dmwr_bad_4dw_nodata.get_tlp_type().unwrap_err(),
2659 TlpError::UnsupportedCombination
2660 );
2661 }
2662
2663 #[test]
2664 fn dmwr_full_packet_3dw_fields() {
2665 let payload = [
2667 0xAB, 0xCD, 0x42, 0x0F, 0xDE, 0xAD, 0x00, 0x00, ];
2670 let pkt = TlpPacket::new(mk_tlp(0b010, 0b11011, &payload), TlpMode::NonFlit).unwrap();
2671 assert_eq!(pkt.tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
2672 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader3DW);
2673
2674 let mr = new_mem_req(pkt.data().to_vec(), &pkt.tlp_format().unwrap()).unwrap();
2675 assert_eq!(mr.req_id(), 0xABCD);
2676 assert_eq!(mr.tag(), 0x42);
2677 assert_eq!(mr.address(), 0xDEAD_0000);
2678 }
2679
2680 #[test]
2681 fn dmwr_full_packet_4dw_fields() {
2682 let payload = [
2684 0xBE, 0xEF, 0xA5, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, ];
2688 let pkt = TlpPacket::new(mk_tlp(0b011, 0b11011, &payload), TlpMode::NonFlit).unwrap();
2689 assert_eq!(pkt.tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
2690 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader4DW);
2691
2692 let mr = new_mem_req(pkt.data().to_vec(), &pkt.tlp_format().unwrap()).unwrap();
2693 assert_eq!(mr.req_id(), 0xBEEF);
2694 assert_eq!(mr.tag(), 0xA5);
2695 assert_eq!(mr.address(), 0x1122_3344_5566_7788);
2696 }
2697
2698 #[test]
2701 fn is_non_posted_returns_true_for_non_posted_types() {
2702 assert!(TlpType::MemReadReq.is_non_posted());
2703 assert!(TlpType::MemReadLockReq.is_non_posted());
2704 assert!(TlpType::IOReadReq.is_non_posted());
2705 assert!(TlpType::IOWriteReq.is_non_posted());
2706 assert!(TlpType::ConfType0ReadReq.is_non_posted());
2707 assert!(TlpType::ConfType0WriteReq.is_non_posted());
2708 assert!(TlpType::ConfType1ReadReq.is_non_posted());
2709 assert!(TlpType::ConfType1WriteReq.is_non_posted());
2710 assert!(TlpType::FetchAddAtomicOpReq.is_non_posted());
2711 assert!(TlpType::SwapAtomicOpReq.is_non_posted());
2712 assert!(TlpType::CompareSwapAtomicOpReq.is_non_posted());
2713 assert!(TlpType::DeferrableMemWriteReq.is_non_posted());
2714 }
2715
2716 #[test]
2717 fn is_non_posted_returns_false_for_posted_types() {
2718 assert!(!TlpType::MemWriteReq.is_non_posted());
2719 assert!(!TlpType::MsgReq.is_non_posted());
2720 assert!(!TlpType::MsgReqData.is_non_posted());
2721 }
2722
2723 #[test]
2724 fn is_non_posted_returns_false_for_completions() {
2725 assert!(!TlpType::Cpl.is_non_posted());
2727 assert!(!TlpType::CplData.is_non_posted());
2728 assert!(!TlpType::CplLocked.is_non_posted());
2729 assert!(!TlpType::CplDataLocked.is_non_posted());
2730 }
2731
2732 #[test]
2735 fn is_non_posted_exhaustive_all_21_variants() {
2736 assert!(
2738 TlpType::MemReadReq.is_non_posted(),
2739 "MemReadReq must be non-posted"
2740 );
2741 assert!(
2742 TlpType::MemReadLockReq.is_non_posted(),
2743 "MemReadLockReq must be non-posted"
2744 );
2745 assert!(
2746 TlpType::IOReadReq.is_non_posted(),
2747 "IOReadReq must be non-posted"
2748 );
2749 assert!(
2750 TlpType::IOWriteReq.is_non_posted(),
2751 "IOWriteReq must be non-posted"
2752 );
2753 assert!(
2754 TlpType::ConfType0ReadReq.is_non_posted(),
2755 "ConfType0ReadReq must be non-posted"
2756 );
2757 assert!(
2758 TlpType::ConfType0WriteReq.is_non_posted(),
2759 "ConfType0WriteReq must be non-posted"
2760 );
2761 assert!(
2762 TlpType::ConfType1ReadReq.is_non_posted(),
2763 "ConfType1ReadReq must be non-posted"
2764 );
2765 assert!(
2766 TlpType::ConfType1WriteReq.is_non_posted(),
2767 "ConfType1WriteReq must be non-posted"
2768 );
2769 assert!(
2770 TlpType::FetchAddAtomicOpReq.is_non_posted(),
2771 "FetchAddAtomicOpReq must be non-posted"
2772 );
2773 assert!(
2774 TlpType::SwapAtomicOpReq.is_non_posted(),
2775 "SwapAtomicOpReq must be non-posted"
2776 );
2777 assert!(
2778 TlpType::CompareSwapAtomicOpReq.is_non_posted(),
2779 "CompareSwapAtomicOpReq must be non-posted"
2780 );
2781 assert!(
2782 TlpType::DeferrableMemWriteReq.is_non_posted(),
2783 "DeferrableMemWriteReq must be non-posted"
2784 );
2785
2786 assert!(
2788 !TlpType::MemWriteReq.is_non_posted(),
2789 "MemWriteReq is posted"
2790 );
2791 assert!(!TlpType::MsgReq.is_non_posted(), "MsgReq is posted");
2792 assert!(!TlpType::MsgReqData.is_non_posted(), "MsgReqData is posted");
2793
2794 assert!(
2796 !TlpType::Cpl.is_non_posted(),
2797 "Cpl is a response, not a request"
2798 );
2799 assert!(
2800 !TlpType::CplData.is_non_posted(),
2801 "CplData is a response, not a request"
2802 );
2803 assert!(
2804 !TlpType::CplLocked.is_non_posted(),
2805 "CplLocked is a response, not a request"
2806 );
2807 assert!(
2808 !TlpType::CplDataLocked.is_non_posted(),
2809 "CplDataLocked is a response, not a request"
2810 );
2811
2812 assert!(
2814 !TlpType::LocalTlpPrefix.is_non_posted(),
2815 "LocalTlpPrefix is not a transaction"
2816 );
2817 assert!(
2818 !TlpType::EndToEndTlpPrefix.is_non_posted(),
2819 "EndToEndTlpPrefix is not a transaction"
2820 );
2821 }
2822
2823 #[test]
2826 fn atomic_fetchadd_3dw_type_and_fields() {
2827 const FMT_3DW_WITH_DATA: u8 = 0b010;
2828 const TY_ATOM_FETCH: u8 = 0b01100;
2829
2830 let payload = [
2837 0x12, 0x34, 0x56, 0x00, 0x89, 0xAB, 0xCD, 0xEF, ];
2841
2842 let pkt = TlpPacket::new(
2843 mk_tlp(FMT_3DW_WITH_DATA, TY_ATOM_FETCH, &payload),
2844 TlpMode::NonFlit,
2845 )
2846 .unwrap();
2847
2848 assert_eq!(pkt.tlp_type().unwrap(), TlpType::FetchAddAtomicOpReq);
2849 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader3DW);
2850
2851 let fmt = pkt.tlp_format().unwrap();
2852 let mr = new_mem_req(pkt.data().to_vec(), &fmt).unwrap();
2853 assert_eq!(mr.req_id(), 0x1234);
2854 assert_eq!(mr.tag(), 0x56);
2855 assert_eq!(mr.address(), 0x89AB_CDEF);
2856 }
2857
2858 #[test]
2859 fn atomic_cas_4dw_type_and_fields() {
2860 const FMT_4DW_WITH_DATA: u8 = 0b011;
2861 const TY_ATOM_CAS: u8 = 0b01110;
2862
2863 let payload = [
2869 0xBE, 0xEF, 0xA5, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, ];
2874
2875 let pkt = TlpPacket::new(
2876 mk_tlp(FMT_4DW_WITH_DATA, TY_ATOM_CAS, &payload),
2877 TlpMode::NonFlit,
2878 )
2879 .unwrap();
2880
2881 assert_eq!(pkt.tlp_type().unwrap(), TlpType::CompareSwapAtomicOpReq);
2882 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader4DW);
2883
2884 let fmt = pkt.tlp_format().unwrap();
2885 let mr = new_mem_req(pkt.data().to_vec(), &fmt).unwrap();
2886 assert_eq!(mr.req_id(), 0xBEEF);
2887 assert_eq!(mr.tag(), 0xA5);
2888 assert_eq!(mr.address(), 0x1122_3344_5566_7788);
2889 }
2890
2891 #[test]
2894 fn fetchadd_3dw_operand() {
2895 let payload = [
2900 0xDE, 0xAD, 0x42, 0x00, 0xC0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, ];
2904 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &payload), TlpMode::NonFlit).unwrap();
2905 let ar = new_atomic_req(&pkt).unwrap();
2906
2907 assert_eq!(ar.op(), AtomicOp::FetchAdd);
2908 assert_eq!(ar.width(), AtomicWidth::W32);
2909 assert_eq!(ar.req_id(), 0xDEAD);
2910 assert_eq!(ar.tag(), 0x42);
2911 assert_eq!(ar.address(), 0xC001_0004);
2912 assert_eq!(ar.operand0(), 0x0A);
2913 assert!(ar.operand1().is_none());
2914 }
2915
2916 #[test]
2917 fn fetchadd_4dw_operand() {
2918 let payload = [
2923 0x00, 0x42, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
2927 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01100, &payload), TlpMode::NonFlit).unwrap();
2928 let ar = new_atomic_req(&pkt).unwrap();
2929
2930 assert_eq!(ar.op(), AtomicOp::FetchAdd);
2931 assert_eq!(ar.width(), AtomicWidth::W64);
2932 assert_eq!(ar.req_id(), 0x0042);
2933 assert_eq!(ar.tag(), 0xBB);
2934 assert_eq!(ar.address(), 0x0000_0001_0000_0000);
2935 assert_eq!(ar.operand0(), 0xFFFF_FFFF_FFFF_FFFF);
2936 assert!(ar.operand1().is_none());
2937 }
2938
2939 #[test]
2940 fn swap_3dw_operand() {
2941 let payload = [
2946 0x11, 0x11, 0x05, 0x00, 0xF0, 0x00, 0x00, 0x08, 0xAB, 0xCD, 0xEF, 0x01, ];
2950 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01101, &payload), TlpMode::NonFlit).unwrap();
2951 let ar = new_atomic_req(&pkt).unwrap();
2952
2953 assert_eq!(ar.op(), AtomicOp::Swap);
2954 assert_eq!(ar.width(), AtomicWidth::W32);
2955 assert_eq!(ar.req_id(), 0x1111);
2956 assert_eq!(ar.tag(), 0x05);
2957 assert_eq!(ar.address(), 0xF000_0008);
2958 assert_eq!(ar.operand0(), 0xABCD_EF01);
2959 assert!(ar.operand1().is_none());
2960 }
2961
2962 #[test]
2963 fn cas_3dw_two_operands() {
2964 let payload = [
2970 0xAB, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, ];
2975 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01110, &payload), TlpMode::NonFlit).unwrap();
2976 let ar = new_atomic_req(&pkt).unwrap();
2977
2978 assert_eq!(ar.op(), AtomicOp::CompareSwap);
2979 assert_eq!(ar.width(), AtomicWidth::W32);
2980 assert_eq!(ar.req_id(), 0xABCD);
2981 assert_eq!(ar.tag(), 0x07);
2982 assert_eq!(ar.address(), 0x0000_4000);
2983 assert_eq!(ar.operand0(), 0xCAFE_BABE);
2984 assert_eq!(ar.operand1(), Some(0xDEAD_BEEF));
2985 }
2986
2987 #[test]
2988 fn cas_4dw_two_operands() {
2989 let payload = [
2995 0x12, 0x34, 0xAA, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, ];
3000 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01110, &payload), TlpMode::NonFlit).unwrap();
3001 let ar = new_atomic_req(&pkt).unwrap();
3002
3003 assert_eq!(ar.op(), AtomicOp::CompareSwap);
3004 assert_eq!(ar.width(), AtomicWidth::W64);
3005 assert_eq!(ar.req_id(), 0x1234);
3006 assert_eq!(ar.tag(), 0xAA);
3007 assert_eq!(ar.address(), 0xFFFF_FFFF_0000_0000);
3008 assert_eq!(ar.operand0(), 0x0101_0101_0202_0202);
3009 assert_eq!(ar.operand1(), Some(0x0303_0303_0404_0404));
3010 }
3011
3012 #[test]
3013 fn atomic_req_rejects_wrong_tlp_type() {
3014 let pkt = TlpPacket::new(mk_tlp(0b000, 0b00000, &[0u8; 16]), TlpMode::NonFlit).unwrap();
3016 assert_eq!(
3017 new_atomic_req(&pkt).err().unwrap(),
3018 TlpError::UnsupportedCombination
3019 );
3020 }
3021
3022 #[test]
3023 fn atomic_req_rejects_wrong_format() {
3024 let pkt = TlpPacket::new(mk_tlp(0b000, 0b01100, &[0u8; 16]), TlpMode::NonFlit).unwrap();
3027 assert_eq!(
3028 new_atomic_req(&pkt).err().unwrap(),
3029 TlpError::UnsupportedCombination
3030 );
3031 }
3032
3033 #[test]
3034 fn atomic_req_rejects_short_payload() {
3035 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &[0u8; 3]), TlpMode::NonFlit).unwrap();
3037 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
3038
3039 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &[0u8; 8]), TlpMode::NonFlit).unwrap();
3041 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
3042
3043 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01110, &[0u8; 20]), TlpMode::NonFlit).unwrap();
3045 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
3046 }
3047
3048 fn mk_pkt(fmt: u8, typ: u8, data: &[u8]) -> TlpPacket {
3051 TlpPacket::new(mk_tlp(fmt, typ, data), TlpMode::NonFlit).unwrap()
3052 }
3053
3054 #[test]
3057 fn atomic_fetchadd_3dw_32_parses_operands() {
3058 let data = [
3060 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x07, ];
3064 let pkt = mk_pkt(0b010, 0b01100, &data);
3065 let a = new_atomic_req(&pkt).unwrap();
3066 assert_eq!(a.op(), AtomicOp::FetchAdd);
3067 assert_eq!(a.width(), AtomicWidth::W32);
3068 assert_eq!(a.req_id(), 0x0100);
3069 assert_eq!(a.tag(), 0x01);
3070 assert_eq!(a.address(), 0x0000_1000);
3071 assert_eq!(a.operand0(), 7);
3072 assert!(a.operand1().is_none());
3073 }
3074
3075 #[test]
3076 fn atomic_swap_4dw_64_parses_operands() {
3077 let data = [
3079 0xBE, 0xEF, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, ];
3083 let pkt = mk_pkt(0b011, 0b01101, &data);
3084 let a = new_atomic_req(&pkt).unwrap();
3085 assert_eq!(a.op(), AtomicOp::Swap);
3086 assert_eq!(a.width(), AtomicWidth::W64);
3087 assert_eq!(a.req_id(), 0xBEEF);
3088 assert_eq!(a.tag(), 0xA5);
3089 assert_eq!(a.address(), 0x0000_0001_0000_0000);
3090 assert_eq!(a.operand0(), 0xDEAD_BEEF_CAFE_BABE);
3091 assert!(a.operand1().is_none());
3092 }
3093
3094 #[test]
3095 fn atomic_cas_3dw_32_parses_operands() {
3096 let data = [
3098 0xAB, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, ];
3103 let pkt = mk_pkt(0b010, 0b01110, &data);
3104 let a = new_atomic_req(&pkt).unwrap();
3105 assert_eq!(a.op(), AtomicOp::CompareSwap);
3106 assert_eq!(a.width(), AtomicWidth::W32);
3107 assert_eq!(a.req_id(), 0xABCD);
3108 assert_eq!(a.tag(), 0x07);
3109 assert_eq!(a.address(), 0x0000_4000);
3110 assert_eq!(a.operand0(), 0xCAFE_BABE);
3111 assert_eq!(a.operand1(), Some(0xDEAD_BEEF));
3112 }
3113
3114 #[test]
3117 fn completion_laddr_full_7_bits() {
3118 let bytes = vec![
3121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, ];
3124 let cmpl = new_cmpl_req(bytes).unwrap();
3125 assert_eq!(cmpl.laddr(), 0x7F);
3126 }
3127
3128 #[test]
3129 fn completion_laddr_bit6_set() {
3130 let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40];
3133 let cmpl = new_cmpl_req(bytes).unwrap();
3134 assert_eq!(cmpl.laddr(), 0x40);
3135 }
3136
3137 #[test]
3138 fn completion_laddr_with_reserved_bit_set() {
3139 let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5];
3142 let cmpl = new_cmpl_req(bytes).unwrap();
3143 assert_eq!(cmpl.laddr(), 0x55);
3144 }
3145
3146 #[test]
3147 fn completion_full_fields_with_laddr() {
3148 let bytes = vec![
3151 0x20, 0x01, 0x00, 0xFC, 0x12, 0x34, 0xAB, 0x64, ];
3154 let cmpl = new_cmpl_req(bytes).unwrap();
3155 assert_eq!(cmpl.cmpl_id(), 0x2001);
3156 assert_eq!(cmpl.byte_cnt(), 0x0FC);
3157 assert_eq!(cmpl.req_id(), 0x1234);
3158 assert_eq!(cmpl.tag(), 0xAB);
3159 assert_eq!(cmpl.laddr(), 0x64);
3160 }
3161
3162 #[test]
3163 fn atomic_fetchadd_rejects_invalid_operand_length() {
3164 let bad = [
3167 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
3171 let pkt = mk_pkt(0b010, 0b01100, &bad);
3172 assert_eq!(new_atomic_req(&pkt).unwrap_err(), TlpError::InvalidLength);
3173 }
3174
3175 #[test]
3178 fn message_dw3_preserves_upper_16_bits() {
3179 let bytes = vec![
3181 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x00, ];
3185 let msg = new_msg_req(bytes).unwrap();
3186 assert_eq!(msg.dw3(), 0xDEAD_BEEF);
3187 }
3188
3189 #[test]
3190 fn message_dw4_preserves_upper_16_bits() {
3191 let bytes = vec![
3193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, ];
3197 let msg = new_msg_req(bytes).unwrap();
3198 assert_eq!(msg.dw4(), 0xCAFE_BABE);
3199 }
3200
3201 #[test]
3202 fn message_dw3_dw4_all_bits_set() {
3203 let bytes = vec![
3205 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
3206 ];
3207 let msg = new_msg_req(bytes).unwrap();
3208 assert_eq!(msg.dw3(), 0xFFFF_FFFF);
3209 assert_eq!(msg.dw4(), 0xFFFF_FFFF);
3210 }
3211
3212 #[test]
3213 fn message_request_full_fields() {
3214 let bytes = vec![
3216 0xAB, 0xCD, 0x42, 0x7F, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
3217 ];
3218 let msg = new_msg_req(bytes).unwrap();
3219 assert_eq!(msg.req_id(), 0xABCD);
3220 assert_eq!(msg.tag(), 0x42);
3221 assert_eq!(msg.msg_code(), 0x7F);
3222 assert_eq!(msg.dw3(), 0x1234_5678);
3223 assert_eq!(msg.dw4(), 0x9ABC_DEF0);
3224 }
3225
3226 #[test]
3229 fn tlp_packet_header_debug() {
3230 let hdr = TlpPacketHeader::new(vec![0x00, 0x00, 0x20, 0x01], TlpMode::NonFlit).unwrap();
3231 let s = format!("{:?}", hdr);
3232 assert!(s.contains("TlpPacketHeader"));
3233 assert!(s.contains("format"));
3234 assert!(s.contains("length"));
3235 }
3236
3237 #[test]
3238 fn tlp_packet_debug() {
3239 let pkt =
3240 TlpPacket::new(vec![0x40, 0x00, 0x00, 0x01, 0xDE, 0xAD], TlpMode::NonFlit).unwrap();
3241 let s = format!("{:?}", pkt);
3242 assert!(s.contains("TlpPacket"));
3243 assert!(s.contains("data_len"));
3244 }
3245
3246 #[test]
3247 fn packet_mode_returns_correct_mode() {
3248 let non_flit = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::NonFlit).unwrap();
3249 assert_eq!(non_flit.mode(), TlpMode::NonFlit);
3250
3251 let flit = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::Flit).unwrap();
3252 assert_eq!(flit.mode(), TlpMode::Flit);
3253 }
3254
3255 #[test]
3256 fn tlp_packet_debug_flit() {
3257 let pkt = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::Flit).unwrap();
3258 let s = format!("{:?}", pkt);
3259 assert!(s.contains("TlpPacket"));
3260 assert!(s.contains("flit_dw0"));
3261 }
3262
3263 #[test]
3266 fn display_memread32() {
3267 let bytes = vec![
3269 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x0F, 0x20, 0x01, 0xFF, 0x00, ];
3273 let pkt = TlpPacket::new(bytes, TlpMode::NonFlit).unwrap();
3274 let s = format!("{pkt}");
3275 assert!(s.starts_with("MRd32"));
3276 assert!(s.contains("req=0400"));
3277 assert!(s.contains("addr=2001FF00"));
3278 }
3279
3280 #[test]
3281 fn display_memwrite64() {
3282 let bytes = vec![
3284 0x60, 0x00, 0x00, 0x01, 0xBE, 0xEF, 0xA5, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, ];
3290 let pkt = TlpPacket::new(bytes, TlpMode::NonFlit).unwrap();
3291 let s = format!("{pkt}");
3292 assert!(s.starts_with("MWr64"));
3293 assert!(s.contains("req=BEEF"));
3294 assert!(s.contains("tag=A5"));
3295 }
3296
3297 #[test]
3298 fn display_config_type0_read() {
3299 let bytes = vec![
3301 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x0F, 0x02, 0x18, 0x00, 0x40, ];
3305 let pkt = TlpPacket::new(bytes, TlpMode::NonFlit).unwrap();
3306 let s = format!("{pkt}");
3307 assert!(s.starts_with("CfgRd0"));
3308 assert!(s.contains("req=0100"));
3309 assert!(s.contains("bus=02"));
3310 }
3311
3312 #[test]
3313 fn display_completion_with_data() {
3314 let bytes = vec![
3316 0x4A, 0x00, 0x00, 0x01, 0x20, 0x01, 0x00, 0xFC, 0x04, 0x00, 0xAB, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, ];
3321 let pkt = TlpPacket::new(bytes, TlpMode::NonFlit).unwrap();
3322 let s = format!("{pkt}");
3323 assert!(s.starts_with("CplD"));
3324 assert!(s.contains("cpl=2001"));
3325 assert!(s.contains("req=0400"));
3326 assert!(s.contains("tag=AB"));
3327 }
3328
3329 #[test]
3330 fn display_message() {
3331 let bytes = vec![
3333 0x30, 0x00, 0x00, 0x00, 0xAB, 0xCD, 0x01, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
3338 let pkt = TlpPacket::new(bytes, TlpMode::NonFlit).unwrap();
3339 let s = format!("{pkt}");
3340 assert!(s.starts_with("Msg"));
3341 assert!(s.contains("req=ABCD"));
3342 assert!(s.contains("code=7F"));
3343 }
3344
3345 #[test]
3346 fn display_fetchadd_3dw() {
3347 let bytes = vec![
3349 0x4C, 0x00, 0x00, 0x01, 0xDE, 0xAD, 0x42, 0x00, 0xC0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, ];
3354 let pkt = TlpPacket::new(bytes, TlpMode::NonFlit).unwrap();
3355 let s = format!("{pkt}");
3356 assert!(s.starts_with("FAdd"));
3357 assert!(s.contains("req=DEAD"));
3358 assert!(s.contains("tag=42"));
3359 assert!(s.contains("addr=C0010004"));
3360 }
3361
3362 #[test]
3365 fn display_flit_nop() {
3366 let bytes = vec![0x00, 0x00, 0x00, 0x00]; let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
3368 assert_eq!(format!("{pkt}"), "Flit:NOP");
3369 }
3370
3371 #[test]
3372 fn display_flit_memwrite32() {
3373 let mut bytes = vec![
3375 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0x00, 0x00, ];
3379 bytes.extend_from_slice(&[0u8; 16]);
3381 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
3382 let s = format!("{pkt}");
3383 assert!(s.starts_with("Flit:MWr32"));
3384 assert!(s.contains("len=4"));
3385 }
3386
3387 #[test]
3388 fn display_flit_memread32() {
3389 let bytes = vec![
3391 0x03, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ];
3395 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
3396 let s = format!("{pkt}");
3397 assert!(s.starts_with("Flit:MRd32"));
3398 assert!(s.contains("len=8"));
3399 assert!(s.contains("tc=2"));
3400 }
3401
3402 #[test]
3403 fn display_flit_cfgwrite0_with_ohc() {
3404 let bytes = vec![
3406 0x44, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xAA, 0xBB, 0xCC, 0xDD, ];
3412 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
3413 let s = format!("{pkt}");
3414 assert!(s.starts_with("Flit:CfgWr0"));
3415 assert!(s.contains("ohc=1"));
3416 }
3417
3418 #[test]
3419 fn display_flit_local_prefix() {
3420 let bytes = vec![0x8D, 0x00, 0x00, 0x00]; let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
3422 assert_eq!(format!("{pkt}"), "Flit:LPfx");
3423 }
3424
3425 #[test]
3426 fn display_header_standalone() {
3427 let hdr = TlpPacketHeader::new(vec![0x00, 0x00, 0x00, 0x01], TlpMode::NonFlit).unwrap();
3428 let s = format!("{hdr}");
3429 assert!(s.starts_with("MRd32"));
3430 assert!(s.contains("len=1"));
3431 }
3432}