1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use super::*;
impl BcjFilter {
pub(crate) fn new_riscv(start_pos: usize, encoder: bool) -> Self {
Self {
is_encoder: encoder,
pos: start_pos,
prev_mask: 0,
filter: Self::riscv_code,
}
}
fn riscv_code(&mut self, buf: &mut [u8]) -> usize {
let len = buf.len();
if len < 8 {
return 0;
}
let end = len - 8;
let mut i = 0;
while i <= end {
let inst = buf[i] as u32;
if inst == 0xEF {
// JAL
let b1 = buf[i + 1] as u32;
// Only filter rd=x1(ra) and rd=x5(t0).
if (b1 & 0x0D) != 0 {
i += 2;
continue;
}
let b2 = buf[i + 2] as u32;
let b3 = buf[i + 3] as u32;
let pc = (self.pos + i) as i32;
if self.is_encoder {
// Encoder: Decode address bits from the instruction format.
let addr = ((b1 & 0xF0) << 8)
| ((b2 & 0x0F) << 16)
| ((b2 & 0x10) << 7)
| ((b2 & 0xE0) >> 4)
| ((b3 & 0x7F) << 4)
| ((b3 & 0x80) << 13);
let addr = (addr as i32).wrapping_add(pc);
buf[i + 1] = ((b1 & 0x0F) | ((addr as u32 >> 13) & 0xF0)) as u8;
buf[i + 2] = (addr >> 9) as u8;
buf[i + 3] = (addr >> 1) as u8;
} else {
// Decoder: Encode address bits back to instruction format.
let addr = ((b1 & 0xF0) << 13) | (b2 << 9) | (b3 << 1);
let addr = (addr as i32).wrapping_sub(pc);
buf[i + 1] = ((b1 & 0x0F) | ((addr as u32 >> 8) & 0xF0)) as u8;
buf[i + 2] =
(((addr >> 16) & 0x0F) | ((addr >> 7) & 0x10) | ((addr << 4) & 0xE0)) as u8;
buf[i + 3] = (((addr >> 4) & 0x7F) | ((addr >> 13) & 0x80)) as u8;
}
i += 4;
} else if (inst & 0x7F) == 0x17 {
// AUIPC
let mut inst_full = inst
| ((buf[i + 1] as u32) << 8)
| ((buf[i + 2] as u32) << 16)
| ((buf[i + 3] as u32) << 24);
if (inst_full & 0xE80) != 0 {
// AUIPC's rd doesn't equal x0 or x2.
let inst2 =
u32::from_le_bytes([buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]]);
if (((inst_full << 8) ^ inst2) & 0xF8003) != 3 {
i += 6;
continue;
}
if self.is_encoder {
let addr =
((inst_full & 0xFFFFF000) as i32).wrapping_add((inst2 as i32) >> 20);
let addr = addr.wrapping_add((self.pos + i) as i32);
// Construct the first 32 bits.
inst_full = 0x17 | (2 << 7) | (inst2 << 12);
buf[i] = inst_full as u8;
buf[i + 1] = (inst_full >> 8) as u8;
buf[i + 2] = (inst_full >> 16) as u8;
buf[i + 3] = (inst_full >> 24) as u8;
// Store address in big endian.
buf[i + 4] = (addr >> 24) as u8;
buf[i + 5] = (addr >> 16) as u8;
buf[i + 6] = (addr >> 8) as u8;
buf[i + 7] = addr as u8;
} else {
let addr =
((inst_full & 0xFFFFF000) as i32).wrapping_add((inst2 >> 20) as i32);
inst_full = 0x17 | (2 << 7) | (inst2 << 12);
let inst2_new = addr;
buf[i] = inst_full as u8;
buf[i + 1] = (inst_full >> 8) as u8;
buf[i + 2] = (inst_full >> 16) as u8;
buf[i + 3] = (inst_full >> 24) as u8;
buf[i + 4] = inst2_new as u8;
buf[i + 5] = (inst2_new >> 8) as u8;
buf[i + 6] = (inst2_new >> 16) as u8;
buf[i + 7] = (inst2_new >> 24) as u8;
}
} else {
// AUIPC's rd equals x0 or x2.
let fake_rs1 = inst_full >> 27;
if ((inst_full.wrapping_sub(0x3100)) & 0x3F80) >= (fake_rs1 & 0x1D) {
i += 4;
continue;
}
if self.is_encoder {
let fake_addr =
u32::from_le_bytes([buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]]);
let fake_inst2 = (inst_full >> 12) | (fake_addr << 20);
inst_full = 0x17 | (fake_rs1 << 7) | (fake_addr & 0xFFFFF000);
buf[i] = inst_full as u8;
buf[i + 1] = (inst_full >> 8) as u8;
buf[i + 2] = (inst_full >> 16) as u8;
buf[i + 3] = (inst_full >> 24) as u8;
buf[i + 4] = fake_inst2 as u8;
buf[i + 5] = (fake_inst2 >> 8) as u8;
buf[i + 6] = (fake_inst2 >> 16) as u8;
buf[i + 7] = (fake_inst2 >> 24) as u8;
} else {
let addr =
i32::from_be_bytes([buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]]);
let addr = addr.wrapping_sub((self.pos + i) as i32);
let inst2_rs1 = inst_full >> 27;
let inst2 = (inst_full >> 12) | ((addr as u32) << 20);
inst_full = 0x17
| (inst2_rs1 << 7)
| ((addr.wrapping_add(0x800) as u32) & 0xFFFFF000);
buf[i] = inst_full as u8;
buf[i + 1] = (inst_full >> 8) as u8;
buf[i + 2] = (inst_full >> 16) as u8;
buf[i + 3] = (inst_full >> 24) as u8;
buf[i + 4] = inst2 as u8;
buf[i + 5] = (inst2 >> 8) as u8;
buf[i + 6] = (inst2 >> 16) as u8;
buf[i + 7] = (inst2 >> 24) as u8;
}
}
i += 8;
} else {
i += 2;
}
}
self.pos += i;
i
}
}