Skip to content

Commit 322a217

Browse files
committed
Make RISC-V instructions accept signed immediates
Now instructions with immediates (both for branches and alu operations) take i32s. There's also no more attempts to try and take a smaller number which may be misleading. I had to roll my own implementation for signed N bit integers to pass into the instructions properly, since rust does not have arbitrary bit widths unfortunately. Needs more testing which I will do via another one of my projects that relies on this.
1 parent 0cd2b0e commit 322a217

File tree

2 files changed

+115
-40
lines changed

2 files changed

+115
-40
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "dasm"
33
authors = ["David Cruz <[email protected]>"]
44
description = "A tiny, zero dependency assembler"
5-
version = "0.2.0"
5+
version = "0.3.0"
66
edition = "2021"
77
keywords = ["assembler", "jit", "dasm", "x86", "codegen"]
88
categories = ["os", "no-std", "no-std::no-alloc"]

src/tier/raw/rv32/mod.rs

Lines changed: 114 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ macro_rules! bitcat {
77
(bitcat! { acc($a) $b($e) } | bitcat! { acc($a - $b) $($rest)+ })
88
};
99

10+
( acc($a:expr) signed $b:literal($e:expr), $($rest:tt)+ ) => {
11+
(bitcat! { acc($a) signed $b($e) } | bitcat! { acc($a - $b) $($rest)+ })
12+
};
13+
14+
( acc($a:expr) signed $b:literal($e:expr) ) => {
15+
(i32_to_iN::<$b>($e)) << const { $a - $b }
16+
};
17+
1018
( acc($a:expr) $b:literal($e:expr) ) => {
1119
($e as u32 & const { (1 << $b) - 1 }) << const { $a - $b }
1220
};
@@ -16,126 +24,193 @@ macro_rules! bitcat {
1624
};
1725
}
1826

27+
macro_rules! bits {
28+
($start:literal .. $end:literal, $num:expr) => {
29+
($num >> $start) & ((1 << ($end - $start)) - 1)
30+
};
31+
32+
($start:literal ..= $end:literal, $num:expr) => {
33+
($num >> $start) & ((1 << ($end - $start + 1)) - 1)
34+
};
35+
36+
($bit:literal, $num:expr) => {
37+
($num >> $bit) & 1
38+
};
39+
}
40+
41+
#[allow(non_snake_case)]
42+
fn i32_to_iN<const N: u32>(from: i32) -> u32 {
43+
let lower_bits = (1 << (N - 1)) - 1;
44+
45+
if from.is_negative() {
46+
(from as u32) & lower_bits | (1 << (N - 1))
47+
} else {
48+
(from as u32) & lower_bits
49+
}
50+
}
51+
52+
#[test]
53+
fn test_i32_reinterpret() {
54+
assert_eq!(i32_to_iN::<4>(-1), 0b1111);
55+
assert_eq!(i32_to_iN::<5>(-1), 0b11111);
56+
assert_eq!(i32_to_iN::<4>(-2), 0b1110);
57+
assert_eq!(i32_to_iN::<4>(1), 0b0001);
58+
assert_eq!(i32_to_iN::<4>(0), 0b0000);
59+
assert_eq!(i32_to_iN::<4>(-3), 0b1101);
60+
assert_eq!(i32_to_iN::<4>(-4), 0b1100);
61+
assert_eq!(i32_to_iN::<4>(2), 0b0010);
62+
assert_eq!(i32_to_iN::<4>(3), 0b0011);
63+
assert_eq!(i32_to_iN::<5>(-16), 0b10000);
64+
assert_eq!(i32_to_iN::<5>(-15), 0b10001);
65+
assert_eq!(i32_to_iN::<5>(15), 0b01111);
66+
assert_eq!(i32_to_iN::<6>(-32), 0b100000);
67+
assert_eq!(i32_to_iN::<6>(31), 0b011111);
68+
}
69+
70+
#[test]
71+
#[rustfmt::skip]
72+
fn test_bitcat_signed() {
73+
assert_eq!(bitcat! { acc(8) signed 4(0), 4(0) }, 0b0000_0000);
74+
assert_eq!(bitcat! { acc(8) signed 4(-1), 4(0) }, 0b1111_0000);
75+
assert_eq!(bitcat! { acc(8) signed 4(-2), 4(1) }, 0b1110_0001);
76+
assert_eq!(bitcat! { acc(8) signed 4(2), 4(3) }, 0b0010_0011);
77+
assert_eq!(bitcat! { acc(8) signed 5(-16), 3(7) }, 0b10000_111);
78+
assert_eq!(bitcat! { acc(8) signed 6(-32), 2(3) }, 0b100000_11);
79+
assert_eq!(bitcat! { acc(16) signed 8(-128), 8(255) }, 0b10000000_11111111);
80+
assert_eq!(bitcat! { acc(16) signed 12(-2048), 4(15) }, 0b100000000000_1111);
81+
assert_eq!(bitcat! { acc(32) signed 20(-524288), 12(0xFFF) }, 0b10000000000000000000_111111111111);
82+
}
83+
1984
pub(crate) use bitcat;
2085

