Skip to content

Commit 420604a

Browse files
committed
Initial RISC-V implementation
1 parent d27d095 commit 420604a

File tree

6 files changed

+365
-0
lines changed

6 files changed

+365
-0
lines changed

examples/rv32/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "rv32"
3+
version = "0.1.0"
4+
authors = ["David Cruz <[email protected]>"]
5+
edition = "2021"
6+
publish = false
7+
8+
[dependencies]
9+
dasm = { path = "../.." }

examples/rv32/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# rv32
2+
3+
Example for generating RISC-V instructions
4+
5+
```
6+
cargo run --package rv32
7+
```

examples/rv32/src/main.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
fn main() -> Result<(), Box<dyn std::error::Error>> {
2+
println!("Hello from: {}", std::env::consts::ARCH);
3+
4+
let x0 = 0;
5+
let x10 = 10;
6+
let x12 = 12;
7+
let x17 = 17;
8+
let a0 = x10;
9+
let a1 = 11;
10+
let a7 = x17;
11+
let a2 = x12;
12+
13+
let string = b"Hello, RISC-V!\n";
14+
15+
// unsafe {
16+
// std::arch::asm!(
17+
// "li a7, 64", // syscall number for write
18+
// "li a0, 1", // file descriptor (stdout)
19+
// "addi a1, {0}, 0", // load address of the string
20+
// "addi a2, {1}, 0", // length of the string
21+
// "ecall", // make the syscall
22+
23+
// "li a7, 93", // syscall number for exit
24+
// "li a0, 0", // exit code
25+
// "ecall", // make the syscall
26+
27+
// in(reg) string.as_ptr() as usize,
28+
// in(reg) string.len()
29+
// );
30+
// };
31+
32+
let mut mem: Vec<u32> = vec![];
33+
34+
fn add_test(rd: u32, r1: u32, r2: u32) -> u32 {
35+
(0b0000000 << 25) +
36+
(r2 << 20) +
37+
(r1 << 15) +
38+
(0b000 << 12) +
39+
(rd << 7) +
40+
0b0110011
41+
}
42+
43+
let n1 = 0b0000000_00000_10001_000_00000_0110011;
44+
let n2 = add_test(0, 0b10001, 0);
45+
46+
println!("add_example {:032b}", n1);
47+
println!("add_got {:032b}", n2);
48+
println!("{}", n1 == n2);
49+
50+
mem.extend(&[
51+
dasm::tier::raw::rv32::li(a0, 0),
52+
dasm::tier::raw::rv32::addi(a0, a0, 55),
53+
54+
dasm::tier::raw::rv32::ret()
55+
]);
56+
57+
// mem.push(dasm::tier::raw::rv32::lui(a0, 0b10000001111110000001_101010101011));
58+
// mem.push(dasm::tier::raw::rv32::addi(a0, a0, 0b100010010001));
59+
// mem.push(dasm::tier::raw::rv32::ret());
60+
61+
let u8_slice: &[u8] = unsafe {
62+
std::slice::from_raw_parts(
63+
mem.as_ptr() as *const u8,
64+
mem.len() * std::mem::size_of::<u32>(),
65+
)
66+
};
67+
68+
let map = dasm::mmap::Mmap::exec(u8_slice)?;
69+
let f: extern "C" fn() -> u64 = unsafe { std::mem::transmute(map.as_ptr()) };
70+
println!("{}", f());
71+
72+
Ok(())
73+
}

src/tier/raw/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
pub mod amd64;
22
pub mod x86;
3+
4+
pub mod rv32;
5+
pub mod rv64;

