1#![warn(missing_docs)]
2#![deny(unsafe_code)]
3
4use std::fmt::{self, Display};
9
10use bitfield::bitfield;
11
12#[non_exhaustive]
17#[derive(Debug, Clone, Copy, PartialEq)]
18pub enum TlpMode {
19 NonFlit,
22
23 Flit,
27}
28
29#[derive(Debug, Clone, PartialEq)]
31pub enum TlpError {
32 InvalidFormat,
34 InvalidType,
36 UnsupportedCombination,
38 InvalidLength,
40 NotImplemented,
42 MissingMandatoryOhc,
45}
46
47impl fmt::Display for TlpError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 TlpError::InvalidFormat => write!(f, "invalid TLP format field"),
51 TlpError::InvalidType => write!(f, "invalid TLP type field"),
52 TlpError::UnsupportedCombination => write!(f, "unsupported format/type combination"),
53 TlpError::InvalidLength => write!(f, "byte slice too short for expected TLP fields"),
54 TlpError::NotImplemented => write!(f, "feature not yet implemented"),
55 TlpError::MissingMandatoryOhc => {
56 write!(f, "mandatory OHC word missing for this TLP type")
57 }
58 }
59 }
60}
61
62impl std::error::Error for TlpError {}
63
64#[repr(u8)]
66#[derive(Debug, PartialEq, Copy, Clone)]
67pub enum TlpFmt {
68 NoDataHeader3DW = 0b000,
70 NoDataHeader4DW = 0b001,
72 WithDataHeader3DW = 0b010,
74 WithDataHeader4DW = 0b011,
76 TlpPrefix = 0b100,
78}
79
80impl Display for TlpFmt {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 let name = match self {
83 TlpFmt::NoDataHeader3DW => "3DW no Data Header",
84 TlpFmt::NoDataHeader4DW => "4DW no Data Header",
85 TlpFmt::WithDataHeader3DW => "3DW with Data Header",
86 TlpFmt::WithDataHeader4DW => "4DW with Data Header",
87 TlpFmt::TlpPrefix => "Tlp Prefix",
88 };
89 write!(f, "{name}")
90 }
91}
92
93impl TryFrom<u32> for TlpFmt {
94 type Error = TlpError;
95
96 fn try_from(v: u32) -> Result<Self, Self::Error> {
97 match v {
98 0b000 => Ok(TlpFmt::NoDataHeader3DW),
99 0b001 => Ok(TlpFmt::NoDataHeader4DW),
100 0b010 => Ok(TlpFmt::WithDataHeader3DW),
101 0b011 => Ok(TlpFmt::WithDataHeader4DW),
102 0b100 => Ok(TlpFmt::TlpPrefix),
103 _ => Err(TlpError::InvalidFormat),
104 }
105 }
106}
107
108#[derive(Debug, Copy, Clone, PartialEq)]
110pub enum AtomicOp {
111 FetchAdd,
113 Swap,
115 CompareSwap,
117}
118
119#[derive(Debug, Copy, Clone, PartialEq)]
121pub enum AtomicWidth {
122 W32,
124 W64,
126}
127
128#[derive(PartialEq)]
129pub(crate) enum TlpFormatEncodingType {
130 MemoryRequest = 0b00000,
131 MemoryLockRequest = 0b00001,
132 IORequest = 0b00010,
133 ConfigType0Request = 0b00100,
134 ConfigType1Request = 0b00101,
135 Completion = 0b01010,
136 CompletionLocked = 0b01011,
137 FetchAtomicOpRequest = 0b01100,
138 UnconSwapAtomicOpRequest = 0b01101,
139 CompSwapAtomicOpRequest = 0b01110,
140 DeferrableMemoryWriteRequest = 0b11011,
141 MessageRequest = 0b10000,
144}
145
146impl TryFrom<u32> for TlpFormatEncodingType {
147 type Error = TlpError;
148
149 fn try_from(v: u32) -> Result<Self, Self::Error> {
150 match v {
151 0b00000 => Ok(TlpFormatEncodingType::MemoryRequest),
152 0b00001 => Ok(TlpFormatEncodingType::MemoryLockRequest),
153 0b00010 => Ok(TlpFormatEncodingType::IORequest),
154 0b00100 => Ok(TlpFormatEncodingType::ConfigType0Request),
155 0b00101 => Ok(TlpFormatEncodingType::ConfigType1Request),
156 0b01010 => Ok(TlpFormatEncodingType::Completion),
157 0b01011 => Ok(TlpFormatEncodingType::CompletionLocked),
158 0b01100 => Ok(TlpFormatEncodingType::FetchAtomicOpRequest),
159 0b01101 => Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest),
160 0b01110 => Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest),
161 0b11011 => Ok(TlpFormatEncodingType::DeferrableMemoryWriteRequest),
162 0b10000..=0b10101 => Ok(TlpFormatEncodingType::MessageRequest),
165 _ => Err(TlpError::InvalidType),
166 }
167 }
168}
169
170#[derive(PartialEq, Debug)]
172pub enum TlpType {
173 MemReadReq,
175 MemReadLockReq,
177 MemWriteReq,
179 IOReadReq,
181 IOWriteReq,
183 ConfType0ReadReq,
185 ConfType0WriteReq,
187 ConfType1ReadReq,
189 ConfType1WriteReq,
191 MsgReq,
193 MsgReqData,
195 Cpl,
197 CplData,
199 CplLocked,
201 CplDataLocked,
203 FetchAddAtomicOpReq,
205 SwapAtomicOpReq,
207 CompareSwapAtomicOpReq,
209 DeferrableMemWriteReq,
211 LocalTlpPrefix,
213 EndToEndTlpPrefix,
215}
216
217impl Display for TlpType {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 let name = match self {
220 TlpType::MemReadReq => "Memory Read Request",
221 TlpType::MemReadLockReq => "Locked Memory Read Request",
222 TlpType::MemWriteReq => "Memory Write Request",
223 TlpType::IOReadReq => "IO Read Request",
224 TlpType::IOWriteReq => "IO Write Request",
225 TlpType::ConfType0ReadReq => "Type 0 Config Read Request",
226 TlpType::ConfType0WriteReq => "Type 0 Config Write Request",
227 TlpType::ConfType1ReadReq => "Type 1 Config Read Request",
228 TlpType::ConfType1WriteReq => "Type 1 Config Write Request",
229 TlpType::MsgReq => "Message Request",
230 TlpType::MsgReqData => "Message with Data Request",
231 TlpType::Cpl => "Completion",
232 TlpType::CplData => "Completion with Data",
233 TlpType::CplLocked => "Locked Completion",
234 TlpType::CplDataLocked => "Locked Completion with Data",
235 TlpType::FetchAddAtomicOpReq => "Fetch Add Atomic Op Request",
236 TlpType::SwapAtomicOpReq => "Swap Atomic Op Request",
237 TlpType::CompareSwapAtomicOpReq => "Compare Swap Atomic Op Request",
238 TlpType::DeferrableMemWriteReq => "Deferrable Memory Write Request",
239 TlpType::LocalTlpPrefix => "Local Tlp Prefix",
240 TlpType::EndToEndTlpPrefix => "End To End Tlp Prefix",
241 };
242 write!(f, "{name}")
243 }
244}
245
246impl TlpType {
247 pub fn is_non_posted(&self) -> bool {
252 matches!(
253 self,
254 TlpType::MemReadReq
255 | TlpType::MemReadLockReq
256 | TlpType::IOReadReq
257 | TlpType::IOWriteReq
258 | TlpType::ConfType0ReadReq
259 | TlpType::ConfType0WriteReq
260 | TlpType::ConfType1ReadReq
261 | TlpType::ConfType1WriteReq
262 | TlpType::FetchAddAtomicOpReq
263 | TlpType::SwapAtomicOpReq
264 | TlpType::CompareSwapAtomicOpReq
265 | TlpType::DeferrableMemWriteReq
266 )
267 }
268
269 pub fn is_posted(&self) -> bool {
283 !self.is_non_posted()
284 }
285}
286
287bitfield! {
288 struct TlpHeader(MSB0 [u8]);
289 u32;
290 get_format, _: 2, 0;
291 get_type, _: 7, 3;
292 get_t9, _: 8, 8;
293 get_tc, _: 11, 9;
294 get_t8, _: 12, 12;
295 get_attr_b2, _: 13, 13;
296 get_ln, _: 14, 14;
297 get_th, _: 15, 15;
298 get_td, _: 16, 16;
299 get_ep, _: 17, 17;
300 get_attr, _: 19, 18;
301 get_at, _: 21, 20;
302 get_length, _: 31, 22;
303}
304
305impl<T: AsRef<[u8]>> TlpHeader<T> {
306 fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
307 let tlp_type = self.get_type();
308 let tlp_fmt = self.get_format();
309
310 if let Ok(TlpFmt::TlpPrefix) = TlpFmt::try_from(tlp_fmt) {
313 return if tlp_type & 0b10000 != 0 {
314 Ok(TlpType::EndToEndTlpPrefix)
315 } else {
316 Ok(TlpType::LocalTlpPrefix)
317 };
318 }
319
320 match TlpFormatEncodingType::try_from(tlp_type) {
321 Ok(TlpFormatEncodingType::MemoryRequest) => match TlpFmt::try_from(tlp_fmt) {
322 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadReq),
323 Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadReq),
324 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::MemWriteReq),
325 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::MemWriteReq),
326 Ok(_) => Err(TlpError::UnsupportedCombination),
327 Err(e) => Err(e),
328 },
329 Ok(TlpFormatEncodingType::MemoryLockRequest) => match TlpFmt::try_from(tlp_fmt) {
330 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadLockReq),
331 Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadLockReq),
332 Ok(_) => Err(TlpError::UnsupportedCombination),
333 Err(e) => Err(e),
334 },
335 Ok(TlpFormatEncodingType::IORequest) => match TlpFmt::try_from(tlp_fmt) {
336 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::IOReadReq),
337 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::IOWriteReq),
338 Ok(_) => Err(TlpError::UnsupportedCombination),
339 Err(e) => Err(e),
340 },
341 Ok(TlpFormatEncodingType::ConfigType0Request) => match TlpFmt::try_from(tlp_fmt) {
342 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType0ReadReq),
343 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType0WriteReq),
344 Ok(_) => Err(TlpError::UnsupportedCombination),
345 Err(e) => Err(e),
346 },
347 Ok(TlpFormatEncodingType::ConfigType1Request) => match TlpFmt::try_from(tlp_fmt) {
348 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType1ReadReq),
349 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType1WriteReq),
350 Ok(_) => Err(TlpError::UnsupportedCombination),
351 Err(e) => Err(e),
352 },
353 Ok(TlpFormatEncodingType::Completion) => match TlpFmt::try_from(tlp_fmt) {
354 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::Cpl),
355 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplData),
356 Ok(_) => Err(TlpError::UnsupportedCombination),
357 Err(e) => Err(e),
358 },
359 Ok(TlpFormatEncodingType::CompletionLocked) => match TlpFmt::try_from(tlp_fmt) {
360 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::CplLocked),
361 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplDataLocked),
362 Ok(_) => Err(TlpError::UnsupportedCombination),
363 Err(e) => Err(e),
364 },
365 Ok(TlpFormatEncodingType::FetchAtomicOpRequest) => match TlpFmt::try_from(tlp_fmt) {
366 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::FetchAddAtomicOpReq),
367 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::FetchAddAtomicOpReq),
368 Ok(_) => Err(TlpError::UnsupportedCombination),
369 Err(e) => Err(e),
370 },
371 Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest) => {
372 match TlpFmt::try_from(tlp_fmt) {
373 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::SwapAtomicOpReq),
374 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::SwapAtomicOpReq),
375 Ok(_) => Err(TlpError::UnsupportedCombination),
376 Err(e) => Err(e),
377 }
378 }
379 Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest) => match TlpFmt::try_from(tlp_fmt) {
380 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CompareSwapAtomicOpReq),
381 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::CompareSwapAtomicOpReq),
382 Ok(_) => Err(TlpError::UnsupportedCombination),
383 Err(e) => Err(e),
384 },
385 Ok(TlpFormatEncodingType::DeferrableMemoryWriteRequest) => {
386 match TlpFmt::try_from(tlp_fmt) {
387 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::DeferrableMemWriteReq),
388 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::DeferrableMemWriteReq),
389 Ok(_) => Err(TlpError::UnsupportedCombination),
390 Err(e) => Err(e),
391 }
392 }
393 Ok(TlpFormatEncodingType::MessageRequest) => match TlpFmt::try_from(tlp_fmt) {
396 Ok(TlpFmt::NoDataHeader3DW) | Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MsgReq),
397 Ok(TlpFmt::WithDataHeader3DW) | Ok(TlpFmt::WithDataHeader4DW) => {
398 Ok(TlpType::MsgReqData)
399 }
400 Ok(_) => Err(TlpError::UnsupportedCombination),
401 Err(e) => Err(e),
402 },
403 Err(e) => Err(e),
404 }
405 }
406}
407
408pub trait MemRequest {
415 fn address(&self) -> u64;
417 fn req_id(&self) -> u16;
419 fn tag(&self) -> u8;
421 fn ldwbe(&self) -> u8;
423 fn fdwbe(&self) -> u8;
425}
426
427bitfield! {
430 #[allow(missing_docs)]
431 pub struct MemRequest3DW(MSB0 [u8]);
432 u32;
433 pub get_requester_id, _: 15, 0;
435 pub get_tag, _: 23, 16;
437 pub get_last_dw_be, _: 27, 24;
439 pub get_first_dw_be, _: 31, 28;
441 pub get_address32, _: 63, 32;
443}
444
445bitfield! {
447 #[allow(missing_docs)]
448 pub struct MemRequest4DW(MSB0 [u8]);
449 u64;
450 pub get_requester_id, _: 15, 0;
452 pub get_tag, _: 23, 16;
454 pub get_last_dw_be, _: 27, 24;
456 pub get_first_dw_be, _: 31, 28;
458 pub get_address64, _: 95, 32;
460}
461
462impl<T: AsRef<[u8]>> MemRequest for MemRequest3DW<T> {
463 fn address(&self) -> u64 {
464 self.get_address32().into()
465 }
466 fn req_id(&self) -> u16 {
467 self.get_requester_id() as u16
468 }
469 fn tag(&self) -> u8 {
470 self.get_tag() as u8
471 }
472 fn ldwbe(&self) -> u8 {
473 self.get_last_dw_be() as u8
474 }
475 fn fdwbe(&self) -> u8 {
476 self.get_first_dw_be() as u8
477 }
478}
479
480impl<T: AsRef<[u8]>> MemRequest for MemRequest4DW<T> {
481 fn address(&self) -> u64 {
482 self.get_address64()
483 }
484 fn req_id(&self) -> u16 {
485 self.get_requester_id() as u16
486 }
487 fn tag(&self) -> u8 {
488 self.get_tag() as u8
489 }
490 fn ldwbe(&self) -> u8 {
491 self.get_last_dw_be() as u8
492 }
493 fn fdwbe(&self) -> u8 {
494 self.get_first_dw_be() as u8
495 }
496}
497
498pub fn new_mem_req(
538 bytes: impl Into<Vec<u8>>,
539 format: &TlpFmt,
540) -> Result<Box<dyn MemRequest>, TlpError> {
541 let bytes = bytes.into();
542 match format {
543 TlpFmt::NoDataHeader3DW | TlpFmt::WithDataHeader3DW => {
544 if bytes.len() < 8 {
545 return Err(TlpError::InvalidLength);
546 }
547 Ok(Box::new(MemRequest3DW(bytes)))
548 }
549 TlpFmt::NoDataHeader4DW | TlpFmt::WithDataHeader4DW => {
550 if bytes.len() < 12 {
551 return Err(TlpError::InvalidLength);
552 }
553 Ok(Box::new(MemRequest4DW(bytes)))
554 }
555 TlpFmt::TlpPrefix => Err(TlpError::UnsupportedCombination),
556 }
557}
558
559pub trait ConfigurationRequest {
563 fn req_id(&self) -> u16;
565 fn tag(&self) -> u8;
567 fn bus_nr(&self) -> u8;
569 fn dev_nr(&self) -> u8;
571 fn func_nr(&self) -> u8;
573 fn ext_reg_nr(&self) -> u8;
575 fn reg_nr(&self) -> u8;
577}
578
579pub fn new_conf_req(bytes: impl Into<Vec<u8>>) -> Result<Box<dyn ConfigurationRequest>, TlpError> {
611 let bytes = bytes.into();
612 if bytes.len() < 8 {
613 return Err(TlpError::InvalidLength);
614 }
615 Ok(Box::new(ConfigRequest(bytes)))
616}
617
618bitfield! {
620 #[allow(missing_docs)]
621 pub struct ConfigRequest(MSB0 [u8]);
622 u32;
623 pub get_requester_id, _: 15, 0;
625 pub get_tag, _: 23, 16;
627 pub get_last_dw_be, _: 27, 24;
629 pub get_first_dw_be, _: 31, 28;
631 pub get_bus_nr, _: 39, 32;
633 pub get_dev_nr, _: 44, 40;
635 pub get_func_nr, _: 47, 45;
637 pub rsvd, _: 51, 48;
639 pub get_ext_reg_nr, _: 55, 52;
641 pub get_register_nr, _: 61, 56;
643 r, _: 63, 62;
644}
645
646impl<T: AsRef<[u8]>> ConfigurationRequest for ConfigRequest<T> {
647 fn req_id(&self) -> u16 {
648 self.get_requester_id() as u16
649 }
650 fn tag(&self) -> u8 {
651 self.get_tag() as u8
652 }
653 fn bus_nr(&self) -> u8 {
654 self.get_bus_nr() as u8
655 }
656 fn dev_nr(&self) -> u8 {
657 self.get_dev_nr() as u8
658 }
659 fn func_nr(&self) -> u8 {
660 self.get_func_nr() as u8
661 }
662 fn ext_reg_nr(&self) -> u8 {
663 self.get_ext_reg_nr() as u8
664 }
665 fn reg_nr(&self) -> u8 {
666 self.get_register_nr() as u8
667 }
668}
669
670pub trait CompletionRequest {
676 fn cmpl_id(&self) -> u16;
678 fn cmpl_stat(&self) -> u8;
680 fn bcm(&self) -> u8;
682 fn byte_cnt(&self) -> u16;
684 fn req_id(&self) -> u16;
686 fn tag(&self) -> u8;
688 fn laddr(&self) -> u8;
690}
691
692bitfield! {
694 #[allow(missing_docs)]
695 pub struct CompletionReqDW23(MSB0 [u8]);
696 u16;
697 pub get_completer_id, _: 15, 0;
699 pub get_cmpl_stat, _: 18, 16;
701 pub get_bcm, _: 19, 19;
703 pub get_byte_cnt, _: 31, 20;
705 pub get_req_id, _: 47, 32;
707 pub get_tag, _: 55, 48;
709 r, _: 56, 56;
710 pub get_laddr, _: 63, 57;
712}
713
714impl<T: AsRef<[u8]>> CompletionRequest for CompletionReqDW23<T> {
715 fn cmpl_id(&self) -> u16 {
716 self.get_completer_id()
717 }
718 fn cmpl_stat(&self) -> u8 {
719 self.get_cmpl_stat() as u8
720 }
721 fn bcm(&self) -> u8 {
722 self.get_bcm() as u8
723 }
724 fn byte_cnt(&self) -> u16 {
725 self.get_byte_cnt()
726 }
727 fn req_id(&self) -> u16 {
728 self.get_req_id()
729 }
730 fn tag(&self) -> u8 {
731 self.get_tag() as u8
732 }
733 fn laddr(&self) -> u8 {
734 self.get_laddr() as u8
735 }
736}
737
738pub fn new_cmpl_req(bytes: impl Into<Vec<u8>>) -> Result<Box<dyn CompletionRequest>, TlpError> {
760 let bytes = bytes.into();
761 if bytes.len() < 8 {
762 return Err(TlpError::InvalidLength);
763 }
764 Ok(Box::new(CompletionReqDW23(bytes)))
765}
766
767pub trait MessageRequest {
770 fn req_id(&self) -> u16;
772 fn tag(&self) -> u8;
774 fn msg_code(&self) -> u8;
776 fn dw3(&self) -> u32;
778 fn dw4(&self) -> u32;
780}
781
782bitfield! {
784 #[allow(missing_docs)]
785 pub struct MessageReqDW24(MSB0 [u8]);
786 u32;
787 pub get_requester_id, _: 15, 0;
789 pub get_tag, _: 23, 16;
791 pub get_msg_code, _: 31, 24;
793 pub get_dw3, _: 63, 32;
795 pub get_dw4, _: 95, 64;
797}
798
799impl<T: AsRef<[u8]>> MessageRequest for MessageReqDW24<T> {
800 fn req_id(&self) -> u16 {
801 self.get_requester_id() as u16
802 }
803 fn tag(&self) -> u8 {
804 self.get_tag() as u8
805 }
806 fn msg_code(&self) -> u8 {
807 self.get_msg_code() as u8
808 }
809 fn dw3(&self) -> u32 {
810 self.get_dw3()
811 }
812 fn dw4(&self) -> u32 {
813 self.get_dw4()
814 }
815 }
817
818pub fn new_msg_req(bytes: impl Into<Vec<u8>>) -> Result<Box<dyn MessageRequest>, TlpError> {
839 let bytes = bytes.into();
840 if bytes.len() < 12 {
841 return Err(TlpError::InvalidLength);
842 }
843 Ok(Box::new(MessageReqDW24(bytes)))
844}
845
846pub trait AtomicRequest: std::fmt::Debug {
849 fn op(&self) -> AtomicOp;
851 fn width(&self) -> AtomicWidth;
853 fn req_id(&self) -> u16;
855 fn tag(&self) -> u8;
857 fn address(&self) -> u64;
859 fn operand0(&self) -> u64;
861 fn operand1(&self) -> Option<u64>;
863}
864
865#[derive(Debug)]
866struct AtomicReq {
867 op: AtomicOp,
868 width: AtomicWidth,
869 req_id: u16,
870 tag: u8,
871 address: u64,
872 operand0: u64,
873 operand1: Option<u64>,
874}
875
876impl AtomicRequest for AtomicReq {
877 fn op(&self) -> AtomicOp {
878 self.op
879 }
880 fn width(&self) -> AtomicWidth {
881 self.width
882 }
883 fn req_id(&self) -> u16 {
884 self.req_id
885 }
886 fn tag(&self) -> u8 {
887 self.tag
888 }
889 fn address(&self) -> u64 {
890 self.address
891 }
892 fn operand0(&self) -> u64 {
893 self.operand0
894 }
895 fn operand1(&self) -> Option<u64> {
896 self.operand1
897 }
898}
899
900fn read_operand_be(b: &[u8], off: usize, width: AtomicWidth) -> u64 {
901 match width {
902 AtomicWidth::W32 => u32::from_be_bytes([b[off], b[off + 1], b[off + 2], b[off + 3]]) as u64,
903 AtomicWidth::W64 => u64::from_be_bytes([
904 b[off],
905 b[off + 1],
906 b[off + 2],
907 b[off + 3],
908 b[off + 4],
909 b[off + 5],
910 b[off + 6],
911 b[off + 7],
912 ]),
913 }
914}
915
916pub fn new_atomic_req(pkt: &TlpPacket) -> Result<Box<dyn AtomicRequest>, TlpError> {
946 let tlp_type = pkt.tlp_type()?;
947 let format = pkt.tlp_format()?;
948 let bytes = pkt.data();
949
950 let op = match tlp_type {
951 TlpType::FetchAddAtomicOpReq => AtomicOp::FetchAdd,
952 TlpType::SwapAtomicOpReq => AtomicOp::Swap,
953 TlpType::CompareSwapAtomicOpReq => AtomicOp::CompareSwap,
954 _ => return Err(TlpError::UnsupportedCombination),
955 };
956 let (width, hdr_len) = match format {
957 TlpFmt::WithDataHeader3DW => (AtomicWidth::W32, 8usize),
958 TlpFmt::WithDataHeader4DW => (AtomicWidth::W64, 12usize),
959 _ => return Err(TlpError::UnsupportedCombination),
960 };
961
962 let op_size = match width {
963 AtomicWidth::W32 => 4usize,
964 AtomicWidth::W64 => 8usize,
965 };
966 let num_ops = if matches!(op, AtomicOp::CompareSwap) {
967 2
968 } else {
969 1
970 };
971 let needed = hdr_len + op_size * num_ops;
972 if bytes.len() != needed {
973 return Err(TlpError::InvalidLength);
974 }
975
976 let req_id = u16::from_be_bytes([bytes[0], bytes[1]]);
977 let tag = bytes[2];
978 let address = match width {
979 AtomicWidth::W32 => u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64,
980 AtomicWidth::W64 => u64::from_be_bytes([
981 bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11],
982 ]),
983 };
984
985 let operand0 = read_operand_be(bytes, hdr_len, width);
986 let operand1 = if matches!(op, AtomicOp::CompareSwap) {
987 Some(read_operand_be(bytes, hdr_len + op_size, width))
988 } else {
989 None
990 };
991
992 Ok(Box::new(AtomicReq {
993 op,
994 width,
995 req_id,
996 tag,
997 address,
998 operand0,
999 operand1,
1000 }))
1001}
1002
1003#[non_exhaustive]
1016#[derive(Debug, Clone, Copy, PartialEq)]
1017pub enum FlitTlpType {
1018 Nop,
1020 MemRead32,
1022 UioMemRead,
1024 MsgToRc,
1026 MemWrite32,
1028 IoWrite,
1030 CfgWrite0,
1032 FetchAdd32,
1034 CompareSwap32,
1036 DeferrableMemWrite32,
1038 UioMemWrite,
1040 MsgDToRc,
1042 LocalTlpPrefix,
1044}
1045
1046impl FlitTlpType {
1047 pub fn base_header_dw(&self) -> u8 {
1053 match self {
1054 FlitTlpType::Nop | FlitTlpType::LocalTlpPrefix => 1,
1055 FlitTlpType::UioMemRead | FlitTlpType::UioMemWrite => 4,
1056 _ => 3,
1057 }
1058 }
1059
1060 pub fn is_read_request(&self) -> bool {
1063 matches!(self, FlitTlpType::MemRead32 | FlitTlpType::UioMemRead)
1064 }
1065
1066 pub fn has_data_payload(&self) -> bool {
1074 matches!(
1075 self,
1076 FlitTlpType::MemWrite32
1077 | FlitTlpType::UioMemWrite
1078 | FlitTlpType::IoWrite
1079 | FlitTlpType::CfgWrite0
1080 | FlitTlpType::FetchAdd32
1081 | FlitTlpType::CompareSwap32
1082 | FlitTlpType::DeferrableMemWrite32
1083 | FlitTlpType::MsgDToRc
1084 )
1085 }
1086}
1087
1088impl Display for FlitTlpType {
1089 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090 let name = match self {
1091 FlitTlpType::Nop => "NOP",
1092 FlitTlpType::MemRead32 => "Memory Read (32-bit)",
1093 FlitTlpType::UioMemRead => "UIO Memory Read (64-bit)",
1094 FlitTlpType::MsgToRc => "Message routed to RC",
1095 FlitTlpType::MemWrite32 => "Memory Write (32-bit)",
1096 FlitTlpType::IoWrite => "I/O Write",
1097 FlitTlpType::CfgWrite0 => "Config Type 0 Write",
1098 FlitTlpType::FetchAdd32 => "FetchAdd AtomicOp (32-bit)",
1099 FlitTlpType::CompareSwap32 => "CompareSwap AtomicOp (32-bit)",
1100 FlitTlpType::DeferrableMemWrite32 => "Deferrable Memory Write (32-bit)",
1101 FlitTlpType::UioMemWrite => "UIO Memory Write (64-bit)",
1102 FlitTlpType::MsgDToRc => "Message with Data routed to RC",
1103 FlitTlpType::LocalTlpPrefix => "Local TLP Prefix",
1104 };
1105 write!(f, "{name}")
1106 }
1107}
1108
1109impl TryFrom<u8> for FlitTlpType {
1110 type Error = TlpError;
1111
1112 fn try_from(v: u8) -> Result<Self, Self::Error> {
1113 match v {
1114 0x00 => Ok(FlitTlpType::Nop),
1115 0x03 => Ok(FlitTlpType::MemRead32),
1116 0x22 => Ok(FlitTlpType::UioMemRead),
1117 0x30 => Ok(FlitTlpType::MsgToRc),
1118 0x40 => Ok(FlitTlpType::MemWrite32),
1119 0x42 => Ok(FlitTlpType::IoWrite),
1120 0x44 => Ok(FlitTlpType::CfgWrite0),
1121 0x4C => Ok(FlitTlpType::FetchAdd32),
1122 0x4E => Ok(FlitTlpType::CompareSwap32),
1123 0x5B => Ok(FlitTlpType::DeferrableMemWrite32),
1124 0x61 => Ok(FlitTlpType::UioMemWrite),
1125 0x70 => Ok(FlitTlpType::MsgDToRc),
1126 0x8D => Ok(FlitTlpType::LocalTlpPrefix),
1127 _ => Err(TlpError::InvalidType),
1128 }
1129 }
1130}
1131
1132#[derive(Debug, Clone, Copy, PartialEq)]
1145pub struct FlitDW0 {
1146 pub tlp_type: FlitTlpType,
1148 pub tc: u8,
1150 pub ohc: u8,
1154 pub ts: u8,
1156 pub attr: u8,
1158 pub length: u16,
1160}
1161
1162impl FlitDW0 {
1163 pub fn from_dw0(b: &[u8]) -> Result<Self, TlpError> {
1168 if b.len() < 4 {
1169 return Err(TlpError::InvalidLength);
1170 }
1171 let tlp_type = FlitTlpType::try_from(b[0])?;
1172 let tc = (b[1] >> 5) & 0x07;
1173 let ohc = b[1] & 0x1F;
1174 let ts = (b[2] >> 5) & 0x07;
1175 let attr = (b[2] >> 2) & 0x07;
1176 let length = (((b[2] & 0x03) as u16) << 8) | (b[3] as u16);
1177 Ok(FlitDW0 {
1178 tlp_type,
1179 tc,
1180 ohc,
1181 ts,
1182 attr,
1183 length,
1184 })
1185 }
1186
1187 pub fn ohc_count(&self) -> u8 {
1189 self.ohc.count_ones() as u8
1190 }
1191
1192 pub fn total_bytes(&self) -> usize {
1200 let header_bytes =
1201 (self.tlp_type.base_header_dw() as usize + self.ohc_count() as usize) * 4;
1202 let payload_bytes = if !self.tlp_type.has_data_payload() {
1203 0
1204 } else {
1205 let dw_count = if self.length == 0 {
1206 1024
1207 } else {
1208 self.length as usize
1209 };
1210 dw_count * 4
1211 };
1212 header_bytes + payload_bytes
1213 }
1214}
1215
1216#[derive(Debug, Clone, Copy, PartialEq)]
1230pub struct FlitOhcA {
1231 pub pasid: u32,
1233 pub fdwbe: u8,
1235 pub ldwbe: u8,
1237}
1238
1239impl FlitOhcA {
1240 pub fn from_bytes(b: &[u8]) -> Result<Self, TlpError> {
1244 if b.len() < 4 {
1245 return Err(TlpError::InvalidLength);
1246 }
1247 let pasid = ((b[0] as u32 & 0x0F) << 16) | ((b[1] as u32) << 8) | (b[2] as u32);
1248 let fdwbe = b[3] & 0x0F;
1249 let ldwbe = (b[3] >> 4) & 0x0F;
1250 Ok(FlitOhcA {
1251 pasid,
1252 fdwbe,
1253 ldwbe,
1254 })
1255 }
1256}
1257
1258impl FlitDW0 {
1259 pub fn validate_mandatory_ohc(&self) -> Result<(), TlpError> {
1267 match self.tlp_type {
1268 FlitTlpType::IoWrite | FlitTlpType::CfgWrite0 => {
1269 if self.ohc & 0x01 == 0 {
1270 return Err(TlpError::MissingMandatoryOhc);
1271 }
1272 Ok(())
1273 }
1274 _ => Ok(()),
1275 }
1276 }
1277}
1278
1279pub struct FlitStreamWalker<'a> {
1300 data: &'a [u8],
1301 pos: usize,
1302 errored: bool,
1303}
1304
1305impl<'a> FlitStreamWalker<'a> {
1306 pub fn new(data: &'a [u8]) -> Self {
1308 FlitStreamWalker {
1309 data,
1310 pos: 0,
1311 errored: false,
1312 }
1313 }
1314}
1315
1316impl Iterator for FlitStreamWalker<'_> {
1317 type Item = Result<(usize, FlitTlpType, usize), TlpError>;
1318
1319 fn next(&mut self) -> Option<Self::Item> {
1320 if self.errored || self.pos >= self.data.len() {
1321 return None;
1322 }
1323 let offset = self.pos;
1324 let dw0 = match FlitDW0::from_dw0(&self.data[self.pos..]) {
1325 Ok(d) => d,
1326 Err(e) => {
1327 self.errored = true;
1328 return Some(Err(e));
1329 }
1330 };
1331 let total = dw0.total_bytes();
1332 if self.pos + total > self.data.len() {
1333 self.errored = true;
1334 return Some(Err(TlpError::InvalidLength));
1335 }
1336 self.pos += total;
1337 Some(Ok((offset, dw0.tlp_type, total)))
1338 }
1339}
1340
1341pub struct TlpPacketHeader {
1348 header: TlpHeader<Vec<u8>>,
1349}
1350
1351impl fmt::Debug for TlpPacketHeader {
1352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1353 f.debug_struct("TlpPacketHeader")
1354 .field("format", &self.get_format())
1355 .field("type", &self.get_type())
1356 .field("tc", &self.get_tc())
1357 .field("t9", &self.get_t9())
1358 .field("t8", &self.get_t8())
1359 .field("attr_b2", &self.get_attr_b2())
1360 .field("ln", &self.get_ln())
1361 .field("th", &self.get_th())
1362 .field("td", &self.get_td())
1363 .field("ep", &self.get_ep())
1364 .field("attr", &self.get_attr())
1365 .field("at", &self.get_at())
1366 .field("length", &self.get_length())
1367 .finish()
1368 }
1369}
1370
1371impl TlpPacketHeader {
1372 pub fn new(bytes: Vec<u8>, mode: TlpMode) -> Result<TlpPacketHeader, TlpError> {
1383 match mode {
1384 TlpMode::NonFlit => Self::new_non_flit(bytes),
1385 TlpMode::Flit => Err(TlpError::NotImplemented),
1386 }
1387 }
1388
1389 fn new_non_flit(bytes: Vec<u8>) -> Result<TlpPacketHeader, TlpError> {
1390 if bytes.len() < 4 {
1391 return Err(TlpError::InvalidLength);
1392 }
1393 let mut dw0 = vec![0; 4];
1394 dw0[..4].clone_from_slice(&bytes[0..4]);
1395
1396 Ok(TlpPacketHeader {
1397 header: TlpHeader(dw0),
1398 })
1399 }
1400
1401 pub fn tlp_type(&self) -> Result<TlpType, TlpError> {
1410 self.header.get_tlp_type()
1411 }
1412
1413 #[deprecated(since = "0.5.0", note = "use tlp_type() instead")]
1419 pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
1420 self.tlp_type()
1421 }
1422
1423 pub fn get_tc(&self) -> u32 {
1425 self.header.get_tc()
1426 }
1427
1428 pub(crate) fn get_format(&self) -> u32 {
1430 self.header.get_format()
1431 }
1432 pub(crate) fn get_type(&self) -> u32 {
1433 self.header.get_type()
1434 }
1435 pub(crate) fn get_t9(&self) -> u32 {
1436 self.header.get_t9()
1437 }
1438 pub(crate) fn get_t8(&self) -> u32 {
1439 self.header.get_t8()
1440 }
1441 pub(crate) fn get_attr_b2(&self) -> u32 {
1442 self.header.get_attr_b2()
1443 }
1444 pub(crate) fn get_ln(&self) -> u32 {
1445 self.header.get_ln()
1446 }
1447 pub(crate) fn get_th(&self) -> u32 {
1448 self.header.get_th()
1449 }
1450 pub(crate) fn get_td(&self) -> u32 {
1451 self.header.get_td()
1452 }
1453 pub(crate) fn get_ep(&self) -> u32 {
1454 self.header.get_ep()
1455 }
1456 pub(crate) fn get_attr(&self) -> u32 {
1457 self.header.get_attr()
1458 }
1459 pub(crate) fn get_at(&self) -> u32 {
1460 self.header.get_at()
1461 }
1462 pub(crate) fn get_length(&self) -> u32 {
1463 self.header.get_length()
1464 }
1465}
1466
1467pub struct TlpPacket {
1517 header: TlpPacketHeader,
1518 flit_dw0: Option<FlitDW0>,
1521 data: Vec<u8>,
1522}
1523
1524impl fmt::Debug for TlpPacket {
1525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1526 f.debug_struct("TlpPacket")
1527 .field("header", &self.header)
1528 .field("flit_dw0", &self.flit_dw0)
1529 .field("data_len", &self.data.len())
1530 .finish()
1531 }
1532}
1533
1534impl TlpPacket {
1535 pub fn new(bytes: Vec<u8>, mode: TlpMode) -> Result<TlpPacket, TlpError> {
1546 match mode {
1547 TlpMode::NonFlit => Self::new_non_flit(bytes),
1548 TlpMode::Flit => Self::new_flit(bytes),
1549 }
1550 }
1551
1552 fn new_non_flit(mut bytes: Vec<u8>) -> Result<TlpPacket, TlpError> {
1553 if bytes.len() < 4 {
1554 return Err(TlpError::InvalidLength);
1555 }
1556 let mut header = vec![0; 4];
1557 header.clone_from_slice(&bytes[0..4]);
1558 let data = bytes.drain(4..).collect();
1559 Ok(TlpPacket {
1560 header: TlpPacketHeader::new_non_flit(header)?,
1561 flit_dw0: None,
1562 data,
1563 })
1564 }
1565
1566 fn new_flit(bytes: Vec<u8>) -> Result<TlpPacket, TlpError> {
1567 if bytes.len() < 4 {
1568 return Err(TlpError::InvalidLength);
1569 }
1570 let dw0 = FlitDW0::from_dw0(&bytes)?;
1571 dw0.validate_mandatory_ohc()?;
1572
1573 let hdr_bytes = (dw0.tlp_type.base_header_dw() as usize + dw0.ohc_count() as usize) * 4;
1574 if bytes.len() < hdr_bytes {
1575 return Err(TlpError::InvalidLength);
1576 }
1577 let payload = bytes[hdr_bytes..].to_vec();
1578
1579 let dummy = TlpPacketHeader::new_non_flit(vec![0u8; 4])?;
1581 Ok(TlpPacket {
1582 header: dummy,
1583 flit_dw0: Some(dw0),
1584 data: payload,
1585 })
1586 }
1587
1588 pub fn header(&self) -> &TlpPacketHeader {
1598 &self.header
1599 }
1600
1601 pub fn data(&self) -> &[u8] {
1605 &self.data
1606 }
1607
1608 pub fn tlp_type(&self) -> Result<TlpType, TlpError> {
1619 if self.flit_dw0.is_some() {
1620 return Err(TlpError::NotImplemented);
1621 }
1622 self.header.tlp_type()
1623 }
1624
1625 pub fn tlp_format(&self) -> Result<TlpFmt, TlpError> {
1634 if self.flit_dw0.is_some() {
1635 return Err(TlpError::NotImplemented);
1636 }
1637 TlpFmt::try_from(self.header.get_format())
1638 }
1639
1640 pub fn flit_type(&self) -> Option<FlitTlpType> {
1643 self.flit_dw0.map(|d| d.tlp_type)
1644 }
1645
1646 pub fn mode(&self) -> TlpMode {
1665 if self.flit_dw0.is_some() {
1666 TlpMode::Flit
1667 } else {
1668 TlpMode::NonFlit
1669 }
1670 }
1671
1672 #[deprecated(since = "0.5.0", note = "use header() instead")]
1682 pub fn get_header(&self) -> &TlpPacketHeader {
1683 self.header()
1684 }
1685
1686 #[deprecated(since = "0.5.0", note = "use data() which returns &[u8] instead")]
1692 pub fn get_data(&self) -> Vec<u8> {
1693 self.data.clone()
1694 }
1695
1696 #[deprecated(since = "0.5.0", note = "use tlp_type() instead")]
1702 pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
1703 self.tlp_type()
1704 }
1705
1706 #[deprecated(since = "0.5.0", note = "use tlp_format() instead")]
1712 pub fn get_tlp_format(&self) -> Result<TlpFmt, TlpError> {
1713 self.tlp_format()
1714 }
1715
1716 #[deprecated(since = "0.5.0", note = "use flit_type() instead")]
1722 pub fn get_flit_type(&self) -> Option<FlitTlpType> {
1723 self.flit_type()
1724 }
1725}
1726
1727#[cfg(test)]
1728mod tests {
1729 use super::*;
1730
1731 #[test]
1732 fn tlp_header_type() {
1733 let memread = TlpHeader([0x0, 0x0, 0x0, 0x0]);
1735 assert_eq!(memread.get_tlp_type().unwrap(), TlpType::MemReadReq);
1736
1737 let memread32 = TlpHeader([0x00, 0x00, 0x20, 0x01]);
1739 assert_eq!(memread32.get_tlp_type().unwrap(), TlpType::MemReadReq);
1740
1741 let memwrite32 = TlpHeader([0x40, 0x00, 0x00, 0x01]);
1743 assert_eq!(memwrite32.get_tlp_type().unwrap(), TlpType::MemWriteReq);
1744
1745 let cpl_no_data = TlpHeader([0x0a, 0x00, 0x10, 0x00]);
1747 assert_eq!(cpl_no_data.get_tlp_type().unwrap(), TlpType::Cpl);
1748
1749 let cpl_with_data = TlpHeader([0x4a, 0x00, 0x20, 0x40]);
1751 assert_eq!(cpl_with_data.get_tlp_type().unwrap(), TlpType::CplData);
1752
1753 let memread_4dw = TlpHeader([0x20, 0x00, 0x20, 0x40]);
1755 assert_eq!(memread_4dw.get_tlp_type().unwrap(), TlpType::MemReadReq);
1756
1757 let conf_t0_read = TlpHeader([0x04, 0x00, 0x00, 0x01]);
1759 assert_eq!(
1760 conf_t0_read.get_tlp_type().unwrap(),
1761 TlpType::ConfType0ReadReq
1762 );
1763
1764 let conf_t0_write = TlpHeader([0x44, 0x00, 0x00, 0x01]);
1766 assert_eq!(
1767 conf_t0_write.get_tlp_type().unwrap(),
1768 TlpType::ConfType0WriteReq
1769 );
1770
1771 let conf_t1_read = TlpHeader([0x05, 0x88, 0x80, 0x01]);
1773 assert_eq!(
1774 conf_t1_read.get_tlp_type().unwrap(),
1775 TlpType::ConfType1ReadReq
1776 );
1777
1778 let conf_t1_write = TlpHeader([0x45, 0x88, 0x80, 0x01]);
1780 assert_eq!(
1781 conf_t1_write.get_tlp_type().unwrap(),
1782 TlpType::ConfType1WriteReq
1783 );
1784
1785 let memwrite64 = TlpHeader([0x60, 0x00, 0x90, 0x01]);
1788 assert_eq!(memwrite64.get_tlp_type().unwrap(), TlpType::MemWriteReq);
1789 }
1790
1791 #[test]
1792 fn tlp_header_works_all_zeros() {
1793 let bits_locations = TlpHeader([0x0, 0x0, 0x0, 0x0]);
1794
1795 assert_eq!(bits_locations.get_format(), 0);
1796 assert_eq!(bits_locations.get_type(), 0);
1797 assert_eq!(bits_locations.get_t9(), 0);
1798 assert_eq!(bits_locations.get_tc(), 0);
1799 assert_eq!(bits_locations.get_t8(), 0);
1800 assert_eq!(bits_locations.get_attr_b2(), 0);
1801 assert_eq!(bits_locations.get_ln(), 0);
1802 assert_eq!(bits_locations.get_th(), 0);
1803 assert_eq!(bits_locations.get_td(), 0);
1804 assert_eq!(bits_locations.get_ep(), 0);
1805 assert_eq!(bits_locations.get_attr(), 0);
1806 assert_eq!(bits_locations.get_at(), 0);
1807 assert_eq!(bits_locations.get_length(), 0);
1808 }
1809
1810 #[test]
1811 fn tlp_header_works_all_ones() {
1812 let bits_locations = TlpHeader([0xff, 0xff, 0xff, 0xff]);
1813
1814 assert_eq!(bits_locations.get_format(), 0x7);
1815 assert_eq!(bits_locations.get_type(), 0x1f);
1816 assert_eq!(bits_locations.get_t9(), 0x1);
1817 assert_eq!(bits_locations.get_tc(), 0x7);
1818 assert_eq!(bits_locations.get_t8(), 0x1);
1819 assert_eq!(bits_locations.get_attr_b2(), 0x1);
1820 assert_eq!(bits_locations.get_ln(), 0x1);
1821 assert_eq!(bits_locations.get_th(), 0x1);
1822 assert_eq!(bits_locations.get_td(), 0x1);
1823 assert_eq!(bits_locations.get_ep(), 0x1);
1824 assert_eq!(bits_locations.get_attr(), 0x3);
1825 assert_eq!(bits_locations.get_at(), 0x3);
1826 assert_eq!(bits_locations.get_length(), 0x3ff);
1827 }
1828
1829 #[test]
1830 fn test_invalid_format_error() {
1831 let invalid_fmt_101 = TlpHeader([0xa0, 0x00, 0x00, 0x01]);
1835 assert_eq!(
1836 invalid_fmt_101.get_tlp_type().unwrap_err(),
1837 TlpError::InvalidFormat
1838 );
1839
1840 let invalid_fmt_110 = TlpHeader([0xc0, 0x00, 0x00, 0x01]);
1842 assert_eq!(
1843 invalid_fmt_110.get_tlp_type().unwrap_err(),
1844 TlpError::InvalidFormat
1845 );
1846
1847 let invalid_fmt_111 = TlpHeader([0xe0, 0x00, 0x00, 0x01]);
1849 assert_eq!(
1850 invalid_fmt_111.get_tlp_type().unwrap_err(),
1851 TlpError::InvalidFormat
1852 );
1853 }
1854
1855 #[test]
1856 fn test_invalid_type_error() {
1857 let invalid_type = TlpHeader([0x0f, 0x00, 0x00, 0x01]); let result = invalid_type.get_tlp_type();
1860 assert!(result.is_err());
1861 assert_eq!(result.unwrap_err(), TlpError::InvalidType);
1862 }
1863
1864 #[test]
1865 fn test_unsupported_combination_error() {
1866 let invalid_combo = TlpHeader([0x22, 0x00, 0x00, 0x01]); let result = invalid_combo.get_tlp_type();
1870 assert!(result.is_err());
1871 assert_eq!(result.unwrap_err(), TlpError::UnsupportedCombination);
1872 }
1873
1874 #[test]
1877 fn mem_req_rejects_tlp_prefix() {
1878 let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1879 let result = new_mem_req(bytes, &TlpFmt::TlpPrefix);
1880 assert!(matches!(result, Err(TlpError::UnsupportedCombination)));
1881 }
1882
1883 #[test]
1886 fn packet_new_rejects_empty_input() {
1887 assert!(matches!(
1888 TlpPacket::new(vec![], TlpMode::NonFlit),
1889 Err(TlpError::InvalidLength)
1890 ));
1891 }
1892
1893 #[test]
1894 fn packet_new_rejects_3_bytes() {
1895 assert!(matches!(
1896 TlpPacket::new(vec![0x00, 0x00, 0x00], TlpMode::NonFlit),
1897 Err(TlpError::InvalidLength)
1898 ));
1899 }
1900
1901 #[test]
1902 fn packet_new_accepts_4_bytes() {
1903 assert!(TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::NonFlit).is_ok());
1905 }
1906
1907 #[test]
1908 fn packet_header_new_rejects_short_input() {
1909 assert!(matches!(
1910 TlpPacketHeader::new(vec![0x00, 0x00], TlpMode::NonFlit),
1911 Err(TlpError::InvalidLength)
1912 ));
1913 }
1914
1915 #[test]
1918 fn packet_new_flit_succeeds_for_valid_nop() {
1919 let bytes = vec![0x00, 0x00, 0x00, 0x00];
1921 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
1922 assert_eq!(pkt.flit_type(), Some(FlitTlpType::Nop));
1923 assert!(pkt.data().is_empty());
1924 }
1925
1926 #[test]
1927 fn packet_new_flit_mrd32_has_no_payload() {
1928 let bytes = vec![
1930 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1931 ];
1932 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
1933 assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemRead32));
1934 assert!(pkt.data().is_empty()); }
1936
1937 #[test]
1938 fn packet_new_flit_mwr32_has_payload() {
1939 let bytes = vec![
1941 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, ];
1946 let pkt = TlpPacket::new(bytes, TlpMode::Flit).unwrap();
1947 assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemWrite32));
1948 assert_eq!(pkt.data(), [0xDE, 0xAD, 0xBE, 0xEF]);
1949 }
1950
1951 #[test]
1952 fn packet_new_flit_nonflit_returns_none_for_flit_type() {
1953 let pkt = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::NonFlit).unwrap();
1955 assert_eq!(pkt.flit_type(), None);
1956 }
1957
1958 #[test]
1959 fn packet_header_new_flit_returns_not_implemented() {
1960 let bytes = vec![0x00, 0x00, 0x00, 0x00];
1962 assert_eq!(
1963 TlpPacketHeader::new(bytes, TlpMode::Flit).err().unwrap(),
1964 TlpError::NotImplemented
1965 );
1966 }
1967
1968 #[test]
1971 fn tlp_mode_debug_and_partialeq() {
1972 assert_eq!(TlpMode::NonFlit, TlpMode::NonFlit);
1973 assert_ne!(TlpMode::NonFlit, TlpMode::Flit);
1974 let s = format!("{:?}", TlpMode::NonFlit);
1975 assert!(s.contains("NonFlit"));
1976 let s2 = format!("{:?}", TlpMode::Flit);
1977 assert!(s2.contains("Flit"));
1978 }
1979
1980 #[test]
1981 #[allow(clippy::clone_on_copy)]
1982 fn tlp_mode_copy_and_clone() {
1983 let m = TlpMode::NonFlit;
1984 let m2 = m; let m3 = m.clone(); assert_eq!(m2, TlpMode::NonFlit);
1987 assert_eq!(m3, TlpMode::NonFlit);
1988 }
1989
1990 #[test]
1993 fn not_implemented_error_is_distinct() {
1994 let e = TlpError::NotImplemented;
1995 assert_ne!(e, TlpError::InvalidFormat);
1996 assert_ne!(e, TlpError::InvalidType);
1997 assert_ne!(e, TlpError::UnsupportedCombination);
1998 assert_ne!(e, TlpError::InvalidLength);
1999 assert_eq!(e, TlpError::NotImplemented);
2000 let s = format!("{:?}", e);
2001 assert!(s.contains("NotImplemented"));
2002 }
2003
2004 fn dw0(fmt: u8, typ: u8) -> TlpHeader<[u8; 4]> {
2009 TlpHeader([(fmt << 5) | (typ & 0x1f), 0x00, 0x00, 0x00])
2010 }
2011
2012 fn mk_tlp(fmt: u8, typ: u8, rest: &[u8]) -> Vec<u8> {
2015 let mut v = Vec::with_capacity(4 + rest.len());
2016 v.push((fmt << 5) | (typ & 0x1f));
2017 v.push(0x00); v.push(0x00); v.push(0x00); v.extend_from_slice(rest);
2021 v
2022 }
2023
2024 #[test]
2027 fn header_decode_supported_pairs() {
2028 const FMT_3DW_NO_DATA: u8 = 0b000;
2029 const FMT_4DW_NO_DATA: u8 = 0b001;
2030 const FMT_3DW_WITH_DATA: u8 = 0b010;
2031 const FMT_4DW_WITH_DATA: u8 = 0b011;
2032
2033 const TY_MEM: u8 = 0b00000;
2034 const TY_MEM_LK: u8 = 0b00001;
2035 const TY_IO: u8 = 0b00010;
2036 const TY_CFG0: u8 = 0b00100;
2037 const TY_CFG1: u8 = 0b00101;
2038 const TY_CPL: u8 = 0b01010;
2039 const TY_CPL_LK: u8 = 0b01011;
2040 const TY_ATOM_FETCH: u8 = 0b01100;
2041 const TY_ATOM_SWAP: u8 = 0b01101;
2042 const TY_ATOM_CAS: u8 = 0b01110;
2043 const TY_DMWR: u8 = 0b11011;
2044
2045 assert_eq!(
2047 dw0(FMT_3DW_NO_DATA, TY_MEM).get_tlp_type().unwrap(),
2048 TlpType::MemReadReq
2049 );
2050 assert_eq!(
2051 dw0(FMT_4DW_NO_DATA, TY_MEM).get_tlp_type().unwrap(),
2052 TlpType::MemReadReq
2053 );
2054 assert_eq!(
2055 dw0(FMT_3DW_WITH_DATA, TY_MEM).get_tlp_type().unwrap(),
2056 TlpType::MemWriteReq
2057 );
2058 assert_eq!(
2059 dw0(FMT_4DW_WITH_DATA, TY_MEM).get_tlp_type().unwrap(),
2060 TlpType::MemWriteReq
2061 );
2062
2063 assert_eq!(
2065 dw0(FMT_3DW_NO_DATA, TY_MEM_LK).get_tlp_type().unwrap(),
2066 TlpType::MemReadLockReq
2067 );
2068 assert_eq!(
2069 dw0(FMT_4DW_NO_DATA, TY_MEM_LK).get_tlp_type().unwrap(),
2070 TlpType::MemReadLockReq
2071 );
2072
2073 assert_eq!(
2075 dw0(FMT_3DW_NO_DATA, TY_IO).get_tlp_type().unwrap(),
2076 TlpType::IOReadReq
2077 );
2078 assert_eq!(
2079 dw0(FMT_3DW_WITH_DATA, TY_IO).get_tlp_type().unwrap(),
2080 TlpType::IOWriteReq
2081 );
2082
2083 assert_eq!(
2085 dw0(FMT_3DW_NO_DATA, TY_CFG0).get_tlp_type().unwrap(),
2086 TlpType::ConfType0ReadReq
2087 );
2088 assert_eq!(
2089 dw0(FMT_3DW_WITH_DATA, TY_CFG0).get_tlp_type().unwrap(),
2090 TlpType::ConfType0WriteReq
2091 );
2092
2093 assert_eq!(
2095 dw0(FMT_3DW_NO_DATA, TY_CFG1).get_tlp_type().unwrap(),
2096 TlpType::ConfType1ReadReq
2097 );
2098 assert_eq!(
2099 dw0(FMT_3DW_WITH_DATA, TY_CFG1).get_tlp_type().unwrap(),
2100 TlpType::ConfType1WriteReq
2101 );
2102
2103 assert_eq!(
2105 dw0(FMT_3DW_NO_DATA, TY_CPL).get_tlp_type().unwrap(),
2106 TlpType::Cpl
2107 );
2108 assert_eq!(
2109 dw0(FMT_3DW_WITH_DATA, TY_CPL).get_tlp_type().unwrap(),
2110 TlpType::CplData
2111 );
2112
2113 assert_eq!(
2115 dw0(FMT_3DW_NO_DATA, TY_CPL_LK).get_tlp_type().unwrap(),
2116 TlpType::CplLocked
2117 );
2118 assert_eq!(
2119 dw0(FMT_3DW_WITH_DATA, TY_CPL_LK).get_tlp_type().unwrap(),
2120 TlpType::CplDataLocked
2121 );
2122
2123 assert_eq!(
2125 dw0(FMT_3DW_WITH_DATA, TY_ATOM_FETCH)
2126 .get_tlp_type()
2127 .unwrap(),
2128 TlpType::FetchAddAtomicOpReq
2129 );
2130 assert_eq!(
2131 dw0(FMT_4DW_WITH_DATA, TY_ATOM_FETCH)
2132 .get_tlp_type()
2133 .unwrap(),
2134 TlpType::FetchAddAtomicOpReq
2135 );
2136
2137 assert_eq!(
2138 dw0(FMT_3DW_WITH_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap(),
2139 TlpType::SwapAtomicOpReq
2140 );
2141 assert_eq!(
2142 dw0(FMT_4DW_WITH_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap(),
2143 TlpType::SwapAtomicOpReq
2144 );
2145
2146 assert_eq!(
2147 dw0(FMT_3DW_WITH_DATA, TY_ATOM_CAS).get_tlp_type().unwrap(),
2148 TlpType::CompareSwapAtomicOpReq
2149 );
2150 assert_eq!(
2151 dw0(FMT_4DW_WITH_DATA, TY_ATOM_CAS).get_tlp_type().unwrap(),
2152 TlpType::CompareSwapAtomicOpReq
2153 );
2154
2155 assert_eq!(
2157 dw0(FMT_3DW_WITH_DATA, TY_DMWR).get_tlp_type().unwrap(),
2158 TlpType::DeferrableMemWriteReq
2159 );
2160 assert_eq!(
2161 dw0(FMT_4DW_WITH_DATA, TY_DMWR).get_tlp_type().unwrap(),
2162 TlpType::DeferrableMemWriteReq
2163 );
2164
2165 for routing in 0b10000u8..=0b10101u8 {
2169 assert_eq!(
2170 dw0(FMT_3DW_NO_DATA, routing).get_tlp_type().unwrap(),
2171 TlpType::MsgReq,
2172 "Fmt=000 Type={:#07b} should be MsgReq",
2173 routing
2174 );
2175 assert_eq!(
2176 dw0(FMT_4DW_NO_DATA, routing).get_tlp_type().unwrap(),
2177 TlpType::MsgReq,
2178 "Fmt=001 Type={:#07b} should be MsgReq",
2179 routing
2180 );
2181 assert_eq!(
2182 dw0(FMT_3DW_WITH_DATA, routing).get_tlp_type().unwrap(),
2183 TlpType::MsgReqData,
2184 "Fmt=010 Type={:#07b} should be MsgReqData",
2185 routing
2186 );
2187 assert_eq!(
2188 dw0(FMT_4DW_WITH_DATA, routing).get_tlp_type().unwrap(),
2189 TlpType::MsgReqData,
2190 "Fmt=011 Type={:#07b} should be MsgReqData",
2191 routing
2192 );
2193 }
2194 }
2195
2196 #[test]
2199 fn header_decode_rejects_unsupported_combinations() {
2200 const FMT_3DW_NO_DATA: u8 = 0b000;
2201 const FMT_4DW_NO_DATA: u8 = 0b001;
2202 const FMT_3DW_WITH_DATA: u8 = 0b010;
2203 const FMT_4DW_WITH_DATA: u8 = 0b011;
2204
2205 const TY_MEM_LK: u8 = 0b00001;
2206 const TY_IO: u8 = 0b00010;
2207 const TY_CFG0: u8 = 0b00100;
2208 const TY_CFG1: u8 = 0b00101;
2209 const TY_CPL: u8 = 0b01010;
2210 const TY_CPL_LK: u8 = 0b01011;
2211 const TY_ATOM_FETCH: u8 = 0b01100;
2212 const TY_ATOM_SWAP: u8 = 0b01101;
2213 const TY_ATOM_CAS: u8 = 0b01110;
2214 const TY_DMWR: u8 = 0b11011;
2215
2216 assert_eq!(
2218 dw0(FMT_4DW_NO_DATA, TY_IO).get_tlp_type().unwrap_err(),
2219 TlpError::UnsupportedCombination
2220 );
2221 assert_eq!(
2222 dw0(FMT_4DW_WITH_DATA, TY_IO).get_tlp_type().unwrap_err(),
2223 TlpError::UnsupportedCombination
2224 );
2225
2226 assert_eq!(
2228 dw0(FMT_4DW_NO_DATA, TY_CFG0).get_tlp_type().unwrap_err(),
2229 TlpError::UnsupportedCombination
2230 );
2231 assert_eq!(
2232 dw0(FMT_4DW_WITH_DATA, TY_CFG0).get_tlp_type().unwrap_err(),
2233 TlpError::UnsupportedCombination
2234 );
2235 assert_eq!(
2236 dw0(FMT_4DW_NO_DATA, TY_CFG1).get_tlp_type().unwrap_err(),
2237 TlpError::UnsupportedCombination
2238 );
2239 assert_eq!(
2240 dw0(FMT_4DW_WITH_DATA, TY_CFG1).get_tlp_type().unwrap_err(),
2241 TlpError::UnsupportedCombination
2242 );
2243
2244 assert_eq!(
2246 dw0(FMT_4DW_NO_DATA, TY_CPL).get_tlp_type().unwrap_err(),
2247 TlpError::UnsupportedCombination
2248 );
2249 assert_eq!(
2250 dw0(FMT_4DW_WITH_DATA, TY_CPL).get_tlp_type().unwrap_err(),
2251 TlpError::UnsupportedCombination
2252 );
2253 assert_eq!(
2254 dw0(FMT_4DW_NO_DATA, TY_CPL_LK).get_tlp_type().unwrap_err(),
2255 TlpError::UnsupportedCombination
2256 );
2257 assert_eq!(
2258 dw0(FMT_4DW_WITH_DATA, TY_CPL_LK)
2259 .get_tlp_type()
2260 .unwrap_err(),
2261 TlpError::UnsupportedCombination
2262 );
2263
2264 assert_eq!(
2266 dw0(FMT_3DW_NO_DATA, TY_ATOM_FETCH)
2267 .get_tlp_type()
2268 .unwrap_err(),
2269 TlpError::UnsupportedCombination
2270 );
2271 assert_eq!(
2272 dw0(FMT_4DW_NO_DATA, TY_ATOM_FETCH)
2273 .get_tlp_type()
2274 .unwrap_err(),
2275 TlpError::UnsupportedCombination
2276 );
2277 assert_eq!(
2278 dw0(FMT_3DW_NO_DATA, TY_ATOM_SWAP)
2279 .get_tlp_type()
2280 .unwrap_err(),
2281 TlpError::UnsupportedCombination
2282 );
2283 assert_eq!(
2284 dw0(FMT_4DW_NO_DATA, TY_ATOM_SWAP)
2285 .get_tlp_type()
2286 .unwrap_err(),
2287 TlpError::UnsupportedCombination
2288 );
2289 assert_eq!(
2290 dw0(FMT_3DW_NO_DATA, TY_ATOM_CAS)
2291 .get_tlp_type()
2292 .unwrap_err(),
2293 TlpError::UnsupportedCombination
2294 );
2295 assert_eq!(
2296 dw0(FMT_4DW_NO_DATA, TY_ATOM_CAS)
2297 .get_tlp_type()
2298 .unwrap_err(),
2299 TlpError::UnsupportedCombination
2300 );
2301
2302 assert_eq!(
2304 dw0(FMT_3DW_WITH_DATA, TY_MEM_LK)
2305 .get_tlp_type()
2306 .unwrap_err(),
2307 TlpError::UnsupportedCombination
2308 );
2309 assert_eq!(
2310 dw0(FMT_4DW_WITH_DATA, TY_MEM_LK)
2311 .get_tlp_type()
2312 .unwrap_err(),
2313 TlpError::UnsupportedCombination
2314 );
2315
2316 assert_eq!(
2321 dw0(FMT_3DW_NO_DATA, TY_DMWR).get_tlp_type().unwrap_err(),
2322 TlpError::UnsupportedCombination
2323 );
2324 assert_eq!(
2325 dw0(FMT_4DW_NO_DATA, TY_DMWR).get_tlp_type().unwrap_err(),
2326 TlpError::UnsupportedCombination
2327 );
2328 }
2330
2331 #[test]
2334 fn tlp_header_dmwr32_decode() {
2335 let dmwr32 = TlpHeader([0x5B, 0x00, 0x00, 0x00]);
2337 assert_eq!(
2338 dmwr32.get_tlp_type().unwrap(),
2339 TlpType::DeferrableMemWriteReq
2340 );
2341 }
2342
2343 #[test]
2344 fn tlp_header_dmwr64_decode() {
2345 let dmwr64 = TlpHeader([0x7B, 0x00, 0x00, 0x00]);
2347 assert_eq!(
2348 dmwr64.get_tlp_type().unwrap(),
2349 TlpType::DeferrableMemWriteReq
2350 );
2351 }
2352
2353 #[test]
2354 fn tlp_header_dmwr_rejects_nodata_formats() {
2355 let dmwr_bad_3dw_nodata = TlpHeader([0x1B, 0x00, 0x00, 0x00]);
2357 assert_eq!(
2358 dmwr_bad_3dw_nodata.get_tlp_type().unwrap_err(),
2359 TlpError::UnsupportedCombination
2360 );
2361
2362 let dmwr_bad_4dw_nodata = TlpHeader([0x3B, 0x00, 0x00, 0x00]);
2364 assert_eq!(
2365 dmwr_bad_4dw_nodata.get_tlp_type().unwrap_err(),
2366 TlpError::UnsupportedCombination
2367 );
2368 }
2369
2370 #[test]
2371 fn dmwr_full_packet_3dw_fields() {
2372 let payload = [
2374 0xAB, 0xCD, 0x42, 0x0F, 0xDE, 0xAD, 0x00, 0x00, ];
2377 let pkt = TlpPacket::new(mk_tlp(0b010, 0b11011, &payload), TlpMode::NonFlit).unwrap();
2378 assert_eq!(pkt.tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
2379 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader3DW);
2380
2381 let mr = new_mem_req(pkt.data().to_vec(), &pkt.tlp_format().unwrap()).unwrap();
2382 assert_eq!(mr.req_id(), 0xABCD);
2383 assert_eq!(mr.tag(), 0x42);
2384 assert_eq!(mr.address(), 0xDEAD_0000);
2385 }
2386
2387 #[test]
2388 fn dmwr_full_packet_4dw_fields() {
2389 let payload = [
2391 0xBE, 0xEF, 0xA5, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, ];
2395 let pkt = TlpPacket::new(mk_tlp(0b011, 0b11011, &payload), TlpMode::NonFlit).unwrap();
2396 assert_eq!(pkt.tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
2397 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader4DW);
2398
2399 let mr = new_mem_req(pkt.data().to_vec(), &pkt.tlp_format().unwrap()).unwrap();
2400 assert_eq!(mr.req_id(), 0xBEEF);
2401 assert_eq!(mr.tag(), 0xA5);
2402 assert_eq!(mr.address(), 0x1122_3344_5566_7788);
2403 }
2404
2405 #[test]
2408 fn is_non_posted_returns_true_for_non_posted_types() {
2409 assert!(TlpType::MemReadReq.is_non_posted());
2410 assert!(TlpType::MemReadLockReq.is_non_posted());
2411 assert!(TlpType::IOReadReq.is_non_posted());
2412 assert!(TlpType::IOWriteReq.is_non_posted());
2413 assert!(TlpType::ConfType0ReadReq.is_non_posted());
2414 assert!(TlpType::ConfType0WriteReq.is_non_posted());
2415 assert!(TlpType::ConfType1ReadReq.is_non_posted());
2416 assert!(TlpType::ConfType1WriteReq.is_non_posted());
2417 assert!(TlpType::FetchAddAtomicOpReq.is_non_posted());
2418 assert!(TlpType::SwapAtomicOpReq.is_non_posted());
2419 assert!(TlpType::CompareSwapAtomicOpReq.is_non_posted());
2420 assert!(TlpType::DeferrableMemWriteReq.is_non_posted());
2421 }
2422
2423 #[test]
2424 fn is_non_posted_returns_false_for_posted_types() {
2425 assert!(!TlpType::MemWriteReq.is_non_posted());
2426 assert!(!TlpType::MsgReq.is_non_posted());
2427 assert!(!TlpType::MsgReqData.is_non_posted());
2428 }
2429
2430 #[test]
2431 fn is_non_posted_returns_false_for_completions() {
2432 assert!(!TlpType::Cpl.is_non_posted());
2434 assert!(!TlpType::CplData.is_non_posted());
2435 assert!(!TlpType::CplLocked.is_non_posted());
2436 assert!(!TlpType::CplDataLocked.is_non_posted());
2437 }
2438
2439 #[test]
2442 fn is_non_posted_exhaustive_all_21_variants() {
2443 assert!(
2445 TlpType::MemReadReq.is_non_posted(),
2446 "MemReadReq must be non-posted"
2447 );
2448 assert!(
2449 TlpType::MemReadLockReq.is_non_posted(),
2450 "MemReadLockReq must be non-posted"
2451 );
2452 assert!(
2453 TlpType::IOReadReq.is_non_posted(),
2454 "IOReadReq must be non-posted"
2455 );
2456 assert!(
2457 TlpType::IOWriteReq.is_non_posted(),
2458 "IOWriteReq must be non-posted"
2459 );
2460 assert!(
2461 TlpType::ConfType0ReadReq.is_non_posted(),
2462 "ConfType0ReadReq must be non-posted"
2463 );
2464 assert!(
2465 TlpType::ConfType0WriteReq.is_non_posted(),
2466 "ConfType0WriteReq must be non-posted"
2467 );
2468 assert!(
2469 TlpType::ConfType1ReadReq.is_non_posted(),
2470 "ConfType1ReadReq must be non-posted"
2471 );
2472 assert!(
2473 TlpType::ConfType1WriteReq.is_non_posted(),
2474 "ConfType1WriteReq must be non-posted"
2475 );
2476 assert!(
2477 TlpType::FetchAddAtomicOpReq.is_non_posted(),
2478 "FetchAddAtomicOpReq must be non-posted"
2479 );
2480 assert!(
2481 TlpType::SwapAtomicOpReq.is_non_posted(),
2482 "SwapAtomicOpReq must be non-posted"
2483 );
2484 assert!(
2485 TlpType::CompareSwapAtomicOpReq.is_non_posted(),
2486 "CompareSwapAtomicOpReq must be non-posted"
2487 );
2488 assert!(
2489 TlpType::DeferrableMemWriteReq.is_non_posted(),
2490 "DeferrableMemWriteReq must be non-posted"
2491 );
2492
2493 assert!(
2495 !TlpType::MemWriteReq.is_non_posted(),
2496 "MemWriteReq is posted"
2497 );
2498 assert!(!TlpType::MsgReq.is_non_posted(), "MsgReq is posted");
2499 assert!(!TlpType::MsgReqData.is_non_posted(), "MsgReqData is posted");
2500
2501 assert!(
2503 !TlpType::Cpl.is_non_posted(),
2504 "Cpl is a response, not a request"
2505 );
2506 assert!(
2507 !TlpType::CplData.is_non_posted(),
2508 "CplData is a response, not a request"
2509 );
2510 assert!(
2511 !TlpType::CplLocked.is_non_posted(),
2512 "CplLocked is a response, not a request"
2513 );
2514 assert!(
2515 !TlpType::CplDataLocked.is_non_posted(),
2516 "CplDataLocked is a response, not a request"
2517 );
2518
2519 assert!(
2521 !TlpType::LocalTlpPrefix.is_non_posted(),
2522 "LocalTlpPrefix is not a transaction"
2523 );
2524 assert!(
2525 !TlpType::EndToEndTlpPrefix.is_non_posted(),
2526 "EndToEndTlpPrefix is not a transaction"
2527 );
2528 }
2529
2530 #[test]
2533 fn atomic_fetchadd_3dw_type_and_fields() {
2534 const FMT_3DW_WITH_DATA: u8 = 0b010;
2535 const TY_ATOM_FETCH: u8 = 0b01100;
2536
2537 let payload = [
2544 0x12, 0x34, 0x56, 0x00, 0x89, 0xAB, 0xCD, 0xEF, ];
2548
2549 let pkt = TlpPacket::new(
2550 mk_tlp(FMT_3DW_WITH_DATA, TY_ATOM_FETCH, &payload),
2551 TlpMode::NonFlit,
2552 )
2553 .unwrap();
2554
2555 assert_eq!(pkt.tlp_type().unwrap(), TlpType::FetchAddAtomicOpReq);
2556 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader3DW);
2557
2558 let fmt = pkt.tlp_format().unwrap();
2559 let mr = new_mem_req(pkt.data().to_vec(), &fmt).unwrap();
2560 assert_eq!(mr.req_id(), 0x1234);
2561 assert_eq!(mr.tag(), 0x56);
2562 assert_eq!(mr.address(), 0x89AB_CDEF);
2563 }
2564
2565 #[test]
2566 fn atomic_cas_4dw_type_and_fields() {
2567 const FMT_4DW_WITH_DATA: u8 = 0b011;
2568 const TY_ATOM_CAS: u8 = 0b01110;
2569
2570 let payload = [
2576 0xBE, 0xEF, 0xA5, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, ];
2581
2582 let pkt = TlpPacket::new(
2583 mk_tlp(FMT_4DW_WITH_DATA, TY_ATOM_CAS, &payload),
2584 TlpMode::NonFlit,
2585 )
2586 .unwrap();
2587
2588 assert_eq!(pkt.tlp_type().unwrap(), TlpType::CompareSwapAtomicOpReq);
2589 assert_eq!(pkt.tlp_format().unwrap(), TlpFmt::WithDataHeader4DW);
2590
2591 let fmt = pkt.tlp_format().unwrap();
2592 let mr = new_mem_req(pkt.data().to_vec(), &fmt).unwrap();
2593 assert_eq!(mr.req_id(), 0xBEEF);
2594 assert_eq!(mr.tag(), 0xA5);
2595 assert_eq!(mr.address(), 0x1122_3344_5566_7788);
2596 }
2597
2598 #[test]
2601 fn fetchadd_3dw_operand() {
2602 let payload = [
2607 0xDE, 0xAD, 0x42, 0x00, 0xC0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, ];
2611 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &payload), TlpMode::NonFlit).unwrap();
2612 let ar = new_atomic_req(&pkt).unwrap();
2613
2614 assert_eq!(ar.op(), AtomicOp::FetchAdd);
2615 assert_eq!(ar.width(), AtomicWidth::W32);
2616 assert_eq!(ar.req_id(), 0xDEAD);
2617 assert_eq!(ar.tag(), 0x42);
2618 assert_eq!(ar.address(), 0xC001_0004);
2619 assert_eq!(ar.operand0(), 0x0A);
2620 assert!(ar.operand1().is_none());
2621 }
2622
2623 #[test]
2624 fn fetchadd_4dw_operand() {
2625 let payload = [
2630 0x00, 0x42, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
2634 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01100, &payload), TlpMode::NonFlit).unwrap();
2635 let ar = new_atomic_req(&pkt).unwrap();
2636
2637 assert_eq!(ar.op(), AtomicOp::FetchAdd);
2638 assert_eq!(ar.width(), AtomicWidth::W64);
2639 assert_eq!(ar.req_id(), 0x0042);
2640 assert_eq!(ar.tag(), 0xBB);
2641 assert_eq!(ar.address(), 0x0000_0001_0000_0000);
2642 assert_eq!(ar.operand0(), 0xFFFF_FFFF_FFFF_FFFF);
2643 assert!(ar.operand1().is_none());
2644 }
2645
2646 #[test]
2647 fn swap_3dw_operand() {
2648 let payload = [
2653 0x11, 0x11, 0x05, 0x00, 0xF0, 0x00, 0x00, 0x08, 0xAB, 0xCD, 0xEF, 0x01, ];
2657 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01101, &payload), TlpMode::NonFlit).unwrap();
2658 let ar = new_atomic_req(&pkt).unwrap();
2659
2660 assert_eq!(ar.op(), AtomicOp::Swap);
2661 assert_eq!(ar.width(), AtomicWidth::W32);
2662 assert_eq!(ar.req_id(), 0x1111);
2663 assert_eq!(ar.tag(), 0x05);
2664 assert_eq!(ar.address(), 0xF000_0008);
2665 assert_eq!(ar.operand0(), 0xABCD_EF01);
2666 assert!(ar.operand1().is_none());
2667 }
2668
2669 #[test]
2670 fn cas_3dw_two_operands() {
2671 let payload = [
2677 0xAB, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, ];
2682 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01110, &payload), TlpMode::NonFlit).unwrap();
2683 let ar = new_atomic_req(&pkt).unwrap();
2684
2685 assert_eq!(ar.op(), AtomicOp::CompareSwap);
2686 assert_eq!(ar.width(), AtomicWidth::W32);
2687 assert_eq!(ar.req_id(), 0xABCD);
2688 assert_eq!(ar.tag(), 0x07);
2689 assert_eq!(ar.address(), 0x0000_4000);
2690 assert_eq!(ar.operand0(), 0xCAFE_BABE);
2691 assert_eq!(ar.operand1(), Some(0xDEAD_BEEF));
2692 }
2693
2694 #[test]
2695 fn cas_4dw_two_operands() {
2696 let payload = [
2702 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, ];
2707 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01110, &payload), TlpMode::NonFlit).unwrap();
2708 let ar = new_atomic_req(&pkt).unwrap();
2709
2710 assert_eq!(ar.op(), AtomicOp::CompareSwap);
2711 assert_eq!(ar.width(), AtomicWidth::W64);
2712 assert_eq!(ar.req_id(), 0x1234);
2713 assert_eq!(ar.tag(), 0xAA);
2714 assert_eq!(ar.address(), 0xFFFF_FFFF_0000_0000);
2715 assert_eq!(ar.operand0(), 0x0101_0101_0202_0202);
2716 assert_eq!(ar.operand1(), Some(0x0303_0303_0404_0404));
2717 }
2718
2719 #[test]
2720 fn atomic_req_rejects_wrong_tlp_type() {
2721 let pkt = TlpPacket::new(mk_tlp(0b000, 0b00000, &[0u8; 16]), TlpMode::NonFlit).unwrap();
2723 assert_eq!(
2724 new_atomic_req(&pkt).err().unwrap(),
2725 TlpError::UnsupportedCombination
2726 );
2727 }
2728
2729 #[test]
2730 fn atomic_req_rejects_wrong_format() {
2731 let pkt = TlpPacket::new(mk_tlp(0b000, 0b01100, &[0u8; 16]), TlpMode::NonFlit).unwrap();
2734 assert_eq!(
2735 new_atomic_req(&pkt).err().unwrap(),
2736 TlpError::UnsupportedCombination
2737 );
2738 }
2739
2740 #[test]
2741 fn atomic_req_rejects_short_payload() {
2742 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &[0u8; 3]), TlpMode::NonFlit).unwrap();
2744 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
2745
2746 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &[0u8; 8]), TlpMode::NonFlit).unwrap();
2748 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
2749
2750 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01110, &[0u8; 20]), TlpMode::NonFlit).unwrap();
2752 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
2753 }
2754
2755 fn mk_pkt(fmt: u8, typ: u8, data: &[u8]) -> TlpPacket {
2758 TlpPacket::new(mk_tlp(fmt, typ, data), TlpMode::NonFlit).unwrap()
2759 }
2760
2761 #[test]
2764 fn atomic_fetchadd_3dw_32_parses_operands() {
2765 let data = [
2767 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x07, ];
2771 let pkt = mk_pkt(0b010, 0b01100, &data);
2772 let a = new_atomic_req(&pkt).unwrap();
2773 assert_eq!(a.op(), AtomicOp::FetchAdd);
2774 assert_eq!(a.width(), AtomicWidth::W32);
2775 assert_eq!(a.req_id(), 0x0100);
2776 assert_eq!(a.tag(), 0x01);
2777 assert_eq!(a.address(), 0x0000_1000);
2778 assert_eq!(a.operand0(), 7);
2779 assert!(a.operand1().is_none());
2780 }
2781
2782 #[test]
2783 fn atomic_swap_4dw_64_parses_operands() {
2784 let data = [
2786 0xBE, 0xEF, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, ];
2790 let pkt = mk_pkt(0b011, 0b01101, &data);
2791 let a = new_atomic_req(&pkt).unwrap();
2792 assert_eq!(a.op(), AtomicOp::Swap);
2793 assert_eq!(a.width(), AtomicWidth::W64);
2794 assert_eq!(a.req_id(), 0xBEEF);
2795 assert_eq!(a.tag(), 0xA5);
2796 assert_eq!(a.address(), 0x0000_0001_0000_0000);
2797 assert_eq!(a.operand0(), 0xDEAD_BEEF_CAFE_BABE);
2798 assert!(a.operand1().is_none());
2799 }
2800
2801 #[test]
2802 fn atomic_cas_3dw_32_parses_operands() {
2803 let data = [
2805 0xAB, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, ];
2810 let pkt = mk_pkt(0b010, 0b01110, &data);
2811 let a = new_atomic_req(&pkt).unwrap();
2812 assert_eq!(a.op(), AtomicOp::CompareSwap);
2813 assert_eq!(a.width(), AtomicWidth::W32);
2814 assert_eq!(a.req_id(), 0xABCD);
2815 assert_eq!(a.tag(), 0x07);
2816 assert_eq!(a.address(), 0x0000_4000);
2817 assert_eq!(a.operand0(), 0xCAFE_BABE);
2818 assert_eq!(a.operand1(), Some(0xDEAD_BEEF));
2819 }
2820
2821 #[test]
2824 fn completion_laddr_full_7_bits() {
2825 let bytes = vec![
2828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, ];
2831 let cmpl = new_cmpl_req(bytes).unwrap();
2832 assert_eq!(cmpl.laddr(), 0x7F);
2833 }
2834
2835 #[test]
2836 fn completion_laddr_bit6_set() {
2837 let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40];
2840 let cmpl = new_cmpl_req(bytes).unwrap();
2841 assert_eq!(cmpl.laddr(), 0x40);
2842 }
2843
2844 #[test]
2845 fn completion_laddr_with_reserved_bit_set() {
2846 let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5];
2849 let cmpl = new_cmpl_req(bytes).unwrap();
2850 assert_eq!(cmpl.laddr(), 0x55);
2851 }
2852
2853 #[test]
2854 fn completion_full_fields_with_laddr() {
2855 let bytes = vec![
2858 0x20, 0x01, 0x00, 0xFC, 0x12, 0x34, 0xAB, 0x64, ];
2861 let cmpl = new_cmpl_req(bytes).unwrap();
2862 assert_eq!(cmpl.cmpl_id(), 0x2001);
2863 assert_eq!(cmpl.byte_cnt(), 0x0FC);
2864 assert_eq!(cmpl.req_id(), 0x1234);
2865 assert_eq!(cmpl.tag(), 0xAB);
2866 assert_eq!(cmpl.laddr(), 0x64);
2867 }
2868
2869 #[test]
2870 fn atomic_fetchadd_rejects_invalid_operand_length() {
2871 let bad = [
2874 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
2878 let pkt = mk_pkt(0b010, 0b01100, &bad);
2879 assert_eq!(new_atomic_req(&pkt).unwrap_err(), TlpError::InvalidLength);
2880 }
2881
2882 #[test]
2885 fn message_dw3_preserves_upper_16_bits() {
2886 let bytes = vec![
2888 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x00, ];
2892 let msg = new_msg_req(bytes).unwrap();
2893 assert_eq!(msg.dw3(), 0xDEAD_BEEF);
2894 }
2895
2896 #[test]
2897 fn message_dw4_preserves_upper_16_bits() {
2898 let bytes = vec![
2900 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, ];
2904 let msg = new_msg_req(bytes).unwrap();
2905 assert_eq!(msg.dw4(), 0xCAFE_BABE);
2906 }
2907
2908 #[test]
2909 fn message_dw3_dw4_all_bits_set() {
2910 let bytes = vec![
2912 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2913 ];
2914 let msg = new_msg_req(bytes).unwrap();
2915 assert_eq!(msg.dw3(), 0xFFFF_FFFF);
2916 assert_eq!(msg.dw4(), 0xFFFF_FFFF);
2917 }
2918
2919 #[test]
2920 fn message_request_full_fields() {
2921 let bytes = vec![
2923 0xAB, 0xCD, 0x42, 0x7F, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
2924 ];
2925 let msg = new_msg_req(bytes).unwrap();
2926 assert_eq!(msg.req_id(), 0xABCD);
2927 assert_eq!(msg.tag(), 0x42);
2928 assert_eq!(msg.msg_code(), 0x7F);
2929 assert_eq!(msg.dw3(), 0x1234_5678);
2930 assert_eq!(msg.dw4(), 0x9ABC_DEF0);
2931 }
2932
2933 #[test]
2936 fn tlp_packet_header_debug() {
2937 let hdr = TlpPacketHeader::new(vec![0x00, 0x00, 0x20, 0x01], TlpMode::NonFlit).unwrap();
2938 let s = format!("{:?}", hdr);
2939 assert!(s.contains("TlpPacketHeader"));
2940 assert!(s.contains("format"));
2941 assert!(s.contains("length"));
2942 }
2943
2944 #[test]
2945 fn tlp_packet_debug() {
2946 let pkt =
2947 TlpPacket::new(vec![0x40, 0x00, 0x00, 0x01, 0xDE, 0xAD], TlpMode::NonFlit).unwrap();
2948 let s = format!("{:?}", pkt);
2949 assert!(s.contains("TlpPacket"));
2950 assert!(s.contains("data_len"));
2951 }
2952
2953 #[test]
2954 fn packet_mode_returns_correct_mode() {
2955 let non_flit = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::NonFlit).unwrap();
2956 assert_eq!(non_flit.mode(), TlpMode::NonFlit);
2957
2958 let flit = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::Flit).unwrap();
2959 assert_eq!(flit.mode(), TlpMode::Flit);
2960 }
2961
2962 #[test]
2963 fn tlp_packet_debug_flit() {
2964 let pkt = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x00], TlpMode::Flit).unwrap();
2965 let s = format!("{:?}", pkt);
2966 assert!(s.contains("TlpPacket"));
2967 assert!(s.contains("flit_dw0"));
2968 }
2969}