1use crate::relocations::{ArchitectureRelocationEncoding, Relocation, RelocationType, RelocationSize, RelocationKind, RelocationEncoding, ImpossibleRelocation, fits_signed_bitfield};
28use byteorder::{ByteOrder, LittleEndian};
29use std::convert::TryFrom;
30use crate::Register;
31
32#[derive(Debug, Clone, Copy)]
33#[allow(missing_docs)]
34enum RiscvRelocationEncoding {
35 B,
38 J,
41 BC,
44 JC,
47 HI20,
50 LO12,
53 LO12S,
56 SPLIT32,
59 SPLIT32S,
62}
63
64impl ArchitectureRelocationEncoding for RiscvRelocationEncoding {
65 fn decode(code: u8) -> Self {
66 match code {
67 0 => Self::B,
68 1 => Self::J,
69 2 => Self::BC,
70 3 => Self::JC,
71 4 => Self::HI20,
72 5 => Self::LO12,
73 6 => Self::LO12S,
74 7 => Self::SPLIT32,
75 8 => Self::SPLIT32S,
76 n => panic!("Invalid complex relocation code {n} given for the current architecture")
77 }
78 }
79}
80
81impl RiscvRelocationEncoding {
82 fn bitsize(&self) -> (u8, u8) {
83 match self {
84 Self::B => (12, 1),
85 Self::J => (20, 1),
86 Self::BC => (9, 1),
87 Self::JC => (12, 1),
88
89 Self::HI20 => (32, 0),
90 Self::LO12 => (32, 0),
91 Self::LO12S => (32, 0),
92
93 Self::SPLIT32 => (32, 0),
94 Self::SPLIT32S => (32, 0),
95 }
96 }
97}
98
99#[derive(Debug, Clone, Copy)]
101pub struct RiscvRelocation(RelocationType<RiscvRelocationEncoding>);
102
103impl Relocation for RiscvRelocation {
104 fn from_encoding(encoding: u8) -> Self {
105 RiscvRelocation(RelocationType::decode(encoding))
106 }
107 fn from_size(kind: RelocationKind, size: RelocationSize) -> Self {
108 RiscvRelocation(RelocationType::from_size(kind, size))
109 }
110 fn size(&self) -> usize {
111 match self.0.encoding {
112 RelocationEncoding::Simple(s) => s.size(),
113 RelocationEncoding::ArchSpecific(c) => match c {
114 RiscvRelocationEncoding::BC
115 | RiscvRelocationEncoding::JC => 2,
116 RiscvRelocationEncoding::B
117 | RiscvRelocationEncoding::J
118 | RiscvRelocationEncoding::HI20
119 | RiscvRelocationEncoding::LO12
120 | RiscvRelocationEncoding::LO12S => 4,
121 RiscvRelocationEncoding::SPLIT32
122 | RiscvRelocationEncoding::SPLIT32S => 8
123 }
124 }
125 }
126 fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
127 match self.0.encoding {
128 RelocationEncoding::Simple(s) => s.write_value(buf, value),
129 RelocationEncoding::ArchSpecific(c) => {
130 let value = i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?;
132
133 let (bits, scaling) = c.bitsize();
134 let mask = (1i64 << scaling) - 1;
135 match c {
144 RiscvRelocationEncoding::HI20
145 | RiscvRelocationEncoding::LO12
146 | RiscvRelocationEncoding::LO12S
147 | RiscvRelocationEncoding::SPLIT32
148 | RiscvRelocationEncoding::SPLIT32S => {
149 if value < -0x8000_0800 || value > 0x7FFF_F7FF {
150 return Err(ImpossibleRelocation { } );
151 }
152 },
153 _ => {
154 if !fits_signed_bitfield(value, bits) || (value & mask) != 0 {
155 return Err(ImpossibleRelocation { } );
156 }
157 }
158 }
159
160 let val_cast = value as u32;
162
163 match c {
164 RiscvRelocationEncoding::B => {
165 let mut instr = LittleEndian::read_u32(buf);
166 instr &= 0x01FF_F07F;
167
168 instr |= ((val_cast >> 12) & 0x1) << 31;
169 instr |= ((val_cast >> 5) & 0x3F) << 25;
170 instr |= ((val_cast >> 1) & 0xF) << 8;
171 instr |= ((val_cast >> 11) & 0x1) << 7;
172
173 LittleEndian::write_u32(buf, instr);
174 },
175 RiscvRelocationEncoding::J => {
176 let mut instr = LittleEndian::read_u32(buf);
177 instr &= 0x0000_0FFF;
178
179 instr |= ((val_cast >> 20) & 0x1) << 31;
180 instr |= ((val_cast >> 1) & 0x3FF) << 21;
181 instr |= ((val_cast >> 11) & 0x1) << 20;
182 instr |= ((val_cast >> 12) & 0xFF) << 12;
183
184 LittleEndian::write_u32(buf, instr);
185 },
186 RiscvRelocationEncoding::BC => {
187 let mut instr = LittleEndian::read_u16(buf);
188 instr &= 0xE383;
189
190 instr |= (((val_cast >> 8) & 0x1) as u16) << 12;
191 instr |= (((val_cast >> 3) & 0x3) as u16) << 10;
192 instr |= (((val_cast >> 6) & 0x3) as u16) << 5;
193 instr |= (((val_cast >> 1) & 0x3) as u16) << 3;
194 instr |= (((val_cast >> 5) & 0x1) as u16) << 2;
195
196 LittleEndian::write_u16(buf, instr);
197 },
198 RiscvRelocationEncoding::JC => {
199 let mut instr = LittleEndian::read_u16(buf);
200 instr &= 0xE003;
201
202 instr |= (((val_cast >> 11) & 0x1) as u16) << 12;
203 instr |= (((val_cast >> 4) & 0x1) as u16) << 11;
204 instr |= (((val_cast >> 8) & 0x3) as u16) << 9;
205 instr |= (((val_cast >> 10) & 0x1) as u16) << 8;
206 instr |= (((val_cast >> 6) & 0x1) as u16) << 7;
207 instr |= (((val_cast >> 7) & 0x1) as u16) << 6;
208 instr |= (((val_cast >> 1) & 0x7) as u16) << 3;
209 instr |= (((val_cast >> 5) & 0x1) as u16) << 2;
210
211 LittleEndian::write_u16(buf, instr);
212 },
213 RiscvRelocationEncoding::HI20 => {
214 let mut instr = LittleEndian::read_u32(buf);
215 instr &= 0x0000_0FFF;
216
217 let val_round: u32 = val_cast.wrapping_add(0x800);
218 instr |= val_round & 0xFFFF_F000;
219
220 LittleEndian::write_u32(buf, instr);
221 },
222 RiscvRelocationEncoding::LO12 => {
223 let mut instr = LittleEndian::read_u32(buf);
224 instr &= 0x000F_FFFF;
225
226 instr |= (val_cast & 0xFFF) << 20;
227
228 LittleEndian::write_u32(buf, instr);
229 },
230 RiscvRelocationEncoding::LO12S => {
231 let mut instr = LittleEndian::read_u32(buf);
232 instr &= 0x01FF_F07F;
233
234 instr |= (val_cast & 0x1F) << 7;
235 instr |= ((val_cast >> 5) & 0x7F) << 25;
236
237 LittleEndian::write_u32(buf, instr);
238 },
239 RiscvRelocationEncoding::SPLIT32 => {
240 let mut instr1 = LittleEndian::read_u32(&buf[..4]);
241 let mut instr2 = LittleEndian::read_u32(&buf[4..]);
242 instr1 &= 0x0000_0FFF;
243 instr2 &= 0x000F_FFFF;
244
245 let val_round: u32 = val_cast.wrapping_add(0x800);
246 instr1 |= val_round & 0xFFFF_F000;
247 instr2 |= (val_cast & 0xFFF) << 20;
248
249 LittleEndian::write_u32(&mut buf[..4], instr1);
250 LittleEndian::write_u32(&mut buf[4..], instr2);
251 },
252 RiscvRelocationEncoding::SPLIT32S => {
253 let mut instr1 = LittleEndian::read_u32(&buf[..4]);
254 let mut instr2 = LittleEndian::read_u32(&buf[4..]);
255 instr1 &= 0x0000_0FFF;
256 instr2 &= 0x01FF_F07F;
257
258 let val_round: u32 = val_cast.wrapping_add(0x800);
259 instr1 |= val_round & 0xFFFF_F000;
260 instr2 |= (val_cast & 0x1F) << 7;
261 instr2 |= ((val_cast >> 5) & 0x7F) << 25;
262
263 LittleEndian::write_u32(&mut buf[..4], instr1);
264 LittleEndian::write_u32(&mut buf[4..], instr2);
265 },
266 }
267
268 Ok(())
269 }
270 }
271 }
272 fn read_value(&self, buf: &[u8]) -> isize {
273 match self.0.encoding {
274 RelocationEncoding::Simple(s) => s.read_value(buf),
275 RelocationEncoding::ArchSpecific(c) => {
276 let bits;
277 let mut unpacked;
278
279 match c {
280 RiscvRelocationEncoding::B => {
281 bits = 12;
282 let instr = LittleEndian::read_u32(buf);
283
284 unpacked = ((instr >> 31) & 0x1) << 12;
285 unpacked |= ((instr >> 25) & 0x3F) << 5;
286 unpacked |= ((instr >> 8) & 0xF) << 1;
287 unpacked |= ((instr >> 7) & 0x1) << 11;
288 },
289 RiscvRelocationEncoding::J => {
290 bits = 20;
291 let instr = LittleEndian::read_u32(buf);
292
293 unpacked = ((instr >> 31) & 0x1) << 20;
294 unpacked |= ((instr >> 21) & 0x3FF) << 1;
295 unpacked |= ((instr >> 20) & 0x1) << 11;
296 unpacked |= ((instr >> 12) & 0xFF) << 12;
297 },
298 RiscvRelocationEncoding::BC => {
299 bits = 9;
300 let instr = u32::from(LittleEndian::read_u16(buf));
301
302 unpacked = ((instr >> 12) & 0x1) << 8;
303 unpacked |= ((instr >> 10) & 0x3) << 3;
304 unpacked |= ((instr >> 5) & 0x3) << 6;
305 unpacked |= ((instr >> 3) & 0x3) << 1;
306 unpacked |= ((instr >> 2) & 0x1) << 5;
307 },
308 RiscvRelocationEncoding::JC => {
309 bits = 12;
310 let instr = u32::from(LittleEndian::read_u16(buf));
311
312 unpacked = ((instr >> 12) & 0x1) << 11;
313 unpacked |= ((instr >> 11) & 0x1) << 4;
314 unpacked |= ((instr >> 9) & 0x3) << 8;
315 unpacked |= ((instr >> 8) & 0x1) << 10;
316 unpacked |= ((instr >> 7) & 0x1) << 6;
317 unpacked |= ((instr >> 6) & 0x1) << 7;
318 unpacked |= ((instr >> 3) & 0x7) << 1;
319 unpacked |= ((instr >> 2) & 0x1) << 5;
320 },
321 RiscvRelocationEncoding::HI20 => {
322 bits = 32;
323 let instr = LittleEndian::read_u32(buf);
324
325 unpacked = ((instr >> 12) & 0xFFFFF) << 12;
326 },
332 RiscvRelocationEncoding::LO12 => {
333 bits = 12;
334 let instr = LittleEndian::read_u32(buf);
335
336 unpacked = (instr >> 20) & 0xFFF;
337 },
338 RiscvRelocationEncoding::LO12S => {
339 bits = 12;
340 let instr = LittleEndian::read_u32(buf);
341
342 unpacked = (instr >> 7) & 0x1F;
343 unpacked |= ((instr >> 25) & 0x7F) << 5;
344 },
345 RiscvRelocationEncoding::SPLIT32 => {
346 bits = 32;
347 let instr1 = LittleEndian::read_u32(&buf[..4]);
348 let instr2 = LittleEndian::read_u32(&buf[4..]);
349
350 unpacked = ((instr1 >> 12) & 0xFFFFF) << 12;
351 let mut lower: u32 = (instr2 >> 20) & 0xFFF;
352
353 lower = (lower ^ 0x800).wrapping_sub(0x800);
355 unpacked = unpacked.wrapping_add(lower)
356
357 },
358 RiscvRelocationEncoding::SPLIT32S => {
359 bits = 32;
360 let instr1 = LittleEndian::read_u32(&buf[..4]);
361 let instr2 = LittleEndian::read_u32(&buf[4..]);
362
363 unpacked = ((instr1 >> 12) & 0xFFFFF) << 12;
364 let mut lower: u32 = (instr2 >> 7) & 0x1F;
365 lower |= ((instr2 >> 25) & 0x7F) << 5;
366
367 lower = (lower ^ 0x800).wrapping_sub(0x800);
369 unpacked = unpacked.wrapping_add(lower)
370 },
371 }
372
373 let offset = 1u64 << (bits - 1);
375 let value: u64 = (unpacked as u64 ^ offset).wrapping_sub(offset);
376
377 value as i64 as isize
378 }
379 }
380 }
381 fn kind(&self) -> RelocationKind {
382 self.0.kind
383 }
384 fn page_size() -> usize {
385 4096
386 }
387}
388
389pub type Assembler = crate::Assembler<RiscvRelocation>;
391pub type AssemblyModifier<'a> = crate::Modifier<'a, RiscvRelocation>;
393pub type UncommittedModifier<'a> = crate::UncommittedModifier<'a>;
395
396#[inline(never)]
401pub fn immediate_out_of_range_unsigned_32(immediate: u32) -> ! {
402 panic!("Cannot assemble this RISC-V instruction. Immediate {immediate} is out of range.")
403}
404
405#[inline(never)]
407pub fn immediate_out_of_range_signed_32(immediate: i32) -> ! {
408 panic!("Cannot assemble this RISC-V instruction. Immediate {immediate} is out of range.")
409}
410#[inline(never)]
412pub fn immediate_out_of_range_unsigned_64(immediate: u64) -> ! {
413 panic!("Cannot assemble this RISC-V instruction. Immediate {immediate} is out of range.")
414}
415
416#[inline(never)]
418pub fn immediate_out_of_range_signed_64(immediate: i64) -> ! {
419 panic!("Cannot assemble this RISC-V instruction. Immediate {immediate} is out of range.")
420}
421
422#[inline(never)]
424pub fn invalid_register(register: u8) -> ! {
425 panic!("Cannot assemble this RISC-V instruction. Register x{register} cannot be encoded.")
426}
427
428
429#[allow(missing_docs)]
432#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
433pub enum RX {
434 X0 = 0x00, X1 = 0x01, X2 = 0x02, X3 = 0x03,
435 X4 = 0x04, X5 = 0x05, X6 = 0x06, X7 = 0x07,
436 X8 = 0x08, X9 = 0x09, X10= 0x0A, X11= 0x0B,
437 X12= 0x0C, X13= 0x0D, X14= 0x0E, X15= 0x0F,
438 X16= 0x10, X17= 0x11, X18= 0x12, X19= 0x13,
439 X20= 0x14, X21= 0x15, X22= 0x16, X23= 0x17,
440 X24= 0x18, X25= 0x19, X26= 0x1A, X27= 0x1B,
441 X28= 0x1C, X29= 0x1D, X30= 0x1E, X31= 0x1F,
442}
443reg_impls!(RX);
444
445#[allow(missing_docs)]
447#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
448pub enum RF {
449 F0 = 0x00, F1 = 0x01, F2 = 0x02, F3 = 0x03,
450 F4 = 0x04, F5 = 0x05, F6 = 0x06, F7 = 0x07,
451 F8 = 0x08, F9 = 0x09, F10= 0x0A, F11= 0x0B,
452 F12= 0x0C, F13= 0x0D, F14= 0x0E, F15= 0x0F,
453 F16= 0x10, F17= 0x11, F18= 0x12, F19= 0x13,
454 F20= 0x14, F21= 0x15, F22= 0x16, F23= 0x17,
455 F24= 0x18, F25= 0x19, F26= 0x1A, F27= 0x1B,
456 F28= 0x1C, F29= 0x1D, F30= 0x1E, F31= 0x1F,
457}
458reg_impls!(RF);
459
460
461#[cfg(test)]
462mod tests {
463 use super::RX::*;
464 use crate::Register;
465
466 #[test]
467 fn reg_code() {
468 assert_eq!(X2.code(), 2);
469 }
470
471 #[test]
472 fn reg_code_from() {
473 assert_eq!(u8::from(X24), 0x18);
474 }
475}