src/tier/raw/rv32/mod.rs

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
macro_rules! r {
2+
($name: ident, $funct7: expr, $funct3: expr, $opcode: expr) => {
3+
#[inline]
4+
pub const fn $name (rd: u8, rs1: u8, rs2: u8) -> u32 {
5+
const { assert!($funct3 < 2u32.pow(3)) };
6+
const { assert!($funct7 < 2u32.pow(7)) };
7+
const { assert!($opcode < 2u32.pow(7)) };
8+
9+
($funct7 << 25) +
10+
(((rs2 & 0b11111) as u32) << 20) +
11+
(((rs1 & 0b11111) as u32) << 15) +
12+
($funct3 << 12) +
13+
(((rd & 0b11111) as u32) << 7) +
14+
$opcode
15+
}
16+
}
17+
}
18+
19+
macro_rules! i {
20+
($name: ident, $funct3: expr, $opcode: expr) => {
21+
#[inline]
22+
pub const fn $name (rd: u8, rs1: u8, imm: u16) -> u32 {
23+
const { assert!($funct3 < 2u32.pow(3)) };
24+
const { assert!($opcode < 2u32.pow(7)) };
25+
26+
(((imm & 0xFFF) as u32) << 20) +
27+
(((rs1 & 0b11111) as u32) << 15) +
28+
($funct3 << 12) +
29+
(((rd & 0b11111) as u32) << 7) +
30+
$opcode
31+
}
32+
}
33+
}
34+
35+
macro_rules! s {
36+
($name: ident, $funct3: expr, $opcode: expr) => {
37+
#[inline]
38+
pub const fn $name (rs1: u8, rs2: u8, imm: u16) -> u32 {
39+
const { assert!($funct3 < 2u32.pow(3)) };
40+
const { assert!($opcode < 2u32.pow(7)) };
41+
42+
(((imm & 0b1111111) as u32) << 25) +
43+
(((rs2 & 0b11111) as u32) << 20) +
44+
(((rs1 & 0b11111) as u32) << 15) +
45+
($funct3 << 12) +
46+
(((imm & 0b1111) as u32) << 7) +
47+
$opcode
48+
}
49+
}
50+
}
51+
52+
macro_rules! b {
53+
($name: ident, $funct3: expr, $opcode: expr) => {
54+
#[inline]
55+
pub const fn $name (rs1: u8, rs2: u8, imm: u16) -> u32 {
56+
const { assert!($funct3 < 2u32.pow(3)) };
57+
const { assert!($opcode < 2u32.pow(7)) };
58+
59+
((((imm >> 12) & 0b1) as u32) << 31) +
60+
((((imm >> 5) & 0b111111) as u32) << 25) +
61+
((rs2 as u32 & 0b11111) << 20) +
62+
((rs1 as u32 & 0b11111) << 15) +
63+
($funct3 << 12) +
64+
((((imm >> 1) & 0b1111) as u32) << 8) +
65+
((((imm >> 11) & 0b1) as u32) << 7) +
66+
$opcode
67+
}
68+
}
69+
}
70+
71+
macro_rules! u {
72+
($name: ident, $opcode: expr) => {
73+
#[inline]
74+
pub const fn $name(rd: u8, imm: u32) -> u32 {
75+
const { assert!($opcode < 2u32.pow(7)) };
76+
77+
((imm & 0xFFFFF000) as u32) +
78+
((rd as u32 & 0b11111) << 7) +
79+
$opcode
80+
}
81+
}
82+
}
83+
84+
macro_rules! j {
85+
($name: ident, $opcode: expr) => {
86+
#[inline]
87+
pub const fn $name(rd: u8, imm: u32) -> u32 {
88+
const { assert!($opcode < 2u32.pow(7)) };
89+
90+
(((imm >> 20) & 0b1) << 31) +
91+
(((imm >> 1) & 0b1111111111) << 21) +
92+
(((imm >> 11) & 0b1) << 20) +
93+
(((imm >> 12) & 0b111111111111) << 12) +
94+
((rd as u32 & 0b11111) << 7) +
95+
$opcode
96+
}
97+
}
98+
}
99+
100+
r!(add, 0b0000000, 0b000, 0b0110011);
101+
r!(sub, 0b0100000, 0b000, 0b0110011);
102+
r!(sll, 0b0000000, 0b001, 0b0110011);
103+
r!(slt, 0b0000000, 0b010, 0b0110011);
104+
r!(sltu, 0b0000000, 0b011, 0b0110011);
105+
r!(xor, 0b0000000, 0b100, 0b0110011);
106+
r!(srl, 0b0000000, 0b101, 0b0110011);
107+
r!(sra, 0b0100000, 0b101, 0b0110011);
108+
r!(or, 0b0000000, 0b110, 0b0110011);
109+
r!(and, 0b0000000, 0b111, 0b0110011);
110+
111+
i!(lb, 0b000, 0b0000011);
112+
i!(lh, 0b001, 0b0000011);
113+
i!(lw, 0b010, 0b0000011);
114+
i!(lbu, 0b100, 0b0000011);
115+
i!(lhu, 0b101, 0b0000011);
116+
i!(addi, 0b000, 0b0010011);
117+
i!(slti, 0b010, 0b0010011);
118+
i!(sltiu, 0b011, 0b0010011);
119+
i!(xori, 0b100, 0b0010011);
120+
i!(ori, 0b110, 0b0010011);
121+
i!(andi, 0b111, 0b0010011);
122+
i!(slli, 0b001, 0b0010011);
123+
i!(srli, 0b101, 0b0010011);
124+
i!(srai, 0b101, 0b0010011);
125+
i!(jalr, 0b000, 0b1100111);
126+
127+
s!(sb, 0b000, 0b0100011);
128+
s!(sh, 0b001, 0b0100011);
129+
s!(sw, 0b010, 0b0100011);
130+
131+
b!(beq, 0b000, 0b1100011);
132+
b!(bne, 0b001, 0b1100011);
133+
b!(blt, 0b100, 0b1100011);
134+
b!(bge, 0b101, 0b1100011);
135+
b!(bltu, 0b110, 0b1100011);
136+
b!(bgeu, 0b111, 0b1100011);
137+
138+
// u!(lui, 0b0110111);
139+
140+
#[inline]
141+
pub fn lui(rd: u8, imm: u32) -> u32 {
142+
(((imm & 0xFFFFF) as u32) << 12) +
143+
((rd as u32 & 0b11111) << 7) +
144+
0b0110111
145+
}
146+
147+
u!(auipc, 0b0010111);
148+
149+
j!(jal, 0b1101111);
150+
151+
#[inline]
152+
pub fn nop() -> u32 {
153+
addi(0, 0, 0)
154+
}
155+
156+
#[inline]
157+
pub fn li(rd: u8, imm: u16) -> u32 {
158+
addi(rd, 0, imm)
159+
}
160+
161+
#[inline]
162+
pub fn li_32(rd: u8, imm: u32) -> [u32; 2] {
163+
[
164+
lui(rd, (imm >> 12) as _),
165+
addi(rd, rd, (imm & 0xFFF) as _)
166+
]
167+
}
168+
169+
pub fn li_64(rd: u8, imm: u64) -> [u32; 8] {
170+
[
171+
lui(rd, (imm >> 44) as _), // Load upper 20 bits
172+
173+
addi(rd, rd, ((imm >> 32) & 0xFFF) as _), // Add next 12 bits
174+
slli(rd, rd, 12), // Shift left by 12 bits
175+
176+
addi(rd, rd, ((imm >> 20) & 0xFFF) as _), // Add next 12 bits
177+
slli(rd, rd, 12), // Shift left by 12 bits
178+
179+
addi(rd, rd, ((imm >> 8) & 0xFFF) as _), // Add next 12 bits
180+
slli(rd, rd, 12), // Shift left by 12 bits
181+
182+
addi(rd, rd, (imm & 0xFF) as _), // Add final 8 bits
183+
]
184+
}
185+
186+
// pub fn li_64(rd: u8, imm: u64) -> [u32; 5] {
187+
// let [l1, l2] = li_32(rd, (imm >> 32) as _);
188+
// let [l3, l4] = li_32(rd, (imm & 0b11111111111111111111111111111111) as _);
189+
190+
// [
191+
// l1,
192+
// l2,
193+
// slli(rd, rd, 32),
194+
// l3,
195+
// l4
196+
// ]
197+
// }
198+
199+
#[inline]
200+
pub fn mv(rd: u8, rs: u8) -> u32 {
201+
addi(rd, rs, 0)
202+
}
203+
204+
#[inline]
205+
pub fn not(rd: u8, rs: u8) -> u32 {
206+
xori(rd, rs, 0xFFF)
207+
}
208+
209+
#[inline]
210+
pub fn neg(rd: u8, rs: u8) -> u32 {
211+
sub(rd, 0, rs)
212+
}
213+
214+
#[inline]
215+
pub fn seqz(rd: u8, rs: u8) -> u32 {
216+
sltiu(rd, rs, 1)
217+
}
218+
219+
#[inline]
220+
pub fn snez(rd: u8, rs: u8) -> u32 {
221+
sltu(rd, 0, rs)
222+
}
223+
224+
#[inline]
225+
pub fn sltz(rd: u8, rs: u8) -> u32 {
226+
slt(rd, rs, 0)
227+
}
228+
229+
#[inline]
230+
pub fn sgtz(rd: u8, rs: u8) -> u32 {
231+
slt(rd, 0, rs)
232+
}
233+
234+
#[inline]
235+
pub fn beqz(rs: u8, offset: u16) -> u32 {
236+
beq(rs, 0, offset)
237+
}
238+
239+
#[inline]
240+
pub fn bnez(rs: u8, offset: u16) -> u32 {
241+
bne(rs, 0, offset)
242+
}
243+
244+
#[inline]
245+
pub fn j(offset: u32) -> u32 {
246+
jal(0, offset)
247+
}
248+
249+
#[inline]
250+
pub fn jr(rs: u8) -> u32 {
251+
jalr(0, rs, 0)
252+
}
253+
254+
#[inline]
255+
pub fn ret() -> u32 {
256+
jr(1)
257+
}
258+
259+
#[inline]
260+
pub fn la(rd: u8, label: u32) -> [u32; 2] {
261+
[auipc(rd, label >> 12), addi(rd, rd, (label & 0xFFF) as _)]
262+
}
263+
264+
#[inline]
265+
pub fn ecall() -> u32 {
266+
0b000000000000_00000_000_00000_1110011
267+
}
268+
269+
#[inline]
270+
pub fn ebreak() -> u32 {
271+
0b000000000001_00000_000_00000_1110011
272+
}

src/tier/raw/rv64/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub use crate::tier::raw::rv32::*;

0 commit comments

Comments
 (0)