1use std::fmt::{self, Display};
12use std::str::FromStr;
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
16pub enum Xlen {
17 #[default]
19 Rv32,
20 Rv64,
22}
23
24#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
47pub struct Target {
48 pub xlen: Xlen,
50 pub privileged: bool,
52 pub supervisor_mode: bool,
54 pub m: bool,
56 pub a: bool,
58 pub f: bool,
60 pub d: bool,
62 pub q: bool,
64 pub c: bool,
66 pub zicsr: bool,
68 pub zifencei: bool,
70 pub zawrs: bool,
72 pub zfh: bool,
74 pub zba: bool,
76 pub zbb: bool,
78 pub zbc: bool,
80 pub zbkb: bool,
82 pub zbs: bool,
84}
85
86impl Target {
87 pub fn supports(&self, extension: &str) -> Result<bool, ParseTargetError> {
118 let supported = match extension.to_ascii_lowercase().as_str() {
119 "rv32i" | "rv32" | "32" => self.xlen == Xlen::Rv32,
120 "rv64i" | "rv64" | "64" => self.xlen == Xlen::Rv64,
121 "i" => true,
122 "m" => self.m,
123 "a" => self.a,
124 "f" => self.f,
125 "d" => self.d,
126 "q" => self.q,
127 "c" => self.c,
128 "b" => self.zba && self.zbb && self.zbs,
129 "zicsr" => self.zicsr,
130 "zifencei" => self.zifencei,
131 "zawrs" => self.zawrs,
132 "zfh" => self.zfh,
133 "zba" => self.zba,
134 "zbb" => self.zbb,
135 "zbc" => self.zbc,
136 "zbkb" => self.zbkb,
137 "zbs" => self.zbs,
138 _ => return Err(ParseTargetError::UnknownExt),
139 };
140
141 Ok(supported)
142 }
143
144 pub fn contains(&self, other: &Target) -> bool {
151 (other.xlen == self.xlen)
152 && (!other.privileged || self.privileged)
153 && (!other.supervisor_mode || self.supervisor_mode)
154 && (!other.m || self.m)
155 && (!other.a || self.a)
156 && (!other.f || self.f)
157 && (!other.d || self.d)
158 && (!other.q || self.q)
159 && (!other.c || self.c)
160 && (!other.zicsr || self.zicsr)
161 && (!other.zifencei || self.zifencei)
162 && (!other.zawrs || self.zawrs)
163 && (!other.zfh || self.zfh)
164 && (!other.zba || self.zba)
165 && (!other.zbb || self.zbb)
166 && (!other.zbc || self.zbc)
167 && (!other.zbkb || self.zbkb)
168 && (!other.zbs || self.zbs)
169 }
170
171 pub fn from_str_strict(s: &str) -> Result<Self, ParseTargetError> {
182 let target = Target::from_str(s)?;
183
184 if s != target.to_string() {
185 return Err(ParseTargetError::Strict);
186 }
187
188 Ok(target)
189 }
190}
191
192#[derive(Clone, Copy, Debug, PartialEq, Eq)]
194pub enum ParseTargetError {
195 Prefix,
197 Xlen,
199 UnknownExt,
201 Strict,
212}
213
214impl FromStr for Target {
215 type Err = ParseTargetError;
216
217 fn from_str(s: &str) -> Result<Self, Self::Err> {
223 let s = s.to_ascii_lowercase();
224 let rest = s
225 .strip_prefix("rv")
226 .or_else(|| s.strip_prefix("riscv"))
227 .ok_or(ParseTargetError::Prefix)?;
228
229 let xlen = match &rest.get(..2) {
230 Some("32") => Xlen::Rv32,
231 Some("64") => Xlen::Rv64,
232 _ => return Err(ParseTargetError::Xlen),
233 };
234 let rest = &rest[2..];
235
236 let mut target = Target { xlen, ..Default::default() };
237
238 let mut extensions = rest;
239 while !extensions.is_empty() {
240 let (ext, rest) = extension(extensions);
241 extensions = rest;
242
243 match ext {
244 "i" => (), "m" => target.m = true,
246 "a" => target.a = true,
247 "f" => target.f = true,
248 "d" => target.d = true,
249 "q" => target.q = true,
250 "c" => target.c = true,
251 "b" => {
252 target.zba = true;
253 target.zbb = true;
254 target.zbs = true;
255 }
256 "zicsr" => target.zicsr = true,
257 "zifencei" => target.zifencei = true,
258 "zawrs" => target.zawrs = true,
259 "zfh" => target.zfh = true,
260 "zba" => target.zba = true,
261 "zbb" => target.zbb = true,
262 "zbc" => target.zbc = true,
263 "zbkb" => target.zbkb = true,
264 "zbs" => target.zbs = true,
265 _ => return Err(ParseTargetError::UnknownExt),
266 }
267 }
268
269 Ok(target)
270 }
271}
272
273impl Display for Target {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 match self.xlen {
276 Xlen::Rv32 => f.write_str("RV32I")?,
277 Xlen::Rv64 => f.write_str("RV64I")?,
278 }
279
280 let b = self.zba && self.zbb && self.zbs;
281 let extensions = [
282 (self.m, "M"),
283 (self.a, "A"),
284 (self.f, "F"),
285 (self.d, "D"),
286 (self.q, "Q"),
287 (self.c, "C"),
288 (b, "B"),
289 (self.zicsr, "Zicsr"),
290 (self.zifencei, "Zifencei"),
291 (self.zawrs, "Zawrs"),
292 (self.zfh, "Zfh"),
293 (self.zba && !b, "Zba"),
294 (self.zbb && !b, "Zbb"),
295 (self.zbc, "Zbc"),
296 (self.zbkb, "Zbkb"),
297 (self.zbs && !b, "Zbs"),
298 ];
299
300 let mut underscore = false;
301 for extension in extensions.into_iter().filter_map(|(en, s)| en.then_some(s)) {
302 if underscore {
304 f.write_str("_")?;
305 }
306 if extension.len() > 1 {
307 underscore = true;
308 }
309
310 f.write_str(extension)?;
311 }
312
313 Ok(())
314 }
315}
316
317fn extension(s: &str) -> (&str, &str) {
321 let len = if s.starts_with('z')
322 || s.starts_with('x')
323 || s.starts_with("sv")
324 || s.starts_with("ss")
325 || s.starts_with("sh")
326 || s.starts_with("sm")
327 {
328 s.find('_').unwrap_or(s.len())
329 } else {
330 1
331 };
332
333 let mut next_index = len;
334 if s[len..].starts_with('_') {
335 next_index += 1;
336 }
337 let rest = &s[next_index..];
338
339 (&s[..len], rest)
340}
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345
346 #[test]
347 fn extensions() {
348 assert_eq!(extension("a"), ("a", ""));
349 assert_eq!(extension("zifencei"), ("zifencei", ""));
350 assert_eq!(extension("a_"), ("a", ""));
351 assert_eq!(extension("zifencei_"), ("zifencei", ""));
352 assert_eq!(extension("am"), ("a", "m"));
353 assert_eq!(extension("a_m"), ("a", "m"));
354 assert_eq!(extension("a_zifencei"), ("a", "zifencei"));
355 assert_eq!(extension("zifencei_a"), ("zifencei", "a"));
356 assert_eq!(extension("zifencei_zicsr"), ("zifencei", "zicsr"));
357 }
358
359 #[test]
360 fn from_str() {
361 fn check(s: &str, expected: Target) {
362 let got = Target::from_str(s).unwrap();
363 assert_eq!(expected, got);
364 }
365 let def = Target::default();
366
367 check("RV32I", Target { xlen: Xlen::Rv32, ..def });
369 check("RV64I", Target { xlen: Xlen::Rv64, ..def });
370 check("RISCV32I", Target { xlen: Xlen::Rv32, ..def });
371 check("RISCV64I", Target { xlen: Xlen::Rv64, ..def });
372
373 check("RV32IM", Target { m: true, ..def });
375 check("RV32IA", Target { a: true, ..def });
376 check("RV32IC", Target { c: true, ..def });
377 check("RV32IF", Target { f: true, ..def });
378 check("RV32ID", Target { d: true, ..def });
379 check("RV32IQ", Target { q: true, ..def });
380 check("RV32IZba", Target { zba: true, ..def });
381 check("RV32IZbb", Target { zbb: true, ..def });
382 check("RV32IZbc", Target { zbc: true, ..def });
383 check("RV32IZbs", Target { zbs: true, ..def });
384 check("RV32IZbkb", Target { zbkb: true, ..def });
385 check("RV32IZifencei", Target { zifencei: true, ..def });
386 check("RV32IZicsr", Target { zicsr: true, ..def });
387
388 check("RV32IMA", Target { m: true, a: true, ..def });
390 check("RV32IZicsr", Target { zicsr: true, ..def });
391 check("RV32IMZicsr", Target { m: true, zicsr: true, ..def });
392 check("RV32IM_Zicsr", Target { m: true, zicsr: true, ..def });
393 check("RV32IZicsr_M", Target { m: true, zicsr: true, ..def });
394 check(
395 "RV32IZicsr_Zifencei",
396 Target { zicsr: true, zifencei: true, ..def },
397 );
398
399 check("RV32IB", Target { zba: true, zbb: true, zbs: true, ..def });
401 }
402
403 #[test]
404 fn display() {
405 fn check_becomes(s: &str, expected: &str) {
406 let got = Target::from_str(s).unwrap().to_string();
407 assert_eq!(got, expected);
408 }
409 fn check(s: &str) {
410 check_becomes(s, s);
411 }
412
413 check("RV32I");
414 check("RV64IMAC");
415
416 check("RV32IMACZicsr");
418 check("RV32IMACZicsr_Zba_Zbkb");
419
420 check_becomes("RV32IZba", "RV32IZba");
422 check_becomes("RV32IZba_Zbb", "RV32IZba_Zbb");
423 check_becomes("RV32IZba_Zbb_Zbs", "RV32IB");
424 }
425
426 #[test]
427 fn parse_strict() {
428 fn check(s: &str, accept: bool) {
429 let got = Target::from_str_strict(s);
430 let not_ = match accept {
431 true => "",
432 false => "not ",
433 };
434 assert!(got.is_ok() == accept, "expected '{s}' {not_}to be accepted");
435 }
436
437 check("RV32I", true);
438 check("RV64I", true);
439 check("RV32", false); check("RV32M", false); check("RV256I", false); check("RV64IMAC", true);
444 check("RV64IMCA", false); check("RV32IMZba", true);
447 check("RV32IMZba_Zbb", true);
448 check("RV32IMZicsr_Zba", true);
449 check("RV32IMZbb_Zba", false); check("RV32IMZba_Zicsr", false); check("RV32IMZbaZbb", false); }
453
454 #[test]
455 fn contains() {
456 fn check(lhs: &str, rhs: &str, accept: bool) {
457 let lhs = Target::from_str(lhs).unwrap();
458 let rhs = Target::from_str(rhs).unwrap();
459 let not_ = match accept {
460 true => "",
461 false => "not ",
462 };
463 assert!(
464 lhs.contains(&rhs) == accept,
465 "expected {lhs}.contains({rhs} {not_}to be accepted)"
466 );
467 }
468
469 check("RV32I", "RV32I", true);
470 check("RV32IM", "RV32I", true);
471 check("RV32IMA", "RV32I", true);
472 check("RV32IA", "RV32I", true);
473 check("RV32IMAFDQCZicsr_Zifencei", "RV32I", true);
474
475 check("RV32IMAC", "RV32I", true);
476 check("RV32IMAC", "RV32IM", true);
477 check("RV32IMAC", "RV32IC", true);
478 check("RV32IMAC", "RV32IMC", true);
479 check("RV32IMAC", "RV32IMAC", true);
480
481 check("RV32I", "RV32IM", false);
482 check("RV32I", "RV32IMAC", false);
483 check("RV32IMAC", "RV32ID", false);
484 check("RV32IMAC", "RV32IMACD", false);
485
486 check("RV32I", "RV64I", false);
487 check("RV32IMAC", "RV64I", false);
488 }
489}