1use alloc::borrow::ToOwned;
2use alloc::string::String;
3use alloc::vec::Vec;
4use alloc::{format, vec};
5use riscv_codec_proc_macros::{
6 amo_assemble, b_assemble, ci_assemble, cr_assemble, fr_assemble, fr3_assemble, i_assemble,
7 l_assemble, r_assemble, s_assemble, sh_assemble, shw_assemble,
8};
9
10use crate::immediates::*;
11use crate::instruction::RoundingMode;
12use crate::register::{CFRegister, CIRegister, FRegister, IRegister};
13use crate::{cinstruction::CInstruction, instruction::Instruction};
14
15fn parse_int(str: &str) -> Result<i64, String> {
16 match str.parse::<i64>() {
17 Ok(e) => Ok(e),
18 Err(_) => Err(format!("unable to parse int:{str}").to_owned()),
19 }
20}
21
22fn parse_address_expression(str: &str) -> Result<(IRegister, i64), String> {
23 let (offset, register): (&str, &str) = if let Some(x) = str.split_once("(") {
24 x
25 } else {
26 panic!("no (");
27 };
28 match register.strip_suffix(")") {
29 Some(y) => {
30 let r = IRegister::try_from(y)?;
31 let i = parse_int(offset)?;
32 Ok((r, i))
33 }
34 _ => Err("Address expression should end in a )".to_owned()),
35 }
36}
37
38fn parse_address_expression_compressed(str: &str) -> Result<(CIRegister, i64), String> {
39 let (offset, register): (&str, &str) = if let Some(x) = str.split_once("(") {
40 x
41 } else {
42 panic!("no (");
43 };
44 match register.strip_suffix(")") {
45 Some(y) => {
46 let r = CIRegister::try_from(y)?;
47 let i = parse_int(offset)?;
48 Ok((r, i))
49 }
50 _ => Err("Address expression should end in a )".to_owned()),
51 }
52}
53
54fn parse_fence_set(s: &str) -> u8 {
56 let mut x = 0;
57 if s.contains("w") {
58 x |= 0b1;
59 }
60 if s.contains("r") {
61 x |= 0b10;
62 }
63 if s.contains("o") {
64 x |= 0b100;
65 }
66 if s.contains("i") {
67 x |= 0b1000;
68 }
69 x
70}
71
72#[derive(Debug, PartialEq)]
73pub enum AssemblyResult {
74 I(Instruction),
75 C(CInstruction),
76}
77impl AssemblyResult {
78 pub fn c(self) -> CInstruction {
79 match self {
80 AssemblyResult::I(_) => panic!("c called on regular instruction"),
81 AssemblyResult::C(cinstruction) => cinstruction,
82 }
83 }
84 pub fn i(self) -> Instruction {
85 match self {
86 AssemblyResult::I(instruction) => instruction,
87 AssemblyResult::C(_) => panic!("i called on compressed instruction"),
88 }
89 }
90}
91
92pub fn assemble_line(line: &str) -> Result<AssemblyResult, String> {
94 let (mnemonic, operands): (&str, &str) = if let Some(x) = line.split_once(" ") {
95 x
96 } else {
97 (line, "")
98 };
99
100 let mnemonics: Vec<&str> = mnemonic.split(".").collect();
101
102 let operands: Vec<&str> = if operands.is_empty() {
103 vec![]
104 } else {
105 operands.split(',').collect()
106 };
107 let operands: Vec<&str> = operands
108 .iter()
109 .map(|operand| operand.to_owned().trim())
110 .collect();
111
112 if mnemonics[0] == "c" {
113 if mnemonics.len() == 1 {
114 Err("compressed instruction must be specified".to_owned())
115 } else {
116 compressed_assemble(&mnemonics[1..], operands).map(AssemblyResult::C)
117 }
118 } else {
119 let x = match mnemonics[0] {
120 "addi" => i_assemble!(Addi),
122 "addiw" => i_assemble!(Addiw),
123 "andi" => i_assemble!(Andi),
124 "ori" => i_assemble!(Ori),
125 "xori" => i_assemble!(Xori),
126 "slti" => i_assemble!(Slti),
127 "sltiu" => i_assemble!(Sltiu),
128 "slli" => sh_assemble!(Slli),
129 "srai" => sh_assemble!(Srai),
130 "sraiw" => shw_assemble!(Sraiw),
131 "srli" => sh_assemble!(Srli),
132 "srliw" => shw_assemble!(Srliw),
133 "slliw" => shw_assemble!(Slliw),
134 "add" => r_assemble!(Add),
136 "addw" => r_assemble!(Addw),
137 "subw" => r_assemble!(Subw),
138 "and" => r_assemble!(And),
139 "sub" => r_assemble!(Sub),
140 "or" => r_assemble!(Or),
141 "xor" => r_assemble!(Xor),
142 "sllw" => r_assemble!(Sllw),
143 "srl" => r_assemble!(Srl),
144 "sra" => r_assemble!(Sra),
145 "srlw" => r_assemble!(Srlw),
146 "sraw" => r_assemble!(Sraw),
147 "sll" => r_assemble!(Sll),
148 "slt" => r_assemble!(Slt),
149 "sltu" => r_assemble!(Sltu),
150 "mul" => r_assemble!(Mul),
151 "mulh" => r_assemble!(Mulh),
152 "mulhsu" => r_assemble!(Mulhsu),
153 "mulhu" => r_assemble!(Mulhu),
154 "div" => r_assemble!(Div),
155 "divu" => r_assemble!(Divu),
156 "rem" => r_assemble!(Rem),
157 "remu" => r_assemble!(Remu),
158 "mulw" => r_assemble!(Mulw),
159 "divw" => r_assemble!(Divw),
160 "divuw" => r_assemble!(Divuw),
161 "remw" => r_assemble!(Remw),
162 "remuw" => r_assemble!(Remuw),
163 "lb" => l_assemble!(Lb),
165 "lbu" => l_assemble!(Lbu),
166 "lhu" => l_assemble!(Lhu),
167 "lw" => l_assemble!(Lw),
168 "lwu" => l_assemble!(Lwu),
169 "lh" => l_assemble!(Lh),
170 "ld" => l_assemble!(Ld),
172 "sd" => s_assemble!(Sd),
173 "sw" => s_assemble!(Sw),
174 "sh" => s_assemble!(Sh),
175 "sb" => s_assemble!(Sb),
176 "blt" => b_assemble!(Blt),
178 "beq" => b_assemble!(Beq),
179 "bne" => b_assemble!(Bne),
180 "bge" => b_assemble!(Bge),
181 "bgeu" => b_assemble!(Bgeu),
182 "bltu" => b_assemble!(Bltu),
183 "jalr" => {
184 if operands.len() != 2 {
185 Err("jalr instruction requires 2 operands".to_owned())
186 } else {
187 let (base, offset) = parse_address_expression(operands[1])?;
188 Ok(Instruction::Jalr {
189 dest: IRegister::try_from(operands[0])?,
190 base,
191 offset: IImmediate::try_from(offset)?,
192 })
193 }
194 }
195 "jal" => {
196 if operands.len() != 2 {
197 Err("jal instruction requires 2 operands".to_owned())
198 } else {
199 Ok(Instruction::Jal {
200 dest: IRegister::try_from(operands[0])?,
201 offset: JImmediate::try_from(parse_int(operands[1])?)?,
202 })
203 }
204 }
205 "lui" => {
206 if operands.len() != 2 {
207 Err("lui instruction requires 2 operands".to_owned())
208 } else {
209 let int: i64 = parse_int(operands[1])?;
210 if int > 2i64.pow(19) - 1 || int < -2i64.pow(19) {
211 Err("UImmediate out of range".to_owned())
212 } else {
213 Ok(Instruction::Lui {
214 dest: IRegister::try_from(operands[0])?,
215 imm: UImmediate::try_from(int)?,
216 })
217 }
218 }
219 }
220 "auipc" => {
221 if operands.len() != 2 {
222 Err("auipc instruction requires 2 operands".to_owned())
223 } else {
224 let int: i64 = parse_int(operands[1])?;
225 if int > 2i64.pow(19) - 1 || int < -2i64.pow(19) {
226 Err("UImmediate out of range".to_owned())
227 } else {
228 Ok(Instruction::Auipc {
229 dest: IRegister::try_from(operands[0])?,
230 imm: UImmediate::try_from(int)?,
231 })
232 }
233 }
234 }
235 "fence" => {
236 if mnemonics.len() == 1 {
237 if operands.len() != 2 {
238 Err("fence instruction requires 2 operands".to_owned())
239 } else {
240 let ops =
241 parse_fence_set(operands[1]) | (parse_fence_set(operands[0]) << 4);
242 Ok(Instruction::Fence {
243 rd: IRegister::Zero,
245 rs1: IRegister::Zero,
246 ops,
247 fm: 0, })
249 }
250 } else if mnemonics[1] == "tso" {
251 if operands.len() != 2 {
252 Err("fence.tso instruction requires 2 operands".to_owned())
253 } else {
254 let ops =
255 parse_fence_set(operands[1]) | (parse_fence_set(operands[0]) << 4);
256 if ops != (parse_fence_set("rw") | (parse_fence_set("rw") << 4)) {
257 Err("fence.tso should be rw,rw".to_owned())
258 } else {
259 Ok(Instruction::Fence {
260 rd: IRegister::Zero,
262 rs1: IRegister::Zero,
263 ops,
264 fm: 0b1000, })
266 }
267 }
268 } else if mnemonics[1] == "i" {
269 if operands.len() != 0 {
270 Err("fence.i requires 0 operands".to_owned())
271 } else {
272 Ok(Instruction::FenceI)
273 }
274 } else {
275 Err("invalid fence".to_owned())
276 }
277 }
278 "lr" => {
280 if mnemonics.len() == 1 {
281 Err("lr must have size (w/d)".to_owned())
282 } else if mnemonics.len() == 2 {
283 if mnemonics[1] == "w" {
284 Ok(Instruction::LrW {
285 dest: IRegister::try_from(operands[0])?,
286 addr: IRegister::try_from(operands[1])?,
287 aq: false,
288 rl: false,
289 })
290 } else if mnemonics[1] == "d" {
291 Ok(Instruction::LrD {
292 dest: IRegister::try_from(operands[0])?,
293 addr: IRegister::try_from(operands[1])?,
294 aq: false,
295 rl: false,
296 })
297 } else {
298 Err("size of lr isntruction must be word (w) or doubleword (d)".to_owned())
299 }
300 } else if mnemonics.len() == 3 {
301 let (aq, rl) = match mnemonics[2] {
302 "" => (false, false),
303 "aq" => (true, false),
304 "rl" => (false, true),
305 "aqrl" => (true, true),
306 _ => return Err("ordering should be (aq)(rl)".to_owned()),
307 };
308 if mnemonics[1] == "w" {
309 Ok(Instruction::LrW {
310 dest: IRegister::try_from(operands[0])?,
311 addr: IRegister::try_from(operands[1])?,
312 aq,
313 rl,
314 })
315 } else if mnemonics[1] == "d" {
316 Ok(Instruction::LrD {
317 dest: IRegister::try_from(operands[0])?,
318 addr: IRegister::try_from(operands[1])?,
319 aq,
320 rl,
321 })
322 } else {
323 Err("size of lr isntruction must be word (w) or doubleword (d)".to_owned())
324 }
325 } else {
326 Err(
327 "lr instruction has too many suffixes, expected lr.size.ordering"
328 .to_owned(),
329 )
330 }
331 }
332 "sc" => amo_assemble!(Sc),
333 "amoswap" => amo_assemble!(Amoswap),
334 "amoadd" => amo_assemble!(Amoadd),
335 "amoxor" => amo_assemble!(Amoxor),
336 "amoand" => amo_assemble!(Amoand),
337 "amoor" => amo_assemble!(Amoor),
338 "amomin" => amo_assemble!(Amomin),
339 "amomax" => amo_assemble!(Amomax),
340 "amominu" => amo_assemble!(Amominu),
341 "amomaxu" => amo_assemble!(Amomaxu),
342 "flw" => {
343 if operands.len() != 2 {
344 Err("flw instruction requires 2 operands".to_owned())
345 } else {
346 let (base, offset) = parse_address_expression(operands[1])?;
347 Ok(Instruction::Flw {
348 dest: FRegister::try_from(operands[0])?,
349 base,
350 offset: IImmediate::try_from(offset)?,
351 })
352 }
353 }
354 "fsw" => {
355 if operands.len() != 2 {
356 Err("fsw instruction requires 2 operands".to_owned())
357 } else {
358 let (base, offset) = parse_address_expression(operands[1])?;
359 Ok(Instruction::Fsw {
360 base,
361 src: FRegister::try_from(operands[0])?,
362 offset: SImmediate::try_from(offset)?,
363 })
364 }
365 }
366 "fsqrt" => {
367 let rm = if operands.len() == 2 {
368 RoundingMode::DYN
369 } else if operands.len() == 3 {
370 RoundingMode::from_str(operands[2])?
371 } else {
372 return Err("fsqrt instruction requires 2 or 3 operands".to_owned());
373 };
374
375 match mnemonics.get(1) {
376 Some(&"s") => Ok(Instruction::FsqrtS {
377 dest: FRegister::try_from(operands[0])?,
378 src: FRegister::try_from(operands[1])?,
379 rm,
380 }),
381 Some(&"d") => Ok(Instruction::FsqrtD {
382 dest: FRegister::try_from(operands[0])?,
383 src: FRegister::try_from(operands[1])?,
384 rm,
385 }),
386 Some(_) => Err("fsqrt instructions requires prefix {s,d}".to_owned()),
387 None => Err("fsqrt instructions requires prefix {s,d}".to_owned()),
388 }
389 }
390 "fadd" => fr_assemble!(Fadd true),
391 "fsub" => fr_assemble!(Fsub true),
392 "fmul" => fr_assemble!(Fmul true),
393 "fdiv" => fr_assemble!(Fdiv true),
394 "fmin" => fr_assemble!(Fmin false),
395 "fmax" => fr_assemble!(Fmax false),
396 "fsgnj" => fr_assemble!(Fsgnj false),
397 "fsgnjx" => fr_assemble!(Fsgnjx false),
398 "fsgnjn" => fr_assemble!(Fsgnjn false),
399 "fmadd" => fr3_assemble!(Fmadd),
400 "fmsub" => fr3_assemble!(Fmsub),
401 "fnmsub" => fr3_assemble!(Fnmsub),
402 "fnmadd" => fr3_assemble!(Fnmadd),
403 "fcvt" => {
404 let rm = if operands.len() == 2 {
405 RoundingMode::DYN
406 } else if operands.len() == 3 {
407 RoundingMode::from_str(operands[2])?
408 } else {
409 return Err("fcvt instruction requires 2 or 3 operands".to_owned());
410 };
411
412 if mnemonics.len() == 3 {
413 match (mnemonics[1], mnemonics[2]) {
415 ("w", "s") => Ok(Instruction::FcvtWS {
416 dest: IRegister::try_from(operands[0])?,
417 src: FRegister::try_from(operands[1])?,
418 rm,
419 }),
420 ("wu", "s") => Ok(Instruction::FcvtWuS {
421 dest: IRegister::try_from(operands[0])?,
422 src: FRegister::try_from(operands[1])?,
423 rm,
424 }),
425 ("s", "w") => Ok(Instruction::FcvtSW {
426 dest: FRegister::try_from(operands[0])?,
427 src: IRegister::try_from(operands[1])?,
428 rm,
429 }),
430 ("s", "wu") => Ok(Instruction::FcvtSWu {
431 dest: FRegister::try_from(operands[0])?,
432 src: IRegister::try_from(operands[1])?,
433 rm,
434 }),
435 ("l", "s") => Ok(Instruction::FcvtLS {
436 dest: IRegister::try_from(operands[0])?,
437 src: FRegister::try_from(operands[1])?,
438 rm,
439 }),
440 ("lu", "s") => Ok(Instruction::FcvtLuS {
441 dest: IRegister::try_from(operands[0])?,
442 src: FRegister::try_from(operands[1])?,
443 rm,
444 }),
445 ("s", "l") => Ok(Instruction::FcvtSL {
446 dest: FRegister::try_from(operands[0])?,
447 src: IRegister::try_from(operands[1])?,
448 rm,
449 }),
450 ("s", "lu") => Ok(Instruction::FcvtSLu {
451 dest: FRegister::try_from(operands[0])?,
452 src: IRegister::try_from(operands[1])?,
453 rm,
454 }),
455 ("w", "d") => Ok(Instruction::FcvtWD {
456 dest: IRegister::try_from(operands[0])?,
457 src1: FRegister::try_from(operands[1])?,
458 rm,
459 }),
460 ("wu", "d") => Ok(Instruction::FcvtWuD {
461 dest: IRegister::try_from(operands[0])?,
462 src1: FRegister::try_from(operands[1])?,
463 rm,
464 }),
465 ("d", "w") => Ok(Instruction::FcvtDW {
466 dest: FRegister::try_from(operands[0])?,
467 src1: IRegister::try_from(operands[1])?,
468 rm,
469 }),
470 ("d", "wu") => Ok(Instruction::FcvtDWu {
471 dest: FRegister::try_from(operands[0])?,
472 src1: IRegister::try_from(operands[1])?,
473 rm,
474 }),
475 ("l", "d") => Ok(Instruction::FcvtLD {
476 dest: IRegister::try_from(operands[0])?,
477 src1: FRegister::try_from(operands[1])?,
478 rm,
479 }),
480 ("lu", "d") => Ok(Instruction::FcvtLuD {
481 dest: IRegister::try_from(operands[0])?,
482 src1: FRegister::try_from(operands[1])?,
483 rm,
484 }),
485 ("d", "l") => Ok(Instruction::FcvtDL {
486 dest: FRegister::try_from(operands[0])?,
487 src: IRegister::try_from(operands[1])?,
488 rm,
489 }),
490 ("d", "lu") => Ok(Instruction::FcvtDLu {
491 dest: FRegister::try_from(operands[0])?,
492 src: IRegister::try_from(operands[1])?,
493 rm,
494 }),
495 ("s", "d") => Ok(Instruction::FcvtSD {
496 dest: FRegister::try_from(operands[0])?,
497 src: FRegister::try_from(operands[1])?,
498 rm,
499 }),
500 ("d", "s") => Ok(Instruction::FcvtDS {
501 dest: FRegister::try_from(operands[0])?,
502 src: FRegister::try_from(operands[1])?,
503 rm,
504 }),
505 _ => Err("invalid fcvt suffixes".to_owned()),
506 }
507 } else {
508 Err("fcvt should have 2 suffixes".to_owned())
509 }
510 }
511 "fmv" => {
512 if operands.len() != 2 {
513 Err("fmv requires 2 operands".to_owned())
514 } else if mnemonics.len() == 3 {
515 match (mnemonics[1], mnemonics[2]) {
516 ("x", "w") => Ok(Instruction::FmvXW {
517 dest: IRegister::try_from(operands[0])?,
518 src: FRegister::try_from(operands[1])?,
519 }),
520 ("w", "x") => Ok(Instruction::FmvWX {
521 dest: FRegister::try_from(operands[0])?,
522 src: IRegister::try_from(operands[1])?,
523 }),
524 ("x", "d") => Ok(Instruction::FmvXD {
525 dest: IRegister::try_from(operands[0])?,
526 src: FRegister::try_from(operands[1])?,
527 }),
528 ("d", "x") => Ok(Instruction::FmvDX {
529 dest: FRegister::try_from(operands[0])?,
530 src: IRegister::try_from(operands[1])?,
531 }),
532 _ => Err("invalid fmv suffixes".to_owned()),
533 }
534 } else {
535 Err("fmv requires 2 suffixes".to_owned())
536 }
537 }
538 "feq" => {
539 if operands.len() != 3 {
540 Err("feq requires 3 operands".to_owned())
541 } else if mnemonics.len() == 2 {
542 match mnemonics[1] {
543 "s" => Ok(Instruction::FeqS {
544 dest: IRegister::try_from(operands[0])?,
545 src1: FRegister::try_from(operands[1])?,
546 src2: FRegister::try_from(operands[2])?,
547 }),
548 "d" => Ok(Instruction::FeqD {
549 dest: IRegister::try_from(operands[0])?,
550 src1: FRegister::try_from(operands[1])?,
551 src2: FRegister::try_from(operands[2])?,
552 }),
553 "q" => todo!(),
554 "h" => todo!(),
555 _ => Err("feq requires a suffix {s,d}".to_owned()),
556 }
557 } else {
558 Err("feq requires a suffix {s,d}".to_owned())
559 }
560 }
561 "flt" => {
562 if operands.len() != 3 {
563 Err("flt requires 3 operands".to_owned())
564 } else if mnemonics.len() == 2 {
565 match mnemonics[1] {
566 "s" => Ok(Instruction::FltS {
567 dest: IRegister::try_from(operands[0])?,
568 src1: FRegister::try_from(operands[1])?,
569 src2: FRegister::try_from(operands[2])?,
570 }),
571 "d" => Ok(Instruction::FltD {
572 dest: IRegister::try_from(operands[0])?,
573 src1: FRegister::try_from(operands[1])?,
574 src2: FRegister::try_from(operands[2])?,
575 }),
576 "q" => todo!(),
577 "h" => todo!(),
578 _ => Err("flt requires a suffix {s,d}".to_owned()),
579 }
580 } else {
581 Err("flt requires a suffix {s,d}".to_owned())
582 }
583 }
584 "fle" => {
585 if operands.len() != 3 {
586 Err("fle requires 3 operands".to_owned())
587 } else if mnemonics.len() == 2 {
588 match mnemonics[1] {
589 "s" => Ok(Instruction::FleS {
590 dest: IRegister::try_from(operands[0])?,
591 src1: FRegister::try_from(operands[1])?,
592 src2: FRegister::try_from(operands[2])?,
593 }),
594 "d" => Ok(Instruction::FleD {
595 dest: IRegister::try_from(operands[0])?,
596 src1: FRegister::try_from(operands[1])?,
597 src2: FRegister::try_from(operands[2])?,
598 }),
599 "q" => todo!(),
600 "h" => todo!(),
601 _ => Err("fle requires a suffix {s,d}".to_owned()),
602 }
603 } else {
604 Err("fle requires a suffix {s,d}".to_owned())
605 }
606 }
607 "fclass" => {
608 if operands.len() != 2 {
609 Err("fclass requires 2 operands".to_owned())
610 } else if mnemonics.len() == 2 {
611 match mnemonics[1] {
612 "s" => Ok(Instruction::FclassS {
613 dest: IRegister::try_from(operands[0])?,
614 src: FRegister::try_from(operands[1])?,
615 }),
616 "d" => Ok(Instruction::FclassD {
617 dest: IRegister::try_from(operands[0])?,
618 src1: FRegister::try_from(operands[1])?,
619 }),
620 "q" => todo!(),
621 "h" => todo!(),
622 _ => Err("fclass requires a suffix {s,d}".to_owned()),
623 }
624 } else {
625 Err("fclass requires a suffix {s,d}".to_owned())
626 }
627 }
628 "csrrw" => {
629 if operands.len() != 3 {
630 Err("csrrw requires 3 operands".to_owned())
631 } else {
632 Ok(Instruction::Csrrw {
633 dest: IRegister::try_from(operands[0])?,
634 src: IRegister::try_from(operands[2])?,
635 csr: CSR::try_from(parse_int(operands[1])?)?,
636 })
637 }
638 }
639 "csrrs" => {
640 if operands.len() != 3 {
641 Err("csrrs requires 3 operands".to_owned())
642 } else {
643 Ok(Instruction::Csrrs {
644 dest: IRegister::try_from(operands[0])?,
645 src: IRegister::try_from(operands[2])?,
646 csr: CSR::try_from(parse_int(operands[1])?)?,
647 })
648 }
649 }
650 "csrrc" => {
651 if operands.len() != 3 {
652 Err("csrrc requires 3 operands".to_owned())
653 } else {
654 Ok(Instruction::Csrrc {
655 dest: IRegister::try_from(operands[0])?,
656 src: IRegister::try_from(operands[2])?,
657 csr: CSR::try_from(parse_int(operands[1])?)?,
658 })
659 }
660 }
661 "csrrwi" => {
662 if operands.len() != 3 {
663 Err("csrrwi requires 3 operands".to_owned())
664 } else {
665 Ok(Instruction::Csrrwi {
666 dest: IRegister::try_from(operands[0])?,
667 imm: CSRImmediate::try_from(parse_int(operands[2])?)?,
668 csr: CSR::try_from(parse_int(operands[1])?)?,
669 })
670 }
671 }
672 "csrrsi" => {
673 if operands.len() != 3 {
674 Err("csrrsi requires 3 operands".to_owned())
675 } else {
676 Ok(Instruction::Csrrsi {
677 dest: IRegister::try_from(operands[0])?,
678 imm: CSRImmediate::try_from(parse_int(operands[2])?)?,
679 csr: CSR::try_from(parse_int(operands[1])?)?,
680 })
681 }
682 }
683 "csrrci" => {
684 if operands.len() != 3 {
685 Err("csrrci requires 3 operands".to_owned())
686 } else {
687 Ok(Instruction::Csrrci {
688 dest: IRegister::try_from(operands[0])?,
689 imm: CSRImmediate::try_from(parse_int(operands[2])?)?,
690 csr: CSR::try_from(parse_int(operands[1])?)?,
691 })
692 }
693 }
694 "fld" => {
695 if operands.len() != 2 {
696 Err("fld instruction requires 2 operands".to_owned())
697 } else {
698 let (base, offset) = parse_address_expression(operands[1])?;
699 Ok(Instruction::Fld {
700 dest: FRegister::try_from(operands[0])?,
701 base,
702 offset: IImmediate::try_from(offset)?,
703 })
704 }
705 }
706 "fsd" => {
707 if operands.len() != 2 {
708 Err("fsd instruction requires 2 operands".to_owned())
709 } else {
710 let (base, offset) = parse_address_expression(operands[1])?;
711 Ok(Instruction::Fsd {
712 base,
713 src: FRegister::try_from(operands[0])?,
714 offset: SImmediate::try_from(offset)?,
715 })
716 }
717 }
718 _ => Err(format!("unknown mnemonic: {}", mnemonic)),
719 };
720 x.map(AssemblyResult::I)
721 }
722}
723
724fn compressed_assemble(mnemonics: &[&str], operands: Vec<&str>) -> Result<CInstruction, String> {
725 match mnemonics[0] {
726 "addi4spn" => {
727 if operands.len() != 2 {
728 Err("c.addi4spn requires 2 operands".to_owned())
729 } else {
730 Ok(CInstruction::ADDI4SPN {
731 dest: CIRegister::try_from(operands[0])?,
732 imm: CWideImmediate::try_from(parse_int(operands[1])?)?,
733 })
734 }
735 }
736 "fld" => {
737 if operands.len() != 2 {
738 Err("c.fld requires 2 operands".to_owned())
739 } else {
740 let (base, imm) = parse_address_expression_compressed(operands[1])?;
741 Ok(CInstruction::FLD {
742 dest: CFRegister::try_from(operands[0])?,
743 base,
744 offset: CDImmediate::try_from(imm)?,
745 })
746 }
747 }
748 "lw" => {
749 if operands.len() != 2 {
750 Err("c.lw requires 2 operands".to_owned())
751 } else {
752 let (base, imm) = parse_address_expression_compressed(operands[1])?;
753 Ok(CInstruction::LW {
754 dest: CIRegister::try_from(operands[0])?,
755 base,
756 offset: CWImmediate::try_from(imm)?,
757 })
758 }
759 }
760 "ld" => {
761 if operands.len() != 2 {
762 Err("c.ld requires 2 operands".to_owned())
763 } else {
764 let (base, imm) = parse_address_expression_compressed(operands[1])?;
765 Ok(CInstruction::LD {
766 dest: CIRegister::try_from(operands[0])?,
767 base,
768 offset: CDImmediate::try_from(imm)?,
769 })
770 }
771 }
772 "fsd" => {
773 if operands.len() != 2 {
774 Err("c.fsd requires 2 operands".to_owned())
775 } else {
776 let (base, imm) = parse_address_expression_compressed(operands[1])?;
777 Ok(CInstruction::FSD {
778 src: CFRegister::try_from(operands[0])?,
779 base,
780 offset: CDImmediate::try_from(imm)?,
781 })
782 }
783 }
784 "sw" => {
785 if operands.len() != 2 {
786 Err("c.sw requires 2 operands".to_owned())
787 } else {
788 let (base, imm) = parse_address_expression_compressed(operands[1])?;
789 Ok(CInstruction::SW {
790 src: CIRegister::try_from(operands[0])?,
791 base,
792 offset: CWImmediate::try_from(imm)?,
793 })
794 }
795 }
796 "sd" => {
797 if operands.len() != 2 {
798 Err("c.sd requires 2 operands".to_owned())
799 } else {
800 let (base, imm) = parse_address_expression_compressed(operands[1])?;
801 Ok(CInstruction::SD {
802 src: CIRegister::try_from(operands[0])?,
803 base,
804 offset: CDImmediate::try_from(imm)?,
805 })
806 }
807 }
808 "addi" => ci_assemble!(ADDI),
809 "addiw" => ci_assemble!(ADDIW),
810 "li" => ci_assemble!(LI),
811 "addi16sp" => {
812 if operands.len() != 1 {
813 Err("c.addi16sp requires 1 operands".to_owned())
814 } else {
815 let i = parse_int(operands[0])?;
816
817 Ok(CInstruction::ADDI16SP {
818 imm: C16SPImmediate::try_from(i)?,
819 })
820 }
821 }
822 "lui" => ci_assemble!(LUI),
823 "srli" => {
824 if operands.len() != 2 {
825 Err("c.srli requires 2 operands".to_owned())
826 } else {
827 Ok(CInstruction::SRLI {
828 dest: CIRegister::try_from(operands[0])?,
829 shamt: CShamt::try_from(parse_int(operands[1])?)?,
830 })
831 }
832 }
833 "srai" => {
834 if operands.len() != 2 {
835 Err("c.srai requires 2 operands".to_owned())
836 } else {
837 Ok(CInstruction::SRAI {
838 dest: CIRegister::try_from(operands[0])?,
839 shamt: CShamt::try_from(parse_int(operands[1])?)?,
840 })
841 }
842 }
843 "andi" => {
844 if operands.len() != 2 {
845 Err("c.andi requires 2 operands".to_owned())
846 } else {
847 Ok(CInstruction::ANDI {
848 dest: CIRegister::try_from(operands[0])?,
849 imm: CIImmediate::try_from(parse_int(operands[1])?)?,
850 })
851 }
852 }
853 "sub" => cr_assemble!(SUB),
854 "xor" => cr_assemble!(XOR),
855 "or" => cr_assemble!(OR),
856 "and" => cr_assemble!(AND),
857 "subw" => cr_assemble!(SUBW),
858 "addw" => cr_assemble!(ADDW),
859 "j" => {
860 if operands.len() != 1 {
861 Err("c.j requires 1 operand".to_owned())
862 } else {
863 Ok(CInstruction::J {
864 offset: CJImmediate::try_from(parse_int(operands[0])?)?,
865 })
866 }
867 }
868 "beqz" => {
869 if operands.len() != 2 {
870 Err("c.beqz requires 2 operands".to_owned())
871 } else {
872 Ok(CInstruction::BEQZ {
873 src: CIRegister::try_from(operands[0])?,
874 offset: CBImmediate::try_from(parse_int(operands[1])?)?,
875 })
876 }
877 }
878 "bnez" => {
879 if operands.len() != 2 {
880 Err("c.bne requires 2 operands".to_owned())
881 } else {
882 Ok(CInstruction::BNEZ {
883 src: CIRegister::try_from(operands[0])?,
884 offset: CBImmediate::try_from(parse_int(operands[1])?)?,
885 })
886 }
887 }
888 "slli" => {
889 if operands.len() != 2 {
890 Err("c.slli requires 2 operands".to_owned())
891 } else {
892 Ok(CInstruction::SLLI {
893 dest: IRegister::try_from(operands[0])?,
894 shamt: CShamt::try_from(parse_int(operands[1])?)?,
895 })
896 }
897 }
898 "fldsp" => {
899 if operands.len() != 2 {
900 Err("c.fldsp requires 2 operands".to_owned())
901 } else {
902 Ok(CInstruction::FLDSP {
903 dest: FRegister::try_from(operands[0])?,
904 offset: CDSPImmediate::try_from(parse_int(operands[1])?)?,
905 })
906 }
907 }
908 "ldsp" => {
909 if operands.len() != 2 {
910 Err("c.ldsp requires 2 operands".to_owned())
911 } else {
912 Ok(CInstruction::LDSP {
913 dest: IRegister::try_from(operands[0])?,
914 offset: CDSPImmediate::try_from(parse_int(operands[1])?)?,
915 })
916 }
917 }
918 "lwsp" => {
919 if operands.len() != 2 {
920 Err("c.lwsp requires 2 operands".to_owned())
921 } else {
922 Ok(CInstruction::LWSP {
923 dest: IRegister::try_from(operands[0])?,
924 offset: CWSPImmediate::try_from(parse_int(operands[1])?)?,
925 })
926 }
927 }
928 "jr" => {
929 if operands.len() != 1 {
930 Err("c.jr requires 1 operand".to_owned())
931 } else {
932 Ok(CInstruction::JR {
933 src: IRegister::try_from(operands[0])?,
934 })
935 }
936 }
937 "jalr" => {
938 if operands.len() != 1 {
939 Err("c.jalr requires 1 operand".to_owned())
940 } else {
941 Ok(CInstruction::JALR {
942 src: IRegister::try_from(operands[0])?,
943 })
944 }
945 }
946 "ebreak" => {
947 if operands.len() != 0 {
948 Err("c.jr requires 0 operands".to_owned())
949 } else {
950 Ok(CInstruction::EBREAK)
951 }
952 }
953 "add" => {
954 if operands.len() != 2 {
955 Err("c.add requires 2 operands".to_owned())
956 } else {
957 Ok(CInstruction::ADD {
958 dest: IRegister::try_from(operands[0])?,
959 src: IRegister::try_from(operands[1])?,
960 })
961 }
962 }
963 "fsdsp" => {
964 if operands.len() != 2 {
965 Err("c.fsdsp requires 2 operands".to_owned())
966 } else {
967 Ok(CInstruction::FSDSP {
968 src: FRegister::try_from(operands[0])?,
969 offset: CSDSPImmediate::try_from(parse_int(operands[1])?)?,
970 })
971 }
972 }
973 "swsp" => {
974 if operands.len() != 2 {
975 Err("c.swsp requires 2 operands".to_owned())
976 } else {
977 Ok(CInstruction::SWSP {
978 src: IRegister::try_from(operands[0])?,
979 offset: CSWSPImmediate::try_from(parse_int(operands[1])?)?,
980 })
981 }
982 }
983 "sdsp" => {
984 if operands.len() != 2 {
985 Err("c.sdsp requires 2 operands".to_owned())
986 } else {
987 Ok(CInstruction::SDSP {
988 src: IRegister::try_from(operands[0])?,
989 offset: CSDSPImmediate::try_from(parse_int(operands[1])?)?,
990 })
991 }
992 }
993 "mv" => {
994 if operands.len() != 2 {
995 Err("c.mv requires 2 operands".to_owned())
996 } else {
997 Ok(CInstruction::MV {
998 dest: IRegister::try_from(operands[0])?,
999 src: IRegister::try_from(operands[1])?,
1000 })
1001 }
1002 }
1003 _ => Err(format!(
1004 "unknown compressed instruction mnemonic: {}",
1005 mnemonics[0]
1006 )),
1007 }
1008}