use rtlp_lib::*;
pub const FM_NOP: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
pub const FM_MRD32_MIN: [u8; 12] = [
0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub const FM_MRD32_A1_PASID: [u8; 16] = [
0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x0F,
];
pub const FM_MWR32_MIN: [u8; 16] = [
0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF,
];
pub const FM_MWR32_PARTIAL_A1: [u8; 20] = [
0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xAA, 0xBB, 0xCC, 0xDD,
];
pub const FM_IOWR_A2: [u8; 20] = [
0x42, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
0x10, 0x20, 0x30, 0x40,
];
pub const FM_CFGWR0_A3: [u8; 20] = [
0x44, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
0x44, 0x33, 0x22, 0x11,
];
pub const FM_UIOMRD64_MIN: [u8; 16] = [
0x22, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub const FM_UIOMWR64_MIN: [u8; 24] = [
0x61, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
];
pub const FM_MSG_TO_RC: [u8; 12] = [
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub const FM_MSGD_TO_RC: [u8; 16] = [
0x70, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x55, 0xAA, 0x55,
];
pub const FM_FETCHADD32: [u8; 16] = [
0x4C, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
];
pub const FM_CAS32: [u8; 20] = [
0x4E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
0x22, 0x22, 0x22, 0x22,
];
pub const FM_DMWR32: [u8; 16] = [
0x5B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xEE, 0x00,
];
pub const FM_STREAM_FRAGMENT_0: [u8; 48] = [
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF,
0x22, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
pub const FM_LOCAL_PREFIX_ONLY: [u8; 4] = [0x8D, 0x00, 0x00, 0x00];
#[test]
fn flit_packet_new_succeeds_for_valid_flit() {
let pkt = TlpPacket::new(FM_MRD32_MIN.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemRead32));
assert!(pkt.data().is_empty()); }
#[test]
fn flit_header_new_returns_not_implemented() {
let bytes = FM_MRD32_MIN.to_vec();
assert_eq!(
TlpPacketHeader::new(bytes, TlpMode::Flit).err().unwrap(),
TlpError::NotImplemented
);
}
#[test]
fn flit_all_fm_vectors_parse_to_expected_type() {
let cases: &[(&[u8], FlitTlpType)] = &[
(&FM_NOP, FlitTlpType::Nop),
(&FM_MRD32_MIN, FlitTlpType::MemRead32),
(&FM_MRD32_A1_PASID, FlitTlpType::MemRead32),
(&FM_MWR32_MIN, FlitTlpType::MemWrite32),
(&FM_MWR32_PARTIAL_A1, FlitTlpType::MemWrite32),
(&FM_IOWR_A2, FlitTlpType::IoWrite),
(&FM_CFGWR0_A3, FlitTlpType::CfgWrite0),
(&FM_UIOMRD64_MIN, FlitTlpType::UioMemRead),
(&FM_UIOMWR64_MIN, FlitTlpType::UioMemWrite),
(&FM_MSG_TO_RC, FlitTlpType::MsgToRc),
(&FM_MSGD_TO_RC, FlitTlpType::MsgDToRc),
(&FM_FETCHADD32, FlitTlpType::FetchAdd32),
(&FM_CAS32, FlitTlpType::CompareSwap32),
(&FM_DMWR32, FlitTlpType::DeferrableMemWrite32),
(&FM_LOCAL_PREFIX_ONLY, FlitTlpType::LocalTlpPrefix),
];
for (bytes, expected) in cases {
let dw0 = FlitDW0::from_dw0(bytes)
.unwrap_or_else(|e| panic!("FM_* failed to parse: {:?} (byte0={:#04x})", e, bytes[0]));
assert_eq!(
dw0.tlp_type, *expected,
"byte0={:#04x} decoded to {:?}, expected {:?}",
bytes[0], dw0.tlp_type, expected
);
}
}
#[test]
fn flit_all_fm_vectors_parse_with_correct_ohc() {
let cases: &[(&[u8], u8, &str)] = &[
(&FM_NOP, 0, "FM_NOP"),
(&FM_MRD32_MIN, 0, "FM_MRD32_MIN"),
(&FM_MWR32_MIN, 0, "FM_MWR32_MIN"),
(&FM_MRD32_A1_PASID, 1, "FM_MRD32_A1_PASID"), (&FM_MWR32_PARTIAL_A1, 1, "FM_MWR32_PARTIAL_A1"), (&FM_IOWR_A2, 1, "FM_IOWR_A2"), (&FM_CFGWR0_A3, 1, "FM_CFGWR0_A3"), ];
for (bytes, expected_ohc, name) in cases {
let dw0 = FlitDW0::from_dw0(bytes).unwrap();
assert_eq!(dw0.ohc, *expected_ohc, "{} ohc mismatch", name);
assert_eq!(
dw0.ohc_count(),
(*expected_ohc).count_ones() as u8,
"{} ohc_count mismatch",
name
);
}
}
#[test]
fn flit_t1_nop_dw0_fields() {
let dw0 = FlitDW0::from_dw0(&FM_NOP).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::Nop);
assert_eq!(dw0.tc, 0);
assert_eq!(dw0.ohc, 0);
assert_eq!(dw0.ts, 0);
assert_eq!(dw0.attr, 0);
assert_eq!(dw0.length, 0);
}
#[test]
fn flit_t1_mrd32_dw0_fields() {
let dw0 = FlitDW0::from_dw0(&FM_MRD32_MIN).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::MemRead32);
assert_eq!(dw0.tc, 0);
assert_eq!(dw0.ohc, 0);
assert_eq!(dw0.length, 1); }
#[test]
fn flit_t1_mrd32_a1_dw0_ohc_present() {
let dw0 = FlitDW0::from_dw0(&FM_MRD32_A1_PASID).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::MemRead32);
assert_eq!(dw0.ohc, 0x01); assert_eq!(dw0.ohc_count(), 1);
assert_eq!(dw0.length, 1);
}
#[test]
fn flit_t1_mwr32_dw0_fields() {
let dw0 = FlitDW0::from_dw0(&FM_MWR32_MIN).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::MemWrite32);
assert_eq!(dw0.tc, 0);
assert_eq!(dw0.ohc, 0);
assert_eq!(dw0.length, 1);
}
#[test]
fn flit_t1_uiomrd64_dw0_fields() {
let dw0 = FlitDW0::from_dw0(&FM_UIOMRD64_MIN).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::UioMemRead);
assert_eq!(dw0.ohc, 0);
assert_eq!(dw0.length, 2);
}
#[test]
fn flit_t1_cas32_dw0_length_is_2() {
let dw0 = FlitDW0::from_dw0(&FM_CAS32).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::CompareSwap32);
assert_eq!(dw0.length, 2);
}
#[test]
fn flit_t1_unknown_type_returns_invalid_type_error() {
let bad_type = [0xFF, 0x00, 0x00, 0x00];
assert_eq!(
FlitDW0::from_dw0(&bad_type).err().unwrap(),
TlpError::InvalidType
);
}
#[test]
fn flit_t1_short_slice_returns_invalid_length_error() {
assert_eq!(
FlitDW0::from_dw0(&[0x03, 0x00, 0x00]).err().unwrap(),
TlpError::InvalidLength
);
}
#[test]
fn flit_t2_nop_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_NOP).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::Nop);
assert_eq!(dw0.tlp_type.base_header_dw(), 1);
assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.total_bytes(), 4); }
#[test]
fn flit_t2_total_bytes_length_zero_encodes_1024dw() {
let dw0 = FlitDW0::from_dw0(&[0x40, 0x00, 0x00, 0x00]).unwrap();
assert_eq!(dw0.length, 0);
assert_eq!(dw0.total_bytes(), 3 * 4 + 1024 * 4);
}
#[test]
fn flit_t2_total_bytes_length_zero_read_still_no_payload() {
let dw0 = FlitDW0::from_dw0(&[0x03, 0x00, 0x00, 0x00]).unwrap();
assert_eq!(dw0.length, 0);
assert_eq!(dw0.total_bytes(), 3 * 4);
}
#[test]
fn flit_t2_mrd32_min_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_MRD32_MIN).unwrap();
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.length, 1);
assert_eq!(dw0.total_bytes(), 12);
}
#[test]
fn flit_t2_mrd32_a1_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_MRD32_A1_PASID).unwrap();
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 1); assert_eq!(dw0.total_bytes(), 16);
}
#[test]
fn flit_t2_mwr32_min_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_MWR32_MIN).unwrap();
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.length, 1);
assert_eq!(dw0.total_bytes(), 16);
}
#[test]
fn flit_t2_mwr32_partial_a1_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_MWR32_PARTIAL_A1).unwrap();
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 1);
assert_eq!(dw0.length, 1);
assert_eq!(dw0.total_bytes(), 20);
}
#[test]
fn flit_t2_iowr_a2_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_IOWR_A2).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::IoWrite);
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 1);
assert_eq!(dw0.length, 1);
assert_eq!(dw0.total_bytes(), 20);
}
#[test]
fn flit_t2_cfgwr0_a3_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_CFGWR0_A3).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::CfgWrite0);
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 1);
assert_eq!(dw0.length, 1);
assert_eq!(dw0.total_bytes(), 20);
}
#[test]
fn flit_t2_uiomrd64_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_UIOMRD64_MIN).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::UioMemRead);
assert_eq!(dw0.tlp_type.base_header_dw(), 4); assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.length, 2);
assert_eq!(dw0.total_bytes(), 16);
}
#[test]
fn flit_t2_uiomwr64_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_UIOMWR64_MIN).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::UioMemWrite);
assert_eq!(dw0.tlp_type.base_header_dw(), 4);
assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.length, 2);
assert_eq!(dw0.total_bytes(), 24);
}
#[test]
fn flit_t2_cas32_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_CAS32).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::CompareSwap32);
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.length, 2);
assert_eq!(dw0.total_bytes(), 20);
}
#[test]
fn flit_t2_dmwr32_type_and_sizes() {
let dw0 = FlitDW0::from_dw0(&FM_DMWR32).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::DeferrableMemWrite32);
assert_eq!(dw0.tlp_type.base_header_dw(), 3);
assert_eq!(dw0.ohc_count(), 0);
assert_eq!(dw0.length, 1);
assert_eq!(dw0.total_bytes(), 16);
}
#[test]
fn flit_t2_read_request_predicate() {
assert!(FlitTlpType::MemRead32.is_read_request());
assert!(FlitTlpType::UioMemRead.is_read_request());
assert!(!FlitTlpType::MemWrite32.is_read_request());
assert!(!FlitTlpType::IoWrite.is_read_request());
assert!(!FlitTlpType::CfgWrite0.is_read_request());
assert!(!FlitTlpType::FetchAdd32.is_read_request());
assert!(!FlitTlpType::CompareSwap32.is_read_request());
assert!(!FlitTlpType::DeferrableMemWrite32.is_read_request());
assert!(!FlitTlpType::Nop.is_read_request());
}
#[test]
fn flit_t2_local_prefix_base_header_is_1dw() {
let dw0 = FlitDW0::from_dw0(&FM_LOCAL_PREFIX_ONLY).unwrap();
assert_eq!(dw0.tlp_type, FlitTlpType::LocalTlpPrefix);
assert_eq!(dw0.tlp_type.base_header_dw(), 1);
assert_eq!(dw0.total_bytes(), 4);
}
#[test]
fn flit_t3_mrd32_a1_pasid_extraction() {
let dw0 = FlitDW0::from_dw0(&FM_MRD32_A1_PASID).unwrap();
let ohc_offset = dw0.tlp_type.base_header_dw() as usize * 4; let ohc = FlitOhcA::from_bytes(&FM_MRD32_A1_PASID[ohc_offset..]).unwrap();
assert_eq!(ohc.pasid, 0x12345);
assert_eq!(ohc.fdwbe, 0xF);
assert_eq!(ohc.ldwbe, 0x0);
}
#[test]
fn flit_t3_mwr32_partial_a1_be_extraction() {
let dw0 = FlitDW0::from_dw0(&FM_MWR32_PARTIAL_A1).unwrap();
let ohc_offset = dw0.tlp_type.base_header_dw() as usize * 4; let ohc = FlitOhcA::from_bytes(&FM_MWR32_PARTIAL_A1[ohc_offset..]).unwrap();
assert_eq!(ohc.pasid, 0);
assert_eq!(ohc.fdwbe, 0x3); assert_eq!(ohc.ldwbe, 0x0);
}
#[test]
fn flit_t3_iowr_a2_mandatory_ohc_present() {
let dw0 = FlitDW0::from_dw0(&FM_IOWR_A2).unwrap();
assert!(dw0.validate_mandatory_ohc().is_ok());
let ohc_offset = dw0.tlp_type.base_header_dw() as usize * 4; let ohc = FlitOhcA::from_bytes(&FM_IOWR_A2[ohc_offset..]).unwrap();
assert_eq!(ohc.fdwbe, 0xF);
assert_eq!(ohc.ldwbe, 0x0);
}
#[test]
fn flit_t3_iowr_missing_mandatory_ohc_a2() {
let mut bad = FM_IOWR_A2.to_vec();
bad[1] = 0x00; let dw0 = FlitDW0::from_dw0(&bad).unwrap();
assert_eq!(
dw0.validate_mandatory_ohc(),
Err(TlpError::MissingMandatoryOhc)
);
}
#[test]
fn flit_t3_cfgwr0_a3_mandatory_ohc_present() {
let dw0 = FlitDW0::from_dw0(&FM_CFGWR0_A3).unwrap();
assert!(dw0.validate_mandatory_ohc().is_ok());
let ohc_offset = dw0.tlp_type.base_header_dw() as usize * 4; let ohc = FlitOhcA::from_bytes(&FM_CFGWR0_A3[ohc_offset..]).unwrap();
assert_eq!(ohc.fdwbe, 0xF);
assert_eq!(ohc.ldwbe, 0x0);
}
#[test]
fn flit_t3_cfgwr_missing_mandatory_ohc_a3() {
let mut bad = FM_CFGWR0_A3.to_vec();
bad[1] = 0x00; let dw0 = FlitDW0::from_dw0(&bad).unwrap();
assert_eq!(
dw0.validate_mandatory_ohc(),
Err(TlpError::MissingMandatoryOhc)
);
}
#[test]
fn flit_t4_stream_fragment_0_offsets() {
let entries: Vec<_> = FlitStreamWalker::new(&FM_STREAM_FRAGMENT_0)
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(entries.len(), 4);
assert_eq!(entries[0], (0, FlitTlpType::Nop, 4));
assert_eq!(entries[1], (4, FlitTlpType::MemRead32, 12));
assert_eq!(entries[2], (16, FlitTlpType::MemWrite32, 16));
assert_eq!(entries[3], (32, FlitTlpType::UioMemRead, 16));
}
#[test]
fn flit_t4_stream_walker_returns_none_at_end() {
let mut walker = FlitStreamWalker::new(&FM_NOP);
assert!(walker.next().is_some()); assert!(walker.next().is_none()); }
#[test]
fn flit_t4_stream_truncated_payload_error() {
let mut truncated = FM_UIOMWR64_MIN.to_vec();
truncated.pop();
let result: Result<Vec<_>, _> = FlitStreamWalker::new(&truncated).collect();
assert_eq!(result.err().unwrap(), TlpError::InvalidLength);
}
#[test]
fn flit_t5_end_to_end_mrd32_min() {
let pkt = TlpPacket::new(FM_MRD32_MIN.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemRead32));
assert!(pkt.data().is_empty());
}
#[test]
fn flit_t5_end_to_end_mwr32_min() {
let pkt = TlpPacket::new(FM_MWR32_MIN.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::MemWrite32));
assert_eq!(pkt.data(), [0xDE, 0xAD, 0xBE, 0xEF]);
}
#[test]
fn flit_t5_end_to_end_cas32() {
let pkt = TlpPacket::new(FM_CAS32.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::CompareSwap32));
assert_eq!(
pkt.data(),
[
0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, ]
);
}
#[test]
fn flit_t5_end_to_end_dmwr32() {
let pkt = TlpPacket::new(FM_DMWR32.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::DeferrableMemWrite32));
assert_eq!(pkt.data(), [0xC0, 0xFF, 0xEE, 0x00]);
}
#[test]
fn flit_t5_end_to_end_uiomwr64() {
let pkt = TlpPacket::new(FM_UIOMWR64_MIN.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::UioMemWrite));
assert_eq!(
pkt.data(),
[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,]
);
}
#[test]
fn flit_t5_nop_has_no_data() {
let pkt = TlpPacket::new(FM_NOP.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::Nop));
assert!(pkt.data().is_empty());
}
#[test]
fn flit_t5_nonflit_packet_get_flit_type_returns_none() {
let pkt = TlpPacket::new(vec![0x00, 0x00, 0x00, 0x01], TlpMode::NonFlit).unwrap();
assert_eq!(pkt.flit_type(), None);
}
#[test]
fn flit_t5_fetchadd32_operand_value_in_payload() {
let pkt = TlpPacket::new(FM_FETCHADD32.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::FetchAdd32));
assert_eq!(pkt.data().len(), 4, "FetchAdd32 has 1 DW operand");
let operand = u32::from_be_bytes([pkt.data()[0], pkt.data()[1], pkt.data()[2], pkt.data()[3]]);
assert_eq!(
operand, 0x01000000,
"FM_FETCHADD32 addend should be 0x01000000"
);
}
#[test]
fn flit_t5_cas32_operand_values_in_payload() {
let pkt = TlpPacket::new(FM_CAS32.to_vec(), TlpMode::Flit).unwrap();
assert_eq!(pkt.flit_type(), Some(FlitTlpType::CompareSwap32));
assert_eq!(
pkt.data().len(),
8,
"CAS32 has 2 DW payload (compare + swap)"
);
let compare = u32::from_be_bytes([pkt.data()[0], pkt.data()[1], pkt.data()[2], pkt.data()[3]]);
let swap = u32::from_be_bytes([pkt.data()[4], pkt.data()[5], pkt.data()[6], pkt.data()[7]]);
assert_eq!(compare, 0x11111111, "FM_CAS32 compare operand");
assert_eq!(swap, 0x22222222, "FM_CAS32 swap operand");
}