2186
#[inline]
22-
pub fn lui(rd: u8, imm: u32) -> u32 {
23-
bitcat! { 20(imm), 5(rd), 7(0b0110111) }
87+
pub fn lui(rd: u8, imm: i32) -> u32 {
88+
bitcat! { signed 20(imm), 5(rd), 7(0b0110111) }
2489
}
2590

2691
#[inline]
27-
pub fn auipc(rd: u8, imm: u32) -> u32 {
28-
bitcat! { 20(imm), 5(rd), 7(0b0010111) }
92+
pub fn auipc(rd: u8, imm: i32) -> u32 {
93+
bitcat! { signed 20(imm), 5(rd), 7(0b0010111) }
2994
}
3095

3196
#[inline]
32-
pub fn jal(rd: u8, imm: u32) -> u32 {
97+
pub fn jal(rd: u8, imm: i32) -> u32 {
98+
let imm = i32_to_iN::<20>(imm);
3399
bitcat! { 1(imm >> 20), 10(imm >> 1), 1(imm >> 11), 8(imm >> 12), 5(rd), 7(0b1101111) }
34100
}
35101

36102
#[inline]
37-
pub fn jalr(rd: u8, rs1: u8, imm: u16) -> u32 {
38-
bitcat! { 12(imm), 5(rs1), 3(0b000), 5(rd), 7(0b1100111) }
103+
pub fn jalr(rd: u8, rs1: u8, imm: i32) -> u32 {
104+
bitcat! { signed 12(imm), 5(rs1), 3(0b000), 5(rd), 7(0b1100111) }
39105
}
40106

41107
#[inline]
42-
pub fn beq(rs1: u8, rs2: u8, imm: u16) -> u32 {
108+
pub fn beq(rs1: u8, rs2: u8, imm: i32) -> u32 {
109+
let imm = i32_to_iN::<12>(imm);
43110
bitcat! { 1(imm >> 12), 6(imm >> 5), 5(rs2), 5(rs1), 3(0b000), 4(imm >> 1), 1(imm >> 11), 7(0b1100011) }
44111
}
45112

46113
#[inline]
47-
pub fn bne(rs1: u8, rs2: u8, imm: u16) -> u32 {
114+
pub fn bne(rs1: u8, rs2: u8, imm: i32) -> u32 {
115+
let imm = i32_to_iN::<12>(imm);
48116
bitcat! { 1(imm >> 12), 6(imm >> 5), 5(rs2), 5(rs1), 3(0b001), 4(imm >> 1), 1(imm >> 11), 7(0b1100011) }
49117
}
50118

51119
#[inline]
52-
pub fn blt(rs1: u8, rs2: u8, imm: u16) -> u32 {
120+
pub fn blt(rs1: u8, rs2: u8, imm: i32) -> u32 {
121+
let imm = i32_to_iN::<12>(imm);
53122
bitcat! { 1(imm >> 12), 6(imm >> 5), 5(rs2), 5(rs1), 3(0b100), 4(imm >> 1), 1(imm >> 11), 7(0b1100011) }
54123
}
55124

56125
#[inline]
57-
pub fn bge(rs1: u8, rs2: u8, imm: u16) -> u32 {
126+
pub fn bge(rs1: u8, rs2: u8, imm: i32) -> u32 {
127+
let imm = i32_to_iN::<12>(imm);
58128
bitcat! { 1(imm >> 12), 6(imm >> 5), 5(rs2), 5(rs1), 3(0b101), 4(imm >> 1), 1(imm >> 11), 7(0b1100011) }
59129
}
60130

61131
#[inline]
62-
pub fn bltu(rs1: u8, rs2: u8, imm: u16) -> u32 {
132+
pub fn bltu(rs1: u8, rs2: u8, imm: i32) -> u32 {
133+
let imm = i32_to_iN::<12>(imm);
63134
bitcat! { 1(imm >> 12), 6(imm >> 5), 5(rs2), 5(rs1), 3(0b110), 4(imm >> 1), 1(imm >> 11), 7(0b1100011) }
64135
}
65136

66137
#[inline]
67-
pub fn bgeu(rs1: u8, rs2: u8, imm: u16) -> u32 {
138+
pub fn bgeu(rs1: u8, rs2: u8, imm: i32) -> u32 {
139+
let imm = i32_to_iN::<12>(imm);
68140
bitcat! { 1(imm >> 12), 6(imm >> 5), 5(rs2), 5(rs1), 3(0b111), 4(imm >> 1), 1(imm >> 11), 7(0b1100011) }
69141
}
70142

71143
#[inline]
72-
pub fn lb(rd: u8, rs1: u8, imm: u16) -> u32 {
73-
bitcat! { 12(imm), 5(rs1), 3(0b000), 5(rd), 7(0b0000011) }
144+
pub fn lb(rd: u8, rs1: u8, imm: i32) -> u32 {
145+
bitcat! { signed 12(imm), 5(rs1), 3(0b000), 5(rd), 7(0b0000011) }
74146
}
75147

76148
#[inline]
77-
pub fn lh(rd: u8, rs1: u8, imm: u16) -> u32 {
78-
bitcat! { 12(imm), 5(rs1), 3(0b001), 5(rd), 7(0b0000011) }
149+
pub fn lh(rd: u8, rs1: u8, imm: i32) -> u32 {
150+
bitcat! { signed 12(imm), 5(rs1), 3(0b001), 5(rd), 7(0b0000011) }
79151
}
80152

81153
#[inline]
82-
pub fn lw(rd: u8, rs1: u8, imm: u16) -> u32 {
83-
bitcat! { 12(imm), 5(rs1), 3(0b010), 5(rd), 7(0b0000011) }
154+
pub fn lw(rd: u8, rs1: u8, imm: i32) -> u32 {
155+
bitcat! { signed 12(imm), 5(rs1), 3(0b010), 5(rd), 7(0b0000011) }
84156
}
85157

86158
#[inline]
87-
pub fn lbu(rd: u8, rs1: u8, imm: u16) -> u32 {
88-
bitcat! { 12(imm), 5(rs1), 3(0b100), 5(rd), 7(0b0000011) }
159+
pub fn lbu(rd: u8, rs1: u8, imm: i32) -> u32 {
160+
bitcat! { signed 12(imm), 5(rs1), 3(0b100), 5(rd), 7(0b0000011) }
89161
}
90162

91163
#[inline]
92-
pub fn lhu(rd: u8, rs1: u8, imm: u16) -> u32 {
164+
pub fn lhu(rd: u8, rs1: u8, imm: i32) -> u32 {
93165
bitcat! { 12(imm), 5(rs1), 3(0b101), 5(rd), 7(0b0000011) }
94166
}
95167

96168
#[inline]
97-
pub fn sb(rs1: u8, rs2: u8, imm: u16) -> u32 {
169+
pub fn sb(rs1: u8, rs2: u8, imm: i32) -> u32 {
170+
let imm = i32_to_iN::<12>(imm);
98171
bitcat! { 7(imm >> 5), 5(rs2), 5(rs1), 3(0b000), 5(imm), 7(0b0100011) }
99172
}
100173

101174
#[inline]
102-
pub fn sh(rs1: u8, rs2: u8, imm: u16) -> u32 {
175+
pub fn sh(rs1: u8, rs2: u8, imm: i32) -> u32 {
176+
let imm = i32_to_iN::<12>(imm);
103177
bitcat! { 7(imm >> 5), 5(rs2), 5(rs1), 3(0b001), 5(imm), 7(0b0100011) }
104178
}
105179

106180
#[inline]
107-
pub fn sw(rs1: u8, rs2: u8, imm: u16) -> u32 {
181+
pub fn sw(rs1: u8, rs2: u8, imm: i32) -> u32 {
182+
let imm = i32_to_iN::<12>(imm);
108183
bitcat! { 7(imm >> 5), 5(rs2), 5(rs1), 3(0b010), 5(imm), 7(0b0100011) }
109184
}
110185

111186
#[inline]
112-
pub fn addi(rd: u8, rs1: u8, imm: u16) -> u32 {
113-
bitcat! { 12(imm), 5(rs1), 3(0b000), 5(rd), 7(0b0010011) }
187+
pub fn addi(rd: u8, rs1: u8, imm: i32) -> u32 {
188+
bitcat! { signed 12(imm), 5(rs1), 3(0b000), 5(rd), 7(0b0010011) }
114189
}
115190

116191
#[inline]
117-
pub fn slti(rd: u8, rs1: u8, imm: u16) -> u32 {
118-
bitcat! { 12(imm), 5(rs1), 3(0b010), 5(rd), 7(0b0010011) }
192+
pub fn slti(rd: u8, rs1: u8, imm: i32) -> u32 {
193+
bitcat! { signed 12(imm), 5(rs1), 3(0b010), 5(rd), 7(0b0010011) }
119194
}
120195

121196
#[inline]
122-
pub fn sltiu(rd: u8, rs1: u8, imm: u16) -> u32 {
123-
bitcat! { 12(imm), 5(rs1), 3(0b011), 5(rd), 7(0b0010011) }
197+
pub fn sltiu(rd: u8, rs1: u8, imm: i32) -> u32 {
198+
bitcat! { signed 12(imm), 5(rs1), 3(0b011), 5(rd), 7(0b0010011) }
124199
}
125200

126201
#[inline]
127-
pub fn xori(rd: u8, rs1: u8, imm: u16) -> u32 {
128-
bitcat! { 12(imm), 5(rs1), 3(0b100), 5(rd), 7(0b0010011) }
202+
pub fn xori(rd: u8, rs1: u8, imm: i32) -> u32 {
203+
bitcat! { signed 12(imm), 5(rs1), 3(0b100), 5(rd), 7(0b0010011) }
129204
}
130205

131206
#[inline]
132-
pub fn ori(rd: u8, rs1: u8, imm: u16) -> u32 {
133-
bitcat! { 12(imm), 5(rs1), 3(0b110), 5(rd), 7(0b0010011) }
207+
pub fn ori(rd: u8, rs1: u8, imm: i32) -> u32 {
208+
bitcat! { signed 12(imm), 5(rs1), 3(0b110), 5(rd), 7(0b0010011) }
134209
}
135210

136211
#[inline]
137-
pub fn andi(rd: u8, rs1: u8, imm: u16) -> u32 {
138-
bitcat! { 12(imm), 5(rs1), 3(0b111), 5(rd), 7(0b0010011) }
212+
pub fn andi(rd: u8, rs1: u8, imm: i32) -> u32 {
213+
bitcat! { signed 12(imm), 5(rs1), 3(0b111), 5(rd), 7(0b0010011) }
139214
}
140215

141216
#[inline]
@@ -229,7 +304,7 @@ pub fn mv(rd: u8, rs: u8) -> u32 {
229304
}
230305

231306
#[inline]
232-
pub fn j(imm: u32) -> u32 {
307+
pub fn j(imm: i32) -> u32 {
233308
jal(0, imm)
234309
}
235310

@@ -244,6 +319,6 @@ pub fn jal_r(rd: u8, rs1: u8) -> u32 {
244319
}
245320

246321
#[inline]
247-
pub fn call(imm: u32) -> u32 {
322+
pub fn call(imm: i32) -> u32 {
248323
jal(1, imm)
249324
}

0 commit comments

Comments
 (0)