1use std::convert::TryFrom;
2use std::fmt::Display;
3
4#[macro_use]
5extern crate bitfield;
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum TlpError {
10 InvalidFormat,
12 InvalidType,
14 UnsupportedCombination,
16 InvalidLength,
18}
19
20#[repr(u8)]
21#[derive(Debug, PartialEq, Copy, Clone)]
22pub enum TlpFmt {
23 NoDataHeader3DW = 0b000,
24 NoDataHeader4DW = 0b001,
25 WithDataHeader3DW = 0b010,
26 WithDataHeader4DW = 0b011,
27 TlpPrefix = 0b100,
28}
29
30impl Display for TlpFmt {
31 fn fmt (&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
32 let name = match &self {
33 TlpFmt::NoDataHeader3DW => "3DW no Data Header",
34 TlpFmt::NoDataHeader4DW => "4DW no Data Header",
35 TlpFmt::WithDataHeader3DW => "3DW with Data Header",
36 TlpFmt::WithDataHeader4DW => "4DW with Data Header",
37 TlpFmt::TlpPrefix => "Tlp Prefix",
38 };
39 write!(fmt, "{}", name)
40 }
41}
42
43impl TryFrom<u32> for TlpFmt {
44 type Error = TlpError;
45
46 fn try_from(v: u32) -> Result<Self, Self::Error> {
47 match v {
48 x if x == TlpFmt::NoDataHeader3DW as u32 => Ok(TlpFmt::NoDataHeader3DW),
49 x if x == TlpFmt::NoDataHeader4DW as u32 => Ok(TlpFmt::NoDataHeader4DW),
50 x if x == TlpFmt::WithDataHeader3DW as u32 => Ok(TlpFmt::WithDataHeader3DW),
51 x if x == TlpFmt::WithDataHeader4DW as u32 => Ok(TlpFmt::WithDataHeader4DW),
52 x if x == TlpFmt::TlpPrefix as u32 => Ok(TlpFmt::TlpPrefix),
53 _ => Err(TlpError::InvalidFormat),
54 }
55 }
56}
57
58#[derive(Debug, Copy, Clone, PartialEq)]
60pub enum AtomicOp {
61 FetchAdd,
62 Swap,
63 CompareSwap,
64}
65
66#[derive(Debug, Copy, Clone, PartialEq)]
68pub enum AtomicWidth {
69 W32,
70 W64,
71}
72
73#[derive(PartialEq)]
74pub enum TlpFormatEncodingType {
75 MemoryRequest = 0b00000,
76 MemoryLockRequest = 0b00001,
77 IORequest = 0b00010,
78 ConfigType0Request = 0b00100,
79 ConfigType1Request = 0b00101,
80 Completion = 0b01010,
81 CompletionLocked = 0b01011,
82 FetchAtomicOpRequest = 0b01100,
83 UnconSwapAtomicOpRequest= 0b01101,
84 CompSwapAtomicOpRequest = 0b01110,
85 DeferrableMemoryWriteRequest = 0b11011,
86}
87
88impl TryFrom<u32> for TlpFormatEncodingType {
89 type Error = TlpError;
90
91 fn try_from(v: u32) -> Result<Self, Self::Error> {
92 match v {
93 x if x == TlpFormatEncodingType::MemoryRequest as u32 => Ok(TlpFormatEncodingType::MemoryRequest),
94 x if x == TlpFormatEncodingType::MemoryLockRequest as u32 => Ok(TlpFormatEncodingType::MemoryLockRequest),
95 x if x == TlpFormatEncodingType::IORequest as u32 => Ok(TlpFormatEncodingType::IORequest),
96 x if x == TlpFormatEncodingType::ConfigType0Request as u32 => Ok(TlpFormatEncodingType::ConfigType0Request),
97 x if x == TlpFormatEncodingType::ConfigType1Request as u32 => Ok(TlpFormatEncodingType::ConfigType1Request),
98 x if x == TlpFormatEncodingType::Completion as u32 => Ok(TlpFormatEncodingType::Completion),
99 x if x == TlpFormatEncodingType::CompletionLocked as u32 => Ok(TlpFormatEncodingType::CompletionLocked),
100 x if x == TlpFormatEncodingType::FetchAtomicOpRequest as u32 => Ok(TlpFormatEncodingType::FetchAtomicOpRequest),
101 x if x == TlpFormatEncodingType::UnconSwapAtomicOpRequest as u32 => Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest),
102 x if x == TlpFormatEncodingType::CompSwapAtomicOpRequest as u32 => Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest),
103 x if x == TlpFormatEncodingType::DeferrableMemoryWriteRequest as u32 => Ok(TlpFormatEncodingType::DeferrableMemoryWriteRequest),
104 _ => Err(TlpError::InvalidType),
105 }
106 }
107}
108
109#[derive(PartialEq)]
110#[derive(Debug)]
111pub enum TlpType {
112 MemReadReq,
113 MemReadLockReq,
114 MemWriteReq,
115 IOReadReq,
116 IOWriteReq,
117 ConfType0ReadReq,
118 ConfType0WriteReq,
119 ConfType1ReadReq,
120 ConfType1WriteReq,
121 MsgReq,
122 MsgReqData,
123 Cpl,
124 CplData,
125 CplLocked,
126 CplDataLocked,
127 FetchAddAtomicOpReq,
128 SwapAtomicOpReq,
129 CompareSwapAtomicOpReq,
130 DeferrableMemWriteReq,
131 LocalTlpPrefix,
132 EndToEndTlpPrefix,
133}
134
135impl Display for TlpType {
136 fn fmt (&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
137 let name = match &self {
138 TlpType::MemReadReq => "Memory Read Request",
139 TlpType::MemReadLockReq => "Locked Memory Read Request",
140 TlpType::MemWriteReq => "Memory Write Request",
141 TlpType::IOReadReq => "IO Read Request",
142 TlpType::IOWriteReq => "IO Write Request",
143 TlpType::ConfType0ReadReq => "Type 0 Config Read Request",
144 TlpType::ConfType0WriteReq => "Type 0 Config Write Request",
145 TlpType::ConfType1ReadReq => "Type 1 Config Read Request",
146 TlpType::ConfType1WriteReq => "Type 1 Config Write Request",
147 TlpType::MsgReq => "Message Request",
148 TlpType::MsgReqData => "Message with Data Request",
149 TlpType::Cpl => "Completion",
150 TlpType::CplData => "Completion with Data",
151 TlpType::CplLocked => "Locked Completion",
152 TlpType::CplDataLocked => "Locked Completion with Data",
153 TlpType::FetchAddAtomicOpReq => "Fetch Add Atomic Op Request",
154 TlpType::SwapAtomicOpReq => "Swap Atomic Op Request",
155 TlpType::CompareSwapAtomicOpReq => "Compare Swap Atomic Op Request",
156 TlpType::DeferrableMemWriteReq => "Deferrable Memory Write Request",
157 TlpType::LocalTlpPrefix => "Local Tlp Prefix",
158 TlpType::EndToEndTlpPrefix => "End To End Tlp Prefix",
159 };
160 write!(fmt, "{}", name)
161 }
162}
163
164impl TlpType {
165 pub fn is_non_posted(&self) -> bool {
167 matches!(self,
168 TlpType::MemReadReq |
169 TlpType::MemReadLockReq |
170 TlpType::IOReadReq | TlpType::IOWriteReq |
171 TlpType::ConfType0ReadReq | TlpType::ConfType0WriteReq |
172 TlpType::ConfType1ReadReq | TlpType::ConfType1WriteReq |
173 TlpType::FetchAddAtomicOpReq | TlpType::SwapAtomicOpReq | TlpType::CompareSwapAtomicOpReq |
174 TlpType::DeferrableMemWriteReq
175 )
176 }
177}
178
179bitfield! {
180 struct TlpHeader(MSB0 [u8]);
181 u32;
182 get_format, _: 2, 0;
183 get_type, _: 7, 3;
184 get_t9, _: 8, 8;
185 get_tc, _: 11, 9;
186 get_t8, _: 12, 12;
187 get_attr_b2, _: 13, 13;
188 get_ln, _: 14, 14;
189 get_th, _: 15, 15;
190 get_td, _: 16, 16;
191 get_ep, _: 17, 17;
192 get_attr, _: 19, 18;
193 get_at, _: 21, 20;
194 get_length, _: 31, 22;
195}
196
197impl<T: AsRef<[u8]>> TlpHeader<T> {
198
199 fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
200 let tlp_type = self.get_type();
201 let tlp_fmt = self.get_format();
202
203 match TlpFormatEncodingType::try_from(tlp_type) {
204 Ok(TlpFormatEncodingType::MemoryRequest) => {
205 match TlpFmt::try_from(tlp_fmt) {
206 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadReq),
207 Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadReq),
208 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::MemWriteReq),
209 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::MemWriteReq),
210 Ok(_) => Err(TlpError::UnsupportedCombination),
211 Err(e) => Err(e),
212 }
213 }
214 Ok(TlpFormatEncodingType::MemoryLockRequest) => {
215 match TlpFmt::try_from(tlp_fmt) {
216 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::MemReadLockReq),
217 Ok(TlpFmt::NoDataHeader4DW) => Ok(TlpType::MemReadLockReq),
218 Ok(_) => Err(TlpError::UnsupportedCombination),
219 Err(e) => Err(e),
220 }
221 }
222 Ok(TlpFormatEncodingType::IORequest) => {
223 match TlpFmt::try_from(tlp_fmt) {
224 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::IOReadReq),
225 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::IOWriteReq),
226 Ok(_) => Err(TlpError::UnsupportedCombination),
227 Err(e) => Err(e),
228 }
229 }
230 Ok(TlpFormatEncodingType::ConfigType0Request) => {
231 match TlpFmt::try_from(tlp_fmt) {
232 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType0ReadReq),
233 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType0WriteReq),
234 Ok(_) => Err(TlpError::UnsupportedCombination),
235 Err(e) => Err(e),
236 }
237 }
238 Ok(TlpFormatEncodingType::ConfigType1Request) => {
239 match TlpFmt::try_from(tlp_fmt) {
240 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::ConfType1ReadReq),
241 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::ConfType1WriteReq),
242 Ok(_) => Err(TlpError::UnsupportedCombination),
243 Err(e) => Err(e),
244 }
245 }
246 Ok(TlpFormatEncodingType::Completion) => {
247 match TlpFmt::try_from(tlp_fmt) {
248 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::Cpl),
249 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplData),
250 Ok(_) => Err(TlpError::UnsupportedCombination),
251 Err(e) => Err(e),
252 }
253 }
254 Ok(TlpFormatEncodingType::CompletionLocked) => {
255 match TlpFmt::try_from(tlp_fmt) {
256 Ok(TlpFmt::NoDataHeader3DW) => Ok(TlpType::CplLocked),
257 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CplDataLocked),
258 Ok(_) => Err(TlpError::UnsupportedCombination),
259 Err(e) => Err(e),
260 }
261 }
262 Ok(TlpFormatEncodingType::FetchAtomicOpRequest) => {
263 match TlpFmt::try_from(tlp_fmt) {
264 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::FetchAddAtomicOpReq),
265 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::FetchAddAtomicOpReq),
266 Ok(_) => Err(TlpError::UnsupportedCombination),
267 Err(e) => Err(e),
268 }
269 }
270 Ok(TlpFormatEncodingType::UnconSwapAtomicOpRequest) => {
271 match TlpFmt::try_from(tlp_fmt) {
272 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::SwapAtomicOpReq),
273 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::SwapAtomicOpReq),
274 Ok(_) => Err(TlpError::UnsupportedCombination),
275 Err(e) => Err(e),
276 }
277 }
278 Ok(TlpFormatEncodingType::CompSwapAtomicOpRequest) => {
279 match TlpFmt::try_from(tlp_fmt) {
280 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::CompareSwapAtomicOpReq),
281 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::CompareSwapAtomicOpReq),
282 Ok(_) => Err(TlpError::UnsupportedCombination),
283 Err(e) => Err(e),
284 }
285 }
286 Ok(TlpFormatEncodingType::DeferrableMemoryWriteRequest) => {
287 match TlpFmt::try_from(tlp_fmt) {
288 Ok(TlpFmt::WithDataHeader3DW) => Ok(TlpType::DeferrableMemWriteReq),
289 Ok(TlpFmt::WithDataHeader4DW) => Ok(TlpType::DeferrableMemWriteReq),
290 Ok(_) => Err(TlpError::UnsupportedCombination),
291 Err(e) => Err(e),
292 }
293 }
294 Err(e) => Err(e)
295 }
296 }
297}
298
299pub trait MemRequest {
306 fn address(&self) -> u64;
307 fn req_id(&self) -> u16;
308 fn tag(&self) -> u8;
309 fn ldwbe(&self) -> u8;
310 fn fdwbe(&self) -> u8;
311}
312
313bitfield! {
315 pub struct MemRequest3DW(MSB0 [u8]);
316 u32;
317 pub get_requester_id, _: 15, 0;
318 pub get_tag, _: 23, 16;
319 pub get_last_dw_be, _: 27, 24;
320 pub get_first_dw_be, _: 31, 28;
321 pub get_address32, _: 63, 32;
322}
323
324bitfield! {
325 pub struct MemRequest4DW(MSB0 [u8]);
326 u64;
327 pub get_requester_id, _: 15, 0;
328 pub get_tag, _: 23, 16;
329 pub get_last_dw_be, _: 27, 24;
330 pub get_first_dw_be, _: 31, 28;
331 pub get_address64, _: 95, 32;
332}
333
334impl <T: AsRef<[u8]>> MemRequest for MemRequest3DW<T> {
335 fn address(&self) -> u64 {
336 self.get_address32().into()
337 }
338 fn req_id(&self) -> u16 {
339 self.get_requester_id() as u16
340 }
341 fn tag(&self) -> u8 {
342 self.get_tag() as u8
343 }
344 fn ldwbe(&self) -> u8 {
345 self.get_last_dw_be() as u8
346 }
347 fn fdwbe(&self) -> u8 {
348 self.get_first_dw_be() as u8
349 }
350}
351
352impl <T: AsRef<[u8]>> MemRequest for MemRequest4DW<T> {
353 fn address(&self) -> u64 {
354 self.get_address64()
355 }
356 fn req_id(&self) -> u16 {
357 self.get_requester_id() as u16
358 }
359 fn tag(&self) -> u8 {
360 self.get_tag() as u8
361 }
362 fn ldwbe(&self) -> u8 {
363 self.get_last_dw_be() as u8
364 }
365 fn fdwbe(&self) -> u8 {
366 self.get_first_dw_be() as u8
367 }
368}
369
370pub fn new_mem_req(bytes: Vec<u8>, format: &TlpFmt) -> Box<dyn MemRequest> {
400 match format {
401 TlpFmt::NoDataHeader3DW => Box::new(MemRequest3DW(bytes)),
402 TlpFmt::NoDataHeader4DW => Box::new(MemRequest4DW(bytes)),
403 TlpFmt::WithDataHeader3DW => Box::new(MemRequest3DW(bytes)),
404 TlpFmt::WithDataHeader4DW => Box::new(MemRequest4DW(bytes)),
405 TlpFmt::TlpPrefix => Box::new(MemRequest3DW(bytes)),
406 }
407}
408
409pub trait ConfigurationRequest {
413 fn req_id(&self) -> u16;
414 fn tag(&self) -> u8;
415 fn bus_nr(&self) -> u8;
416 fn dev_nr(&self) -> u8;
417 fn func_nr(&self) -> u8;
418 fn ext_reg_nr(&self) -> u8;
419 fn reg_nr(&self) -> u8;
420}
421
422pub fn new_conf_req(bytes: Vec<u8>, _format: &TlpFmt) -> Box<dyn ConfigurationRequest> {
444 Box::new(ConfigRequest(bytes))
445}
446
447bitfield! {
448 pub struct ConfigRequest(MSB0 [u8]);
449 u32;
450 pub get_requester_id, _: 15, 0;
451 pub get_tag, _: 23, 16;
452 pub get_last_dw_be, _: 27, 24;
453 pub get_first_dw_be, _: 31, 28;
454 pub get_bus_nr, _: 39, 32;
455 pub get_dev_nr, _: 44, 40;
456 pub get_func_nr, _: 47, 45;
457 pub rsvd, _: 51, 48;
458 pub get_ext_reg_nr, _: 55, 52;
459 pub get_register_nr, _: 61, 56;
460 r, _: 63, 62;
461}
462
463impl <T: AsRef<[u8]>> ConfigurationRequest for ConfigRequest<T> {
464 fn req_id(&self) -> u16 {
465 self.get_requester_id() as u16
466 }
467 fn tag(&self) -> u8 {
468 self.get_tag() as u8
469 }
470 fn bus_nr(&self) -> u8 {
471 self.get_bus_nr() as u8
472 }
473 fn dev_nr(&self) -> u8 {
474 self.get_dev_nr() as u8
475 }
476 fn func_nr(&self) -> u8 {
477 self.get_func_nr() as u8
478 }
479 fn ext_reg_nr(&self) -> u8 {
480 self.get_ext_reg_nr() as u8
481 }
482 fn reg_nr(&self) -> u8 {
483 self.get_register_nr() as u8
484 }
485}
486
487pub trait CompletionRequest {
493 fn cmpl_id(&self) -> u16;
494 fn cmpl_stat(&self) -> u8;
495 fn bcm(&self) -> u8;
496 fn byte_cnt(&self) -> u16;
497 fn req_id(&self) -> u16;
498 fn tag(&self) -> u8;
499 fn laddr(&self) -> u8;
500}
501
502bitfield! {
503 pub struct CompletionReqDW23(MSB0 [u8]);
504 u16;
505 pub get_completer_id, _: 15, 0;
506 pub get_cmpl_stat, _: 18, 16;
507 pub get_bcm, _: 19, 19;
508 pub get_byte_cnt, _: 31, 20;
509 pub get_req_id, _: 47, 32;
510 pub get_tag, _: 55, 48;
511 r, _: 56, 56;
512 pub get_laddr, _: 63, 57;
513}
514
515impl <T: AsRef<[u8]>> CompletionRequest for CompletionReqDW23<T> {
516 fn cmpl_id(&self) -> u16 {
517 self.get_completer_id()
518 }
519 fn cmpl_stat(&self) -> u8 {
520 self.get_cmpl_stat() as u8
521 }
522 fn bcm(&self) -> u8 {
523 self.get_bcm() as u8
524 }
525 fn byte_cnt(&self) -> u16 {
526 self.get_byte_cnt()
527 }
528 fn req_id(&self) -> u16 {
529 self.get_req_id()
530 }
531 fn tag(&self) -> u8 {
532 self.get_tag() as u8
533 }
534 fn laddr(&self) -> u8 {
535 self.get_laddr() as u8
536 }
537}
538
539pub fn new_cmpl_req(bytes: Vec<u8>, _format: &TlpFmt) -> Box<dyn CompletionRequest> {
557 Box::new(CompletionReqDW23(bytes))
558}
559
560pub trait MessageRequest {
563 fn req_id(&self) -> u16;
564 fn tag(&self) -> u8;
565 fn msg_code(&self) -> u8;
566 fn dw3(&self) -> u32;
568 fn dw4(&self) -> u32;
569}
570
571bitfield! {
572 pub struct MessageReqDW24(MSB0 [u8]);
573 u32;
574 pub get_requester_id, _: 15, 0;
575 pub get_tag, _: 23, 16;
576 pub get_msg_code, _: 31, 24;
577 pub get_dw3, _: 63, 32;
578 pub get_dw4, _: 95, 64;
579}
580
581impl <T: AsRef<[u8]>> MessageRequest for MessageReqDW24<T> {
582 fn req_id(&self) -> u16 {
583 self.get_requester_id() as u16
584 }
585 fn tag(&self) -> u8 {
586 self.get_tag() as u8
587 }
588 fn msg_code(&self) -> u8 {
589 self.get_msg_code() as u8
590 }
591 fn dw3(&self) -> u32 {
592 self.get_dw3()
593 }
594 fn dw4(&self) -> u32 {
595 self.get_dw4()
596 }
597 }
599
600pub fn new_msg_req(bytes: Vec<u8>, _format: &TlpFmt) -> Box<dyn MessageRequest> {
617 Box::new(MessageReqDW24(bytes))
618}
619
620pub trait AtomicRequest: std::fmt::Debug {
623 fn op(&self) -> AtomicOp;
624 fn width(&self) -> AtomicWidth;
625 fn req_id(&self) -> u16;
626 fn tag(&self) -> u8;
627 fn address(&self) -> u64;
628 fn operand0(&self) -> u64;
630 fn operand1(&self) -> Option<u64>;
632}
633
634#[derive(Debug)]
635struct AtomicReq {
636 op: AtomicOp,
637 width: AtomicWidth,
638 req_id: u16,
639 tag: u8,
640 address: u64,
641 operand0: u64,
642 operand1: Option<u64>,
643}
644
645impl AtomicRequest for AtomicReq {
646 fn op(&self) -> AtomicOp { self.op }
647 fn width(&self) -> AtomicWidth { self.width }
648 fn req_id(&self) -> u16 { self.req_id }
649 fn tag(&self) -> u8 { self.tag }
650 fn address(&self) -> u64 { self.address }
651 fn operand0(&self) -> u64 { self.operand0 }
652 fn operand1(&self) -> Option<u64> { self.operand1 }
653}
654
655fn read_operand_be(b: &[u8], off: usize, width: AtomicWidth) -> u64 {
656 match width {
657 AtomicWidth::W32 => u32::from_be_bytes([b[off], b[off+1], b[off+2], b[off+3]]) as u64,
658 AtomicWidth::W64 => u64::from_be_bytes([
659 b[off], b[off+1], b[off+2], b[off+3],
660 b[off+4], b[off+5], b[off+6], b[off+7],
661 ]),
662 }
663}
664
665pub fn new_atomic_req(pkt: &TlpPacket) -> Result<Box<dyn AtomicRequest>, TlpError> {
691 let tlp_type = pkt.get_tlp_type()?;
692 let format = pkt.get_tlp_format()?;
693 let bytes = pkt.get_data();
694
695 let op = match tlp_type {
696 TlpType::FetchAddAtomicOpReq => AtomicOp::FetchAdd,
697 TlpType::SwapAtomicOpReq => AtomicOp::Swap,
698 TlpType::CompareSwapAtomicOpReq => AtomicOp::CompareSwap,
699 _ => return Err(TlpError::UnsupportedCombination),
700 };
701 let (width, hdr_len) = match format {
702 TlpFmt::WithDataHeader3DW => (AtomicWidth::W32, 8usize),
703 TlpFmt::WithDataHeader4DW => (AtomicWidth::W64, 12usize),
704 _ => return Err(TlpError::UnsupportedCombination),
705 };
706
707 let op_size = match width { AtomicWidth::W32 => 4usize, AtomicWidth::W64 => 8usize };
708 let num_ops = if matches!(op, AtomicOp::CompareSwap) { 2 } else { 1 };
709 let needed = hdr_len + op_size * num_ops;
710 if bytes.len() != needed { return Err(TlpError::InvalidLength); }
711
712 let req_id = u16::from_be_bytes([bytes[0], bytes[1]]);
713 let tag = bytes[2];
714 let address = match width {
715 AtomicWidth::W32 => u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64,
716 AtomicWidth::W64 => u64::from_be_bytes([
717 bytes[4], bytes[5], bytes[6], bytes[7],
718 bytes[8], bytes[9], bytes[10], bytes[11],
719 ]),
720 };
721
722 let operand0 = read_operand_be(&bytes, hdr_len, width);
723 let operand1 = if matches!(op, AtomicOp::CompareSwap) {
724 Some(read_operand_be(&bytes, hdr_len + op_size, width))
725 } else {
726 None
727 };
728
729 Ok(Box::new(AtomicReq { op, width, req_id, tag, address, operand0, operand1 }))
730}
731
732pub struct TlpPacketHeader {
735 header: TlpHeader<Vec<u8>>,
736}
737
738impl TlpPacketHeader {
739 pub fn new(bytes: Vec<u8>) -> TlpPacketHeader {
740 let mut dw0 = vec![0; 4];
741 dw0[..4].clone_from_slice(&bytes[0..4]);
742
743 TlpPacketHeader { header: TlpHeader(dw0) }
744 }
745
746 pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
747 self.header.get_tlp_type()
748 }
749
750 pub fn get_format(&self) -> u32 {self.header.get_format()}
751 pub fn get_type(&self) -> u32 {self.header.get_type()}
752 pub fn get_t9(&self) -> u32 {self.header.get_t9()}
753 pub fn get_tc(&self) -> u32 {self.header.get_tc()}
754 pub fn get_t8(&self) -> u32 {self.header.get_t8()}
755 pub fn get_attr_b2(&self) -> u32 {self.header.get_attr_b2()}
756 pub fn get_ln(&self) -> u32 {self.header.get_ln()}
757 pub fn get_th(&self) -> u32 {self.header.get_th()}
758 pub fn get_td(&self) -> u32 {self.header.get_td()}
759 pub fn get_ep(&self) -> u32 {self.header.get_ep()}
760 pub fn get_attr(&self) -> u32 {self.header.get_attr()}
761 pub fn get_at(&self) -> u32 {self.header.get_at()}
762 pub fn get_length(&self) -> u32 {self.header.get_length()}
763
764}
765
766pub struct TlpPacket {
815 header: TlpPacketHeader,
816 data: Vec<u8>,
817}
818
819impl TlpPacket {
820 pub fn new(bytes: Vec<u8>) -> TlpPacket {
821 let mut ownbytes = bytes.to_vec();
822 let mut header = vec![0; 4];
823 header.clone_from_slice(&ownbytes[0..4]);
824 let data = ownbytes.drain(4..).collect();
825 TlpPacket {
826 header: TlpPacketHeader::new(header),
827 data,
828 }
829 }
830
831 pub fn get_header(&self) -> &TlpPacketHeader {
832 &self.header
833 }
834
835 pub fn get_data(&self) -> Vec<u8> {
836 self.data.to_vec()
837 }
838
839 pub fn get_tlp_type(&self) -> Result<TlpType, TlpError> {
840 self.header.get_tlp_type()
841 }
842
843 pub fn get_tlp_format(&self) -> Result<TlpFmt, TlpError> {
844 TlpFmt::try_from(self.header.get_format())
845 }
846}
847
848#[cfg(test)]
849mod tests {
850 use super::*;
851
852 #[test]
853 fn tlp_header_type() {
854 let memread = TlpHeader([0x0, 0x0, 0x0, 0x0]);
856 assert_eq!(memread.get_tlp_type().unwrap(), TlpType::MemReadReq);
857
858 let memread32 = TlpHeader([0x00, 0x00, 0x20, 0x01]);
860 assert_eq!(memread32.get_tlp_type().unwrap(), TlpType::MemReadReq);
861
862 let memwrite32 = TlpHeader([0x40, 0x00, 0x00, 0x01]);
864 assert_eq!(memwrite32.get_tlp_type().unwrap(), TlpType::MemWriteReq);
865
866 let cpl_no_data = TlpHeader([0x0a, 0x00, 0x10, 0x00]);
868 assert_eq!(cpl_no_data.get_tlp_type().unwrap(), TlpType::Cpl);
869
870 let cpl_with_data = TlpHeader([0x4a, 0x00, 0x20, 0x40]);
872 assert_eq!(cpl_with_data.get_tlp_type().unwrap(), TlpType::CplData);
873
874 let memread_4dw = TlpHeader([0x20, 0x00, 0x20, 0x40]);
876 assert_eq!(memread_4dw.get_tlp_type().unwrap(), TlpType::MemReadReq);
877
878 let conf_t0_read = TlpHeader([0x04, 0x00, 0x00, 0x01]);
880 assert_eq!(conf_t0_read.get_tlp_type().unwrap(), TlpType::ConfType0ReadReq);
881
882 let conf_t0_write = TlpHeader([0x44, 0x00, 0x00, 0x01]);
884 assert_eq!(conf_t0_write.get_tlp_type().unwrap(), TlpType::ConfType0WriteReq);
885
886 let conf_t1_read = TlpHeader([0x05, 0x88, 0x80, 0x01]);
888 assert_eq!(conf_t1_read.get_tlp_type().unwrap(), TlpType::ConfType1ReadReq);
889
890 let conf_t1_write = TlpHeader([0x45, 0x88, 0x80, 0x01]);
892 assert_eq!(conf_t1_write.get_tlp_type().unwrap(), TlpType::ConfType1WriteReq);
893
894 let memwrite64 = TlpHeader([0x60, 0x00, 0x90, 0x01]);
897 assert_eq!(memwrite64.get_tlp_type().unwrap(), TlpType::MemWriteReq);
898 }
899
900 #[test]
901 fn tlp_header_works_all_zeros() {
902 let bits_locations = TlpHeader([0x0, 0x0, 0x0, 0x0]);
903
904 assert_eq!(bits_locations.get_format(), 0);
905 assert_eq!(bits_locations.get_type(), 0);
906 assert_eq!(bits_locations.get_t9(), 0);
907 assert_eq!(bits_locations.get_tc(), 0);
908 assert_eq!(bits_locations.get_t8(), 0);
909 assert_eq!(bits_locations.get_attr_b2(), 0);
910 assert_eq!(bits_locations.get_ln(), 0);
911 assert_eq!(bits_locations.get_th(), 0);
912 assert_eq!(bits_locations.get_td(), 0);
913 assert_eq!(bits_locations.get_ep(), 0);
914 assert_eq!(bits_locations.get_attr(), 0);
915 assert_eq!(bits_locations.get_at(), 0);
916 assert_eq!(bits_locations.get_length(), 0);
917 }
918
919 #[test]
920 fn tlp_header_works_all_ones() {
921 let bits_locations = TlpHeader([0xff, 0xff, 0xff, 0xff]);
922
923 assert_eq!(bits_locations.get_format(), 0x7);
924 assert_eq!(bits_locations.get_type(), 0x1f);
925 assert_eq!(bits_locations.get_t9(), 0x1);
926 assert_eq!(bits_locations.get_tc(), 0x7);
927 assert_eq!(bits_locations.get_t8(), 0x1);
928 assert_eq!(bits_locations.get_attr_b2(), 0x1);
929 assert_eq!(bits_locations.get_ln(), 0x1);
930 assert_eq!(bits_locations.get_th(), 0x1);
931 assert_eq!(bits_locations.get_td(), 0x1);
932 assert_eq!(bits_locations.get_ep(), 0x1);
933 assert_eq!(bits_locations.get_attr(), 0x3);
934 assert_eq!(bits_locations.get_at(), 0x3);
935 assert_eq!(bits_locations.get_length(), 0x3ff);
936 }
937
938 #[test]
939 fn test_invalid_format_error() {
940 let invalid_fmt = TlpHeader([0xa0, 0x00, 0x00, 0x01]); let result = invalid_fmt.get_tlp_type();
943 assert!(result.is_err());
944 assert_eq!(result.unwrap_err(), TlpError::InvalidFormat);
945 }
946
947 #[test]
948 fn test_invalid_type_error() {
949 let invalid_type = TlpHeader([0x0f, 0x00, 0x00, 0x01]); let result = invalid_type.get_tlp_type();
952 assert!(result.is_err());
953 assert_eq!(result.unwrap_err(), TlpError::InvalidType);
954 }
955
956 #[test]
957 fn test_unsupported_combination_error() {
958 let invalid_combo = TlpHeader([0x22, 0x00, 0x00, 0x01]); let result = invalid_combo.get_tlp_type();
962 assert!(result.is_err());
963 assert_eq!(result.unwrap_err(), TlpError::UnsupportedCombination);
964 }
965
966 fn dw0(fmt: u8, typ: u8) -> TlpHeader<[u8; 4]> {
971 TlpHeader([(fmt << 5) | (typ & 0x1f), 0x00, 0x00, 0x00])
972 }
973
974 fn mk_tlp(fmt: u8, typ: u8, rest: &[u8]) -> Vec<u8> {
977 let mut v = Vec::with_capacity(4 + rest.len());
978 v.push((fmt << 5) | (typ & 0x1f));
979 v.push(0x00); v.push(0x00); v.push(0x00); v.extend_from_slice(rest);
983 v
984 }
985
986 #[test]
989 fn header_decode_supported_pairs() {
990 const FMT_3DW_NO_DATA: u8 = 0b000;
991 const FMT_4DW_NO_DATA: u8 = 0b001;
992 const FMT_3DW_WITH_DATA: u8 = 0b010;
993 const FMT_4DW_WITH_DATA: u8 = 0b011;
994
995 const TY_MEM: u8 = 0b00000;
996 const TY_MEM_LK: u8 = 0b00001;
997 const TY_IO: u8 = 0b00010;
998 const TY_CFG0: u8 = 0b00100;
999 const TY_CFG1: u8 = 0b00101;
1000 const TY_CPL: u8 = 0b01010;
1001 const TY_CPL_LK: u8 = 0b01011;
1002 const TY_ATOM_FETCH: u8 = 0b01100;
1003 const TY_ATOM_SWAP: u8 = 0b01101;
1004 const TY_ATOM_CAS: u8 = 0b01110;
1005 const TY_DMWR: u8 = 0b11011;
1006
1007 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_MEM).get_tlp_type().unwrap(), TlpType::MemReadReq);
1009 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_MEM).get_tlp_type().unwrap(), TlpType::MemReadReq);
1010 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_MEM).get_tlp_type().unwrap(), TlpType::MemWriteReq);
1011 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_MEM).get_tlp_type().unwrap(), TlpType::MemWriteReq);
1012
1013 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_MEM_LK).get_tlp_type().unwrap(), TlpType::MemReadLockReq);
1015 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_MEM_LK).get_tlp_type().unwrap(), TlpType::MemReadLockReq);
1016
1017 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_IO).get_tlp_type().unwrap(), TlpType::IOReadReq);
1019 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_IO).get_tlp_type().unwrap(), TlpType::IOWriteReq);
1020
1021 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_CFG0).get_tlp_type().unwrap(), TlpType::ConfType0ReadReq);
1023 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_CFG0).get_tlp_type().unwrap(), TlpType::ConfType0WriteReq);
1024
1025 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_CFG1).get_tlp_type().unwrap(), TlpType::ConfType1ReadReq);
1027 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_CFG1).get_tlp_type().unwrap(), TlpType::ConfType1WriteReq);
1028
1029 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_CPL).get_tlp_type().unwrap(), TlpType::Cpl);
1031 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_CPL).get_tlp_type().unwrap(), TlpType::CplData);
1032
1033 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_CPL_LK).get_tlp_type().unwrap(), TlpType::CplLocked);
1035 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_CPL_LK).get_tlp_type().unwrap(), TlpType::CplDataLocked);
1036
1037 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_ATOM_FETCH).get_tlp_type().unwrap(), TlpType::FetchAddAtomicOpReq);
1039 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_ATOM_FETCH).get_tlp_type().unwrap(), TlpType::FetchAddAtomicOpReq);
1040
1041 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap(), TlpType::SwapAtomicOpReq);
1042 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap(), TlpType::SwapAtomicOpReq);
1043
1044 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_ATOM_CAS).get_tlp_type().unwrap(), TlpType::CompareSwapAtomicOpReq);
1045 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_ATOM_CAS).get_tlp_type().unwrap(), TlpType::CompareSwapAtomicOpReq);
1046
1047 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_DMWR).get_tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
1049 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_DMWR).get_tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
1050 }
1051
1052 #[test]
1055 fn header_decode_rejects_unsupported_combinations() {
1056 const FMT_3DW_NO_DATA: u8 = 0b000;
1057 const FMT_4DW_NO_DATA: u8 = 0b001;
1058 const FMT_3DW_WITH_DATA: u8 = 0b010;
1059 const FMT_4DW_WITH_DATA: u8 = 0b011;
1060 const FMT_PREFIX: u8 = 0b100;
1061
1062 const TY_MEM_LK: u8 = 0b00001;
1063 const TY_IO: u8 = 0b00010;
1064 const TY_CFG0: u8 = 0b00100;
1065 const TY_CFG1: u8 = 0b00101;
1066 const TY_CPL: u8 = 0b01010;
1067 const TY_CPL_LK: u8 = 0b01011;
1068 const TY_ATOM_FETCH: u8 = 0b01100;
1069 const TY_ATOM_SWAP: u8 = 0b01101;
1070 const TY_ATOM_CAS: u8 = 0b01110;
1071 const TY_DMWR: u8 = 0b11011;
1072
1073 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_IO).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1075 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_IO).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1076
1077 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_CFG0).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1079 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_CFG0).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1080 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_CFG1).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1081 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_CFG1).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1082
1083 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_CPL).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1085 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_CPL).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1086 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_CPL_LK).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1087 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_CPL_LK).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1088
1089 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_ATOM_FETCH).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1091 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_ATOM_FETCH).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1092 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1093 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_ATOM_SWAP).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1094 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_ATOM_CAS).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1095 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_ATOM_CAS).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1096
1097 assert_eq!(dw0(FMT_3DW_WITH_DATA, TY_MEM_LK).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1099 assert_eq!(dw0(FMT_4DW_WITH_DATA, TY_MEM_LK).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1100
1101 assert_eq!(dw0(FMT_PREFIX, TY_IO).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1104 assert_eq!(dw0(FMT_PREFIX, TY_CPL).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1105 assert_eq!(dw0(FMT_PREFIX, TY_CFG0).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1106
1107 assert_eq!(dw0(FMT_3DW_NO_DATA, TY_DMWR).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1109 assert_eq!(dw0(FMT_4DW_NO_DATA, TY_DMWR).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1110 assert_eq!(dw0(FMT_PREFIX, TY_DMWR).get_tlp_type().unwrap_err(), TlpError::UnsupportedCombination);
1111 }
1112
1113 #[test]
1116 fn tlp_header_dmwr32_decode() {
1117 let dmwr32 = TlpHeader([0x5B, 0x00, 0x00, 0x00]);
1119 assert_eq!(dmwr32.get_tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
1120 }
1121
1122 #[test]
1123 fn tlp_header_dmwr64_decode() {
1124 let dmwr64 = TlpHeader([0x7B, 0x00, 0x00, 0x00]);
1126 assert_eq!(dmwr64.get_tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
1127 }
1128
1129 #[test]
1130 fn tlp_header_dmwr_rejects_nodata_formats() {
1131 let dmwr_bad_3dw_nodata = TlpHeader([0x1B, 0x00, 0x00, 0x00]);
1133 assert_eq!(
1134 dmwr_bad_3dw_nodata.get_tlp_type().unwrap_err(),
1135 TlpError::UnsupportedCombination
1136 );
1137
1138 let dmwr_bad_4dw_nodata = TlpHeader([0x3B, 0x00, 0x00, 0x00]);
1140 assert_eq!(
1141 dmwr_bad_4dw_nodata.get_tlp_type().unwrap_err(),
1142 TlpError::UnsupportedCombination
1143 );
1144 }
1145
1146 #[test]
1147 fn dmwr_full_packet_3dw_fields() {
1148 let payload = [
1150 0xAB, 0xCD, 0x42, 0x0F, 0xDE, 0xAD, 0x00, 0x00, ];
1153 let pkt = TlpPacket::new(mk_tlp(0b010, 0b11011, &payload));
1154 assert_eq!(pkt.get_tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
1155 assert_eq!(pkt.get_tlp_format().unwrap(), TlpFmt::WithDataHeader3DW);
1156
1157 let mr = new_mem_req(pkt.get_data(), &pkt.get_tlp_format().unwrap());
1158 assert_eq!(mr.req_id(), 0xABCD);
1159 assert_eq!(mr.tag(), 0x42);
1160 assert_eq!(mr.address(), 0xDEAD_0000);
1161 }
1162
1163 #[test]
1164 fn dmwr_full_packet_4dw_fields() {
1165 let payload = [
1167 0xBE, 0xEF, 0xA5, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, ];
1171 let pkt = TlpPacket::new(mk_tlp(0b011, 0b11011, &payload));
1172 assert_eq!(pkt.get_tlp_type().unwrap(), TlpType::DeferrableMemWriteReq);
1173 assert_eq!(pkt.get_tlp_format().unwrap(), TlpFmt::WithDataHeader4DW);
1174
1175 let mr = new_mem_req(pkt.get_data(), &pkt.get_tlp_format().unwrap());
1176 assert_eq!(mr.req_id(), 0xBEEF);
1177 assert_eq!(mr.tag(), 0xA5);
1178 assert_eq!(mr.address(), 0x1122_3344_5566_7788);
1179 }
1180
1181 #[test]
1184 fn is_non_posted_returns_true_for_non_posted_types() {
1185 assert!(TlpType::MemReadReq.is_non_posted());
1186 assert!(TlpType::MemReadLockReq.is_non_posted());
1187 assert!(TlpType::IOReadReq.is_non_posted());
1188 assert!(TlpType::IOWriteReq.is_non_posted());
1189 assert!(TlpType::ConfType0ReadReq.is_non_posted());
1190 assert!(TlpType::ConfType0WriteReq.is_non_posted());
1191 assert!(TlpType::ConfType1ReadReq.is_non_posted());
1192 assert!(TlpType::ConfType1WriteReq.is_non_posted());
1193 assert!(TlpType::FetchAddAtomicOpReq.is_non_posted());
1194 assert!(TlpType::SwapAtomicOpReq.is_non_posted());
1195 assert!(TlpType::CompareSwapAtomicOpReq.is_non_posted());
1196 assert!(TlpType::DeferrableMemWriteReq.is_non_posted());
1197 }
1198
1199 #[test]
1200 fn is_non_posted_returns_false_for_posted_types() {
1201 assert!(!TlpType::MemWriteReq.is_non_posted());
1202 assert!(!TlpType::MsgReq.is_non_posted());
1203 assert!(!TlpType::MsgReqData.is_non_posted());
1204 }
1205
1206 #[test]
1207 fn is_non_posted_returns_false_for_completions() {
1208 assert!(!TlpType::Cpl.is_non_posted());
1210 assert!(!TlpType::CplData.is_non_posted());
1211 assert!(!TlpType::CplLocked.is_non_posted());
1212 assert!(!TlpType::CplDataLocked.is_non_posted());
1213 }
1214
1215 #[test]
1218 fn atomic_fetchadd_3dw_type_and_fields() {
1219 const FMT_3DW_WITH_DATA: u8 = 0b010;
1220 const TY_ATOM_FETCH: u8 = 0b01100;
1221
1222 let payload = [
1229 0x12, 0x34, 0x56, 0x00, 0x89, 0xAB, 0xCD, 0xEF, ];
1233
1234 let pkt = TlpPacket::new(mk_tlp(FMT_3DW_WITH_DATA, TY_ATOM_FETCH, &payload));
1235
1236 assert_eq!(pkt.get_tlp_type().unwrap(), TlpType::FetchAddAtomicOpReq);
1237 assert_eq!(pkt.get_tlp_format().unwrap(), TlpFmt::WithDataHeader3DW);
1238
1239 let fmt = pkt.get_tlp_format().unwrap();
1240 let mr = new_mem_req(pkt.get_data(), &fmt);
1241 assert_eq!(mr.req_id(), 0x1234);
1242 assert_eq!(mr.tag(), 0x56);
1243 assert_eq!(mr.address(), 0x89AB_CDEF);
1244 }
1245
1246 #[test]
1247 fn atomic_cas_4dw_type_and_fields() {
1248 const FMT_4DW_WITH_DATA: u8 = 0b011;
1249 const TY_ATOM_CAS: u8 = 0b01110;
1250
1251 let payload = [
1257 0xBE, 0xEF, 0xA5, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, ];
1262
1263 let pkt = TlpPacket::new(mk_tlp(FMT_4DW_WITH_DATA, TY_ATOM_CAS, &payload));
1264
1265 assert_eq!(pkt.get_tlp_type().unwrap(), TlpType::CompareSwapAtomicOpReq);
1266 assert_eq!(pkt.get_tlp_format().unwrap(), TlpFmt::WithDataHeader4DW);
1267
1268 let fmt = pkt.get_tlp_format().unwrap();
1269 let mr = new_mem_req(pkt.get_data(), &fmt);
1270 assert_eq!(mr.req_id(), 0xBEEF);
1271 assert_eq!(mr.tag(), 0xA5);
1272 assert_eq!(mr.address(), 0x1122_3344_5566_7788);
1273 }
1274
1275 #[test]
1278 fn fetchadd_3dw_operand() {
1279 let payload = [
1284 0xDE, 0xAD, 0x42, 0x00, 0xC0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, ];
1288 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &payload));
1289 let ar = new_atomic_req(&pkt).unwrap();
1290
1291 assert_eq!(ar.op(), AtomicOp::FetchAdd);
1292 assert_eq!(ar.width(), AtomicWidth::W32);
1293 assert_eq!(ar.req_id(), 0xDEAD);
1294 assert_eq!(ar.tag(), 0x42);
1295 assert_eq!(ar.address(), 0xC001_0004);
1296 assert_eq!(ar.operand0(), 0x0A);
1297 assert!(ar.operand1().is_none());
1298 }
1299
1300 #[test]
1301 fn fetchadd_4dw_operand() {
1302 let payload = [
1307 0x00, 0x42, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
1311 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01100, &payload));
1312 let ar = new_atomic_req(&pkt).unwrap();
1313
1314 assert_eq!(ar.op(), AtomicOp::FetchAdd);
1315 assert_eq!(ar.width(), AtomicWidth::W64);
1316 assert_eq!(ar.req_id(), 0x0042);
1317 assert_eq!(ar.tag(), 0xBB);
1318 assert_eq!(ar.address(), 0x0000_0001_0000_0000);
1319 assert_eq!(ar.operand0(), 0xFFFF_FFFF_FFFF_FFFF);
1320 assert!(ar.operand1().is_none());
1321 }
1322
1323 #[test]
1324 fn swap_3dw_operand() {
1325 let payload = [
1330 0x11, 0x11, 0x05, 0x00, 0xF0, 0x00, 0x00, 0x08, 0xAB, 0xCD, 0xEF, 0x01, ];
1334 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01101, &payload));
1335 let ar = new_atomic_req(&pkt).unwrap();
1336
1337 assert_eq!(ar.op(), AtomicOp::Swap);
1338 assert_eq!(ar.width(), AtomicWidth::W32);
1339 assert_eq!(ar.req_id(), 0x1111);
1340 assert_eq!(ar.tag(), 0x05);
1341 assert_eq!(ar.address(), 0xF000_0008);
1342 assert_eq!(ar.operand0(), 0xABCD_EF01);
1343 assert!(ar.operand1().is_none());
1344 }
1345
1346 #[test]
1347 fn cas_3dw_two_operands() {
1348 let payload = [
1354 0xAB, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, ];
1359 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01110, &payload));
1360 let ar = new_atomic_req(&pkt).unwrap();
1361
1362 assert_eq!(ar.op(), AtomicOp::CompareSwap);
1363 assert_eq!(ar.width(), AtomicWidth::W32);
1364 assert_eq!(ar.req_id(), 0xABCD);
1365 assert_eq!(ar.tag(), 0x07);
1366 assert_eq!(ar.address(), 0x0000_4000);
1367 assert_eq!(ar.operand0(), 0xCAFE_BABE);
1368 assert_eq!(ar.operand1(), Some(0xDEAD_BEEF));
1369 }
1370
1371 #[test]
1372 fn cas_4dw_two_operands() {
1373 let payload = [
1379 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, ];
1384 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01110, &payload));
1385 let ar = new_atomic_req(&pkt).unwrap();
1386
1387 assert_eq!(ar.op(), AtomicOp::CompareSwap);
1388 assert_eq!(ar.width(), AtomicWidth::W64);
1389 assert_eq!(ar.req_id(), 0x1234);
1390 assert_eq!(ar.tag(), 0xAA);
1391 assert_eq!(ar.address(), 0xFFFF_FFFF_0000_0000);
1392 assert_eq!(ar.operand0(), 0x0101_0101_0202_0202);
1393 assert_eq!(ar.operand1(), Some(0x0303_0303_0404_0404));
1394 }
1395
1396 #[test]
1397 fn atomic_req_rejects_wrong_tlp_type() {
1398 let pkt = TlpPacket::new(mk_tlp(0b000, 0b00000, &[0u8; 16]));
1400 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::UnsupportedCombination);
1401 }
1402
1403 #[test]
1404 fn atomic_req_rejects_wrong_format() {
1405 let pkt = TlpPacket::new(mk_tlp(0b000, 0b01100, &[0u8; 16]));
1408 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::UnsupportedCombination);
1409 }
1410
1411 #[test]
1412 fn atomic_req_rejects_short_payload() {
1413 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &[0u8; 3]));
1415 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
1416
1417 let pkt = TlpPacket::new(mk_tlp(0b010, 0b01100, &[0u8; 8]));
1419 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
1420
1421 let pkt = TlpPacket::new(mk_tlp(0b011, 0b01110, &[0u8; 20]));
1423 assert_eq!(new_atomic_req(&pkt).err().unwrap(), TlpError::InvalidLength);
1424 }
1425
1426 fn mk_pkt(fmt: u8, typ: u8, data: &[u8]) -> TlpPacket {
1429 TlpPacket::new(mk_tlp(fmt, typ, data))
1430 }
1431
1432 #[test]
1435 fn atomic_fetchadd_3dw_32_parses_operands() {
1436 let data = [
1438 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x07, ];
1442 let pkt = mk_pkt(0b010, 0b01100, &data);
1443 let a = new_atomic_req(&pkt).unwrap();
1444 assert_eq!(a.op(), AtomicOp::FetchAdd);
1445 assert_eq!(a.width(), AtomicWidth::W32);
1446 assert_eq!(a.req_id(), 0x0100);
1447 assert_eq!(a.tag(), 0x01);
1448 assert_eq!(a.address(), 0x0000_1000);
1449 assert_eq!(a.operand0(), 7);
1450 assert!(a.operand1().is_none());
1451 }
1452
1453 #[test]
1454 fn atomic_swap_4dw_64_parses_operands() {
1455 let data = [
1457 0xBE, 0xEF, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, ];
1461 let pkt = mk_pkt(0b011, 0b01101, &data);
1462 let a = new_atomic_req(&pkt).unwrap();
1463 assert_eq!(a.op(), AtomicOp::Swap);
1464 assert_eq!(a.width(), AtomicWidth::W64);
1465 assert_eq!(a.req_id(), 0xBEEF);
1466 assert_eq!(a.tag(), 0xA5);
1467 assert_eq!(a.address(), 0x0000_0001_0000_0000);
1468 assert_eq!(a.operand0(), 0xDEAD_BEEF_CAFE_BABE);
1469 assert!(a.operand1().is_none());
1470 }
1471
1472 #[test]
1473 fn atomic_cas_3dw_32_parses_operands() {
1474 let data = [
1476 0xAB, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, ];
1481 let pkt = mk_pkt(0b010, 0b01110, &data);
1482 let a = new_atomic_req(&pkt).unwrap();
1483 assert_eq!(a.op(), AtomicOp::CompareSwap);
1484 assert_eq!(a.width(), AtomicWidth::W32);
1485 assert_eq!(a.req_id(), 0xABCD);
1486 assert_eq!(a.tag(), 0x07);
1487 assert_eq!(a.address(), 0x0000_4000);
1488 assert_eq!(a.operand0(), 0xCAFE_BABE);
1489 assert_eq!(a.operand1(), Some(0xDEAD_BEEF));
1490 }
1491
1492 #[test]
1495 fn completion_laddr_full_7_bits() {
1496 let bytes = vec![
1499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, ];
1502 let cmpl = new_cmpl_req(bytes, &TlpFmt::NoDataHeader3DW);
1503 assert_eq!(cmpl.laddr(), 0x7F);
1504 }
1505
1506 #[test]
1507 fn completion_laddr_bit6_set() {
1508 let bytes = vec![
1511 0x00, 0x00, 0x00, 0x00,
1512 0x00, 0x00, 0x00, 0x40,
1513 ];
1514 let cmpl = new_cmpl_req(bytes, &TlpFmt::NoDataHeader3DW);
1515 assert_eq!(cmpl.laddr(), 0x40);
1516 }
1517
1518 #[test]
1519 fn completion_laddr_with_reserved_bit_set() {
1520 let bytes = vec![
1523 0x00, 0x00, 0x00, 0x00,
1524 0x00, 0x00, 0x00, 0xD5,
1525 ];
1526 let cmpl = new_cmpl_req(bytes, &TlpFmt::NoDataHeader3DW);
1527 assert_eq!(cmpl.laddr(), 0x55);
1528 }
1529
1530 #[test]
1531 fn completion_full_fields_with_laddr() {
1532 let bytes = vec![
1535 0x20, 0x01, 0x00, 0xFC, 0x12, 0x34, 0xAB, 0x64, ];
1538 let cmpl = new_cmpl_req(bytes, &TlpFmt::NoDataHeader3DW);
1539 assert_eq!(cmpl.cmpl_id(), 0x2001);
1540 assert_eq!(cmpl.byte_cnt(), 0x0FC);
1541 assert_eq!(cmpl.req_id(), 0x1234);
1542 assert_eq!(cmpl.tag(), 0xAB);
1543 assert_eq!(cmpl.laddr(), 0x64);
1544 }
1545
1546 #[test]
1547 fn atomic_fetchadd_rejects_invalid_operand_length() {
1548 let bad = [
1551 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
1555 let pkt = mk_pkt(0b010, 0b01100, &bad);
1556 assert_eq!(new_atomic_req(&pkt).unwrap_err(), TlpError::InvalidLength);
1557 }
1558
1559 #[test]
1562 fn message_dw3_preserves_upper_16_bits() {
1563 let bytes = vec![
1565 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x00, ];
1569 let msg = new_msg_req(bytes, &TlpFmt::NoDataHeader3DW);
1570 assert_eq!(msg.dw3(), 0xDEAD_BEEF);
1571 }
1572
1573 #[test]
1574 fn message_dw4_preserves_upper_16_bits() {
1575 let bytes = vec![
1577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, ];
1581 let msg = new_msg_req(bytes, &TlpFmt::NoDataHeader3DW);
1582 assert_eq!(msg.dw4(), 0xCAFE_BABE);
1583 }
1584
1585 #[test]
1586 fn message_dw3_dw4_all_bits_set() {
1587 let bytes = vec![
1589 0x00, 0x00, 0x00, 0x00,
1590 0xFF, 0xFF, 0xFF, 0xFF,
1591 0xFF, 0xFF, 0xFF, 0xFF,
1592 ];
1593 let msg = new_msg_req(bytes, &TlpFmt::NoDataHeader3DW);
1594 assert_eq!(msg.dw3(), 0xFFFF_FFFF);
1595 assert_eq!(msg.dw4(), 0xFFFF_FFFF);
1596 }
1597
1598 #[test]
1599 fn message_request_full_fields() {
1600 let bytes = vec![
1602 0xAB, 0xCD, 0x42, 0x7F,
1603 0x12, 0x34, 0x56, 0x78,
1604 0x9A, 0xBC, 0xDE, 0xF0,
1605 ];
1606 let msg = new_msg_req(bytes, &TlpFmt::NoDataHeader3DW);
1607 assert_eq!(msg.req_id(), 0xABCD);
1608 assert_eq!(msg.tag(), 0x42);
1609 assert_eq!(msg.msg_code(), 0x7F);
1610 assert_eq!(msg.dw3(), 0x1234_5678);
1611 assert_eq!(msg.dw4(), 0x9ABC_DEF0);
1612 }
1613}
1614