bloqade_lanes_bytecode_core/arch/
addr.rs

1//! Bit-packed address types for bytecode instructions.
2//!
3//! These types encode device-level addresses into compact integer
4//! representations used in the 16-byte instruction format.
5
6/// Atom movement direction along a transport bus.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[repr(u8)]
9pub enum Direction {
10    /// Movement from source to destination (value 0).
11    Forward = 0,
12    /// Movement from destination to source (value 1).
13    Backward = 1,
14}
15
16/// Type of transport bus used for an atom move operation.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18#[repr(u8)]
19pub enum MoveType {
20    /// Moves atoms between sites within a word (value 0).
21    SiteBus = 0,
22    /// Moves atoms between words (value 1).
23    WordBus = 1,
24}
25
26/// Bit-packed atom location address (word + site).
27///
28/// Encodes `word_id` (16 bits) and `site_id` (16 bits) into a 32-bit word.
29///
30/// Layout: `[word_id:16][site_id:16]`
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub struct LocationAddr {
33    pub word_id: u32,
34    pub site_id: u32,
35}
36
37impl LocationAddr {
38    /// Encode to a 32-bit packed integer.
39    ///
40    /// Layout: `[word_id:16][site_id:16]`
41    pub fn encode(&self) -> u32 {
42        ((self.word_id as u16 as u32) << 16) | (self.site_id as u16 as u32)
43    }
44
45    /// Decode a 32-bit packed integer into a `LocationAddr`.
46    pub fn decode(bits: u32) -> Self {
47        Self {
48            word_id: (bits >> 16) & 0xFFFF,
49            site_id: bits & 0xFFFF,
50        }
51    }
52}
53
54/// Bit-packed lane address for atom move operations.
55///
56/// Encodes direction (1 bit), move type (1 bit), word_id (16 bits),
57/// site_id (16 bits), and bus_id (16 bits) across two 32-bit data words.
58///
59/// Layout:
60/// - data0: `[word_id:16][site_id:16]`
61/// - data1: `[dir:1][mt:1][pad:14][bus_id:16]`
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub struct LaneAddr {
64    pub direction: Direction,
65    pub move_type: MoveType,
66    pub word_id: u32,
67    pub site_id: u32,
68    pub bus_id: u32,
69}
70
71impl LaneAddr {
72    /// Encode to two 32-bit data words `(data0, data1)`.
73    pub fn encode(&self) -> (u32, u32) {
74        let data0 = ((self.word_id as u16 as u32) << 16) | (self.site_id as u16 as u32);
75        let data1 = ((self.direction as u32) << 31)
76            | ((self.move_type as u32) << 30)
77            | (self.bus_id as u16 as u32);
78        (data0, data1)
79    }
80
81    /// Encode to a single 64-bit packed integer (`data0 | (data1 << 32)`).
82    pub fn encode_u64(&self) -> u64 {
83        let (d0, d1) = self.encode();
84        (d0 as u64) | ((d1 as u64) << 32)
85    }
86
87    /// Decode two 32-bit data words into a `LaneAddr`.
88    pub fn decode(data0: u32, data1: u32) -> Self {
89        let direction = if (data1 >> 31) & 1 == 0 {
90            Direction::Forward
91        } else {
92            Direction::Backward
93        };
94        let move_type = if (data1 >> 30) & 1 == 0 {
95            MoveType::SiteBus
96        } else {
97            MoveType::WordBus
98        };
99        Self {
100            direction,
101            move_type,
102            word_id: (data0 >> 16) & 0xFFFF,
103            site_id: data0 & 0xFFFF,
104            bus_id: data1 & 0xFFFF,
105        }
106    }
107
108    /// Decode a 64-bit packed integer into a `LaneAddr`.
109    pub fn decode_u64(bits: u64) -> Self {
110        Self::decode(bits as u32, (bits >> 32) as u32)
111    }
112}
113
114/// Bit-packed zone address.
115///
116/// Encodes a zone identifier (16 bits) into a 32-bit value.
117///
118/// Layout: `[pad:16][zone_id:16]`
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub struct ZoneAddr {
121    pub zone_id: u32,
122}
123
124impl ZoneAddr {
125    /// Encode to a 32-bit packed integer.
126    pub fn encode(&self) -> u32 {
127        self.zone_id as u16 as u32
128    }
129
130    /// Decode a 32-bit packed integer into a `ZoneAddr`.
131    pub fn decode(bits: u32) -> Self {
132        Self {
133            zone_id: bits & 0xFFFF,
134        }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn test_location_addr_round_trip() {
144        let addr = LocationAddr {
145            word_id: 0xABCD,
146            site_id: 0x1234,
147        };
148        let bits = addr.encode();
149        assert_eq!(bits, 0xABCD_1234);
150        assert_eq!(LocationAddr::decode(bits), addr);
151    }
152
153    #[test]
154    fn test_location_addr_zero() {
155        let addr = LocationAddr {
156            word_id: 0,
157            site_id: 0,
158        };
159        assert_eq!(addr.encode(), 0);
160        assert_eq!(LocationAddr::decode(0), addr);
161    }
162
163    #[test]
164    fn test_lane_addr_round_trip() {
165        let addr = LaneAddr {
166            direction: Direction::Backward,
167            move_type: MoveType::WordBus,
168            word_id: 0x1234,
169            site_id: 0x5678,
170            bus_id: 0x9ABC,
171        };
172        let (data0, data1) = addr.encode();
173        assert_eq!(LaneAddr::decode(data0, data1), addr);
174
175        // Check bit positions in data0
176        assert_eq!((data0 >> 16) & 0xFFFF, 0x1234); // word_id
177        assert_eq!(data0 & 0xFFFF, 0x5678); // site_id
178
179        // Check bit positions in data1
180        assert_eq!((data1 >> 31) & 1, 1); // direction = Backward
181        assert_eq!((data1 >> 30) & 1, 1); // move_type = WordBus
182        assert_eq!(data1 & 0xFFFF, 0x9ABC); // bus_id
183    }
184
185    #[test]
186    fn test_lane_addr_forward_sitebus() {
187        let addr = LaneAddr {
188            direction: Direction::Forward,
189            move_type: MoveType::SiteBus,
190            word_id: 0,
191            site_id: 0,
192            bus_id: 1,
193        };
194        let (data0, data1) = addr.encode();
195        assert_eq!(data0, 0);
196        assert_eq!(data1, 1);
197        assert_eq!(LaneAddr::decode(data0, data1), addr);
198    }
199
200    #[test]
201    fn test_lane_addr_u64_round_trip() {
202        let addr = LaneAddr {
203            direction: Direction::Backward,
204            move_type: MoveType::WordBus,
205            word_id: 1,
206            site_id: 0,
207            bus_id: 0,
208        };
209        let packed = addr.encode_u64();
210        assert_eq!(LaneAddr::decode_u64(packed), addr);
211    }
212
213    #[test]
214    fn test_zone_addr_round_trip() {
215        let addr = ZoneAddr { zone_id: 42 };
216        let bits = addr.encode();
217        assert_eq!(bits, 42);
218        assert_eq!(ZoneAddr::decode(bits), addr);
219    }
220
221    #[test]
222    fn test_zone_addr_max() {
223        let addr = ZoneAddr { zone_id: 0xFFFF };
224        let bits = addr.encode();
225        assert_eq!(bits, 0xFFFF);
226        assert_eq!(ZoneAddr::decode(bits), addr);
227    }
228}