1#[macro_use]
2extern crate pest_derive;
3
4use anyhow::{anyhow, Error};
5use pest::Parser;
6
7#[allow(dead_code, clippy::type_complexity)]
8mod opcodes;
9
10mod asm_parser {
11 #[derive(Parser)]
12 #[grammar = "asm.pest"]
13 pub(crate) struct AsmParser;
14}
15use asm_parser::{AsmParser, Rule};
16
17const V0_TAIL_INSTS: [&str; 14] = [
19 "vfmerge.vfm",
20 "vadc.vxm",
21 "vmadc.vxm",
22 "vsbc.vxm",
23 "vmsbc.vxm",
24 "vmerge.vxm",
25 "vadc.vvm",
26 "vmadc.vvm",
27 "vsbc.vvm",
28 "vmsbc.vvm",
29 "vmerge.vvm",
30 "vadc.vim",
31 "vmadc.vim",
32 "vmerge.vim",
33];
34
35const VV_TERNARY_INSTS: [&str; 19] = [
42 "vmacc.vv",
43 "vnmsac.vv",
44 "vmadd.vv",
45 "vnmsub.vv",
46 "vwmaccu.vv",
47 "vwmacc.vv",
48 "vwmaccsu.vv",
49 "vfmacc.vv",
50 "vfnmacc.vv",
51 "vfmsac.vv",
52 "vfnmsac.vv",
53 "vfmadd.vv",
54 "vfnmadd.vv",
55 "vfmsub.vv",
56 "vfnmsub.vv",
57 "vfwmacc.vv",
58 "vfwnmacc.vv",
59 "vfwmsac.vv",
60 "vfwnmsac.vv",
61];
62const VX_VF_TERNARY_INSTS: [&str; 20] = [
63 "vmacc.vx",
64 "vnmsac.vx",
65 "vmadd.vx",
66 "vnmsub.vx",
67 "vwmaccu.vx",
68 "vwmacc.vx",
69 "vwmaccsu.vx",
70 "vwmaccus.vx",
71 "vfmacc.vf",
72 "vfnmacc.vf",
73 "vfmsac.vf",
74 "vfnmsac.vf",
75 "vfmadd.vf",
76 "vfnmadd.vf",
77 "vfmsub.vf",
78 "vfnmsub.vf",
79 "vfwmacc.vf",
80 "vfwnmacc.vf",
81 "vfwmsac.vf",
82 "vfwnmsac.vf",
83];
84
85pub fn encode(inst: &str, reserved_only: bool) -> Result<Option<u32>, Error> {
97 let pairs = if let Ok(result) = AsmParser::parse(Rule::inst, inst.trim()) {
98 result
99 } else {
100 let _ = AsmParser::parse(Rule::label, inst.trim())
101 .map_err(|err| anyhow!("parse asm error: {}", err))?;
102 return Ok(None);
103 };
104 let mut name = "unknown";
105 let mut args = Vec::new();
106 for pair in pairs.clone() {
107 for inner1_pair in pair.into_inner() {
108 match inner1_pair.as_rule() {
109 Rule::inst_name => {
110 name = inner1_pair.as_str();
111 }
112 Rule::inst_arg => {
113 for inner2_pair in inner1_pair.into_inner() {
114 match inner2_pair.as_rule() {
115 Rule::inst_arg_mask | Rule::inst_arg_simple | Rule::integer => {
116 args.push(inner2_pair.as_str());
117 }
118 _ => {
119 return Ok(None);
120 }
121 }
122 }
123 }
124 _ => {
125 return Ok(None);
126 }
127 }
128 }
129 }
130 if reserved_only {
131 let mut is_reserved = false;
132 'outer: for width in [128, 256, 512, 1024] {
133 for prefix in ["i", "e"] {
134 let part = format!("{}{}", prefix, width);
135 if name.contains(part.as_str()) {
136 is_reserved = true;
137 break 'outer;
138 }
139 for arg in &args {
140 if arg.contains(part.as_str()) {
141 is_reserved = true;
142 break 'outer;
143 }
144 }
145 }
146 }
147 if !is_reserved {
148 return Ok(None);
149 }
150 }
151
152 opcodes::INSTRUCTIONS
153 .iter()
154 .find(|(inst_name, _, _)| *inst_name == name)
155 .map(|(_, base, args_cfg)| gen_inst_code(name, &args, *base, args_cfg))
156 .transpose()
157}
158
159fn gen_inst_code(
160 name: &str,
161 args: &[&str],
162 mut base: u32,
163 arg_cfg: &[(&str, usize)],
164) -> Result<u32, Error> {
165 let simm5_idx = arg_cfg.iter().position(|(name, _)| *name == "simm5");
167 let vs1_idx = arg_cfg.iter().position(|(name, _)| *name == "vs1");
168 let rs1_idx = arg_cfg.iter().position(|(name, _)| *name == "rs1");
169 let vs2_idx = arg_cfg.iter().position(|(name, _)| *name == "vs2");
170 let last_7bits = base & 0b1111111;
171 let mut arg_cfg_vec = arg_cfg.iter().collect::<Vec<_>>();
172 if let (Some(simm5_idx), Some(vs2_idx), 0x57) = (simm5_idx, vs2_idx, last_7bits) {
173 arg_cfg_vec.swap(simm5_idx, vs2_idx);
174 }
175 if let (Some(vs1_idx), Some(vs2_idx), 0x57) = (vs1_idx, vs2_idx, last_7bits) {
176 if !VV_TERNARY_INSTS.contains(&name) {
177 arg_cfg_vec.swap(vs1_idx, vs2_idx);
178 }
179 }
180 if let (Some(rs1_idx), Some(vs2_idx), 0x57) = (rs1_idx, vs2_idx, last_7bits) {
181 if !VX_VF_TERNARY_INSTS.contains(&name) {
182 arg_cfg_vec.swap(rs1_idx, vs2_idx);
183 }
184 }
185 let arg_cfg_final = &arg_cfg_vec;
186
187 let has_vm = arg_cfg_final.iter().any(|(arg_name, _)| *arg_name == "vm");
188 let has_nf = arg_cfg_final.iter().any(|(arg_name, _)| *arg_name == "nf");
189 let number = if has_nf && has_vm {
190 arg_cfg_final.len() - 2
191 } else if has_vm {
192 arg_cfg_final.len() - 1
193 } else {
194 arg_cfg_final.len()
195 };
196 check_args(name, args, number, has_vm)?;
197 for (idx, (arg_name, arg_pos)) in arg_cfg_final.iter().rev().enumerate() {
198 let value = match *arg_name {
199 "rs1" | "rs2" | "rd" => map_x_reg(args[idx], arg_name)?,
200 "vs1" | "vs2" | "vs3" | "vd" => map_v_reg(args[idx], arg_name)?,
201 "simm5" => {
202 let arg_current = args[idx].to_lowercase();
203 let value = if arg_current.starts_with('-') {
204 let value = if let Some(content) = arg_current.strip_prefix("0x") {
205 i8::from_str_radix(content, 16)
206 .map_err(|_| anyhow!("Parse simm5 value failed: {}", arg_current))?
207 } else {
208 arg_current
209 .parse::<i8>()
210 .map_err(|_| anyhow!("Parse simm5 value failed: {}", arg_current))?
211 };
212 if value < -16 || value > 15 {
213 return Err(anyhow!(
214 "Simm5 value out of range: {} expected: [-16, 15]",
215 value
216 ));
217 }
218 value as u8
219 } else {
220 let value = if let Some(content) = arg_current.strip_prefix("0x") {
221 u8::from_str_radix(content, 16)
222 .map_err(|_| anyhow!("Parse uimm5 value failed: {}", arg_current))?
223 } else {
224 arg_current
225 .parse::<u8>()
226 .map_err(|_| anyhow!("Parse uimm5 value failed: {}", arg_current))?
227 };
228 if value > 31 {
229 return Err(anyhow!(
230 "Uimm5 value out of range: {} expected: [0, 31]",
231 value
232 ));
233 }
234 value
235 };
236 (value & 0b00011111) as u32
237 }
238 "zimm" => {
239 let value = args[idx]
240 .parse::<u8>()
241 .map_err(|_| anyhow!("Parse zimm5 value failed: {}", args[idx]))?;
242 if value > 31 {
243 return Err(anyhow!(
244 "zimm5 value out of range: {} expected: [0, 31]",
245 value
246 ));
247 }
248 (value as u8 & 0b00011111) as u32
249 }
250 "zimm10" | "zimm11" => {
252 let mut vsew: u8 = 0;
253 let mut lmul = Vlmul::M1;
254 let mut ta = false;
255 let mut ma = false;
256 let mut tu = false;
257 let mut mu = false;
258 for arg_str in &args[idx..] {
259 if *arg_str == "ta" {
260 ta = true;
261 } else if *arg_str == "ma" {
262 ma = true;
263 } else if *arg_str == "tu" {
264 tu = true;
265 } else if *arg_str == "mu" {
266 mu = true;
267 } else if arg_str.as_bytes()[0] == b'e' {
268 let sew = arg_str[1..]
269 .parse::<u16>()
270 .map_err(|_| anyhow!("Invalid SEW value format: {}", arg_str))?;
271 vsew = match sew {
272 8 => 0,
273 16 => 1,
274 32 => 2,
275 64 => 3,
276 128 => 4,
277 256 => 5,
278 512 => 6,
279 1024 => 7,
280 _ => {
281 return Err(anyhow!(
282 "Invalid SEW value for vtypei: {}, arg: {}",
283 sew,
284 arg_str
285 ))
286 }
287 };
288 } else if arg_str.as_bytes()[0] == b'm' {
289 lmul = Vlmul::from_str(arg_str)
290 .ok_or_else(|| anyhow!("Invalid LMUL value format: {}", arg_str))?;
291 } else {
292 return Err(anyhow!(
293 "Invalid argument for {}, expected: e{{n}}/m{{n}}/ta/ma/tu/mu, got: {}",
294 name,
295 arg_str
296 ));
297 }
298 }
299
300 if ta && tu {
301 return Err(anyhow!("ta/tu can not both exists"));
302 }
303 if ma && mu {
304 return Err(anyhow!("ma/mu can not both exists"));
305 }
306
307 let mut value = lmul as u8;
308 value |= vsew << 3;
309 if ta {
310 value |= 1 << 6;
311 }
312 if ma {
313 value |= 1 << 7;
314 }
315 value as u32
316 }
317 "vm" => {
319 if args.get(idx) == Some(&"v0.t") {
320 0
321 } else {
322 1
323 }
324 }
325 "nf" => 0,
327 "wd" => return Err(anyhow!("Zvamo instructions are not supported.")),
329 _ => unreachable!(),
330 };
331 base |= value << arg_pos;
332 }
333 Ok(base)
334}
335
336#[repr(u8)]
337enum Vlmul {
338 Mf8 = 0b101,
340 Mf4 = 0b110,
342 Mf2 = 0b111,
344 M1 = 0b000,
346 M2 = 0b001,
348 M4 = 0b010,
350 M8 = 0b011,
352}
353
354impl Vlmul {
355 fn from_str(name: &str) -> Option<Vlmul> {
356 match name {
357 "mf8" => Some(Vlmul::Mf8),
358 "mf4" => Some(Vlmul::Mf4),
359 "mf2" => Some(Vlmul::Mf2),
360 "m1" => Some(Vlmul::M1),
361 "m2" => Some(Vlmul::M2),
362 "m4" => Some(Vlmul::M4),
363 "m8" => Some(Vlmul::M8),
364 _ => None,
365 }
366 }
367}
368
369fn check_args(name: &str, args: &[&str], number: usize, vm: bool) -> Result<(), Error> {
370 if V0_TAIL_INSTS.contains(&name) {
371 if args.len() != number + 1 {
372 return Err(anyhow!(
373 "Invalid number of arguments for {}, expected: {}, got: {}",
374 name,
375 number + 1,
376 args.len()
377 ));
378 }
379 if args[args.len() - 1] != "v0" {
380 return Err(anyhow!("The last argument of {} must be v0", name));
381 }
382 return Ok(());
383 }
384 let (expected, min, max) = if name == "vsetvli" || name == "vsetivli" {
385 ("3 <= n <=6".to_string(), 3, 6)
386 } else if !vm {
387 (number.to_string(), number, number)
388 } else {
389 (format!("{} or {}", number, number + 1), number, number + 1)
390 };
391 if args.len() < min || args.len() > max {
392 Err(anyhow!(
393 "Invalid number of arguments for {}, expected: {}, got: {}",
394 name,
395 expected,
396 args.len()
397 ))
398 } else {
399 Ok(())
400 }
401}
402
403fn map_v_reg(name: &str, label: &str) -> Result<u32, Error> {
404 if name.as_bytes()[0] != b'v' {
405 return Err(anyhow!("Invalid {} V register: {}", label, name));
406 }
407 let number = name[1..]
408 .parse::<u32>()
409 .map_err(|_| anyhow!("Invalid {} V register: {}", label, name))?;
410 if number > 31 {
411 return Err(anyhow!("Invalid {} V register: {}", label, name));
412 }
413 Ok(number)
414}
415
416fn map_x_reg(name: &str, label: &str) -> Result<u32, Error> {
417 match name {
418 "x0" | "zero" => Ok(0),
419 "x1" | "ra" => Ok(1),
420 "x2" | "sp" => Ok(2),
421 "x3" | "gp" => Ok(3),
422 "x4" | "tp" => Ok(4),
423 "x5" | "t0" => Ok(5),
424 "x6" | "t1" => Ok(6),
425 "x7" | "t2" => Ok(7),
426 "x8" | "s0" | "fp" => Ok(8),
427 "x9" | "s1" => Ok(9),
428 "x10" | "a0" => Ok(10),
429 "x11" | "a1" => Ok(11),
430 "x12" | "a2" => Ok(12),
431 "x13" | "a3" => Ok(13),
432 "x14" | "a4" => Ok(14),
433 "x15" | "a5" => Ok(15),
434 "x16" | "a6" => Ok(16),
435 "x17" | "a7" => Ok(17),
436 "x18" | "s2" => Ok(18),
437 "x19" | "s3" => Ok(19),
438 "x20" | "s4" => Ok(20),
439 "x21" | "s5" => Ok(21),
440 "x22" | "s6" => Ok(22),
441 "x23" | "s7" => Ok(23),
442 "x24" | "s8" => Ok(24),
443 "x25" | "s9" => Ok(25),
444 "x26" | "s10" => Ok(26),
445 "x27" | "s11" => Ok(27),
446 "x28" | "t3" => Ok(28),
447 "x29" | "t4" => Ok(29),
448 "x30" | "t5" => Ok(30),
449 "x31" | "t6" => Ok(31),
450 _ => Err(anyhow!("Invalid {} X register: {}", label, name)),
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457
458 #[test]
459 fn test_riscvgc() {
460 assert_eq!(encode("add {abc_t}, {abc}, 3", false).unwrap(), None);
461 assert_eq!(encode("add a1, a1, a2", false).unwrap(), None);
462 assert_eq!(encode("jr t0", false).unwrap(), None);
463 assert_eq!(encode("fence", false).unwrap(), None);
464 }
465
466 fn assert_inst(code: u32, inst: &str) {
467 let output_code = encode(inst, false).unwrap().unwrap();
468 assert_eq!(output_code, code, "0b{:032b} - {}", output_code, inst);
469 }
470
471 #[test]
478 fn test_vset() {
479 for (code, inst) in [
480 (0b10000001111110011111001011010111, "vsetvl x5, s3, t6"),
481 (0b00000000000010011111001011010111, "vsetvli x5, s3, e8"),
482 (
483 0b00000010101010011111001011010111,
484 "vsetvli x5, s3, e256, m4",
485 ),
486 (
487 0b00001110101010011111001011010111,
488 "vsetvli x5, s3, e256, m4, ta, ma",
489 ),
490 (
491 0b11000010101010011111001011010111,
492 "vsetivli x5, 19, e256, m4",
493 ),
494 (
495 0b11000010101010011111001011010111,
496 "vsetivli x5, 19, e256, m4, tu, mu",
497 ),
498 (
499 0b11001010101010011111001011010111,
500 "vsetivli x5, 19, e256, m4, tu, ma",
501 ),
502 (
503 0b11000110101010011111001011010111,
504 "vsetivli x5, 19, e256, m4, ta, mu",
505 ),
506 (
507 0b11001110101010011111001011010111,
508 "vsetivli x5, 19, e256, m4, ta, ma",
509 ),
510 ] {
511 assert_inst(code, inst);
512 }
513 }
514
515 #[test]
516 fn test_simm5_range() {
517 for (code, inst) in [
518 (0b00000010001010000011000011010111, "vadd.vi v1, v2, -16"),
519 (0b00000010001001111011000011010111, "vadd.vi v1, v2, 15"),
520 ] {
521 assert_inst(code, inst);
522 }
523
524 assert!(encode("vadd.vi v1, v2, -17", false).is_err());
525 }
526
527 #[test]
532 fn test_rs1_vd_0x07() {
533 for (code, inst) in [
534 (0b00000010101100101000000010000111, "vlm.v v1, (t0)"),
536 (0b00000010000000101000000010000111, "vle8.v v1, (t0)"),
538 (0b00000011000000101000000010000111, "vle8ff.v v1, (t0)"),
540 (0b00000010100000101000000010000111, "vl1re8.v v1, (t0)"),
542 ] {
543 assert_inst(code, inst);
544 }
545 }
546 #[test]
550 fn test_rs1_vs3_0x27() {
551 for (code, inst) in [
552 (0b00000010101100101000000010100111, "vsm.v v1, (t0)"),
554 (0b00000010000000101000000010100111, "vse8.v v1, (t0)"),
556 (0b00000010100000101000000010100111, "vs1r.v v1, (t0)"),
558 ] {
559 assert_inst(code, inst);
560 }
561 }
562
563 #[test]
566 fn test_vs2_rs1_vd_0x07() {
567 for (code, inst) in [
568 (0b00000110001000101000000010000111, "vluxei8.v v1, (t0), v2"),
570 (0b00001110001000101000000010000111, "vloxei8.v v1, (t0), v2"),
572 ] {
573 assert_inst(code, inst);
574 }
575 }
576 #[test]
579 fn test_vs2_rs1_vs3_0x27() {
580 for (code, inst) in [
581 (0b00000110001000101000000010100111, "vsuxei8.v v1, (t0), v2"),
583 (0b00001110001000101000000010100111, "vsoxei8.v v1, (t0), v2"),
585 ] {
586 assert_inst(code, inst);
587 }
588 }
589
590 #[test]
592 fn test_rs2_rs1_vd_0x07() {
593 assert_inst(0b00001010011000101000000010000111, "vlse8.v v1, (t0), t1");
595 }
596
597 #[test]
599 fn test_rs2_rs1_vs3_0x27() {
600 assert_inst(0b00001010011000101000000010100111, "vsse8.v v1, (t0), t1");
602 }
603
604 #[test]
608 fn test_vs2_rs1_vd_0x57() {
609 for (code, inst) in [
610 (0b00000010001000101101000011010111, "vfadd.vf v1, v2, t0"),
612 (
614 0b01011100001000101101000011010111,
615 "vfmerge.vfm v1, v2, t0, v0",
616 ),
617 (0b10110110000101100110000111010111, "vmacc.vx v3, a2, v1"),
619 ] {
620 assert_inst(code, inst);
621 }
622 }
623
624 #[test]
627 fn test_rs1_vd_0x57() {
628 for (code, inst) in [
629 (0b01000010000000101101000011010111, "vfmv.s.f v1, t0"),
631 (0b01011110000000101100000011010111, "vmv.v.x v1, t0"),
633 ] {
634 assert_inst(code, inst);
635 }
636 }
637
638 #[test]
642 fn test_vs2_vs1_vd_0x57() {
643 for (code, inst) in [
644 (0b00000010001000011001000011010111, "vfadd.vv v1, v2, v3"),
646 (
648 0b01000000001000011000000011010111,
649 "vadc.vvm v1, v2, v3, v0",
650 ),
651 (0b10110110001000001010000111010111, "vmacc.vv v3, v1, v2"),
653 ] {
654 assert_inst(code, inst);
655 }
656 }
657
658 #[test]
661 fn test_vs2_rd_0x57() {
662 for (code, inst) in [
665 (0b01000010001000000001001011010111, "vfmv.f.s t0, v2"),
666 (0b01000010001010000010001011010111, "vcpop.m t0, v2"),
667 ] {
668 assert_inst(code, inst);
669 }
670 }
671
672 #[test]
675 fn test_vs2_vd_0x57() {
676 for (code, inst) in [
677 (0b01001010001000000001000011010111, "vfcvt.xu.f.v v1, v2"),
679 (0b10011110001000000011000011010111, "vmv1r.v v1, v2"),
681 ] {
682 assert_inst(code, inst);
683 }
684 }
685
686 #[test]
688 fn test_vs1_vd_0x57() {
689 assert_inst(0b01011110000000010000000011010111, "vmv.v.v v1, v2");
691 }
692
693 #[test]
696 fn test_vs2_simm5_vd_0x57() {
697 for (code, inst) in [
698 (0b00000010001011011011000011010111, "vadd.vi v1, v2, -5"),
700 (0b01000000001000101011000011010111, "vadc.vim v1, v2, 5, v0"),
702 ] {
703 assert_inst(code, inst);
704 }
705 }
706
707 #[test]
709 fn test_simm5_vd_0x57() {
710 assert_inst(0b01011110000000101011000011010111, "vmv.v.i v1, 0x5");
712 }
713 #[test]
715 fn test_vd_0x57() {
716 assert_inst(0b01010010000010001010000011010111, "vid.v v1");
718 }
719
720 #[test]
723 fn test_vmandn_vmorn() {
724 assert_inst(0b01100010001000011010000011010111, "vmandn.mm v1, v2, v3");
726 assert_inst(0b01110010001000011010000011010111, "vmorn.mm v1, v2, v3");
728 }
729}