riscv_codec/
assembly.rs

1use riscv_codec_proc_macros::{
2    amo_assemble, b_assemble, ci_assemble, cr_assemble, fr_assemble, i_assemble, l_assemble,
3    r_assemble, s_assemble, sh_assemble, shw_assemble,
4};
5
6use crate::immediates::*;
7use crate::instruction::RoundingMode;
8use crate::register::{CFRegister, CIRegister, FRegister, IRegister};
9use crate::{cinstruction::CInstruction, instruction::Instruction};
10
11fn parse_int(str: &str) -> Result<i64, String> {
12    match str.parse::<i64>() {
13        Ok(e) => Ok(e),
14        Err(_) => Err(format!("unable to parse int:{str}").to_owned()),
15    }
16}
17
18fn parse_address_expression(str: &str) -> Result<(IRegister, i64), String> {
19    let (offset, register): (&str, &str) = if let Some(x) = str.split_once("(") {
20        x
21    } else {
22        panic!("no (");
23    };
24    match register.strip_suffix(")") {
25        Some(y) => {
26            let r = IRegister::from_string(y)?;
27            let i = parse_int(offset)?;
28            Ok((r, i))
29        }
30        _ => Err("Address expression should end in a )".to_owned()),
31    }
32}
33
34fn parse_address_expression_compressed(str: &str) -> Result<(CIRegister, i64), String> {
35    let (offset, register): (&str, &str) = if let Some(x) = str.split_once("(") {
36        x
37    } else {
38        panic!("no (");
39    };
40    match register.strip_suffix(")") {
41        Some(y) => {
42            let r = CIRegister::try_from(y)?;
43            let i = parse_int(offset)?;
44            Ok((r, i))
45        }
46        _ => Err("Address expression should end in a )".to_owned()),
47    }
48}
49
50/// Converts a string representing operations into a fence u8
51fn parse_fence_set(s: &str) -> u8 {
52    let mut x = 0;
53    if s.contains("w") {
54        x |= 0b1;
55    }
56    if s.contains("r") {
57        x |= 0b10;
58    }
59    if s.contains("o") {
60        x |= 0b100;
61    }
62    if s.contains("i") {
63        x |= 0b1000;
64    }
65    x
66}
67
68#[derive(Debug, PartialEq)]
69pub enum AssemblyResult {
70    I(Instruction),
71    C(CInstruction),
72}
73impl AssemblyResult {
74    pub fn c(self) -> CInstruction {
75        match self {
76            AssemblyResult::I(_) => panic!("c called on regular instruction"),
77            AssemblyResult::C(cinstruction) => cinstruction,
78        }
79    }
80    pub fn i(self) -> Instruction {
81        match self {
82            AssemblyResult::I(instruction) => instruction,
83            AssemblyResult::C(_) => panic!("i called on compressed instruction"),
84        }
85    }
86}
87
88/// Constructs an `Instruction` from a line of assembly.
89pub fn assemble_line(line: &str) -> Result<AssemblyResult, String> {
90    let (mnemonic, operands): (&str, &str) = if let Some(x) = line.split_once(" ") {
91        x
92    } else {
93        (line, "")
94    };
95
96    let mnemonics: Vec<&str> = mnemonic.split(".").collect();
97
98    let operands: Vec<&str> = if operands.is_empty() {
99        vec![]
100    } else {
101        operands.split(',').collect()
102    };
103    let operands: Vec<&str> = operands
104        .iter()
105        .map(|operand| operand.to_owned().trim())
106        .collect();
107
108    if mnemonics[0] == "c" {
109        if mnemonics.len() == 1 {
110            Err("compressed instruction must be specified".to_owned())
111        } else {
112            compressed_assemble(&mnemonics[1..], operands).map(AssemblyResult::C)
113        }
114    } else {
115        let x = match mnemonics[0] {
116            // register-immediate instructions
117            "addi" => i_assemble!(ADDI),
118            "addiw" => i_assemble!(ADDIW),
119            "andi" => i_assemble!(ANDI),
120            "ori" => i_assemble!(ORI),
121            "xori" => i_assemble!(XORI),
122            "slti" => i_assemble!(SLTI),
123            "sltiu" => i_assemble!(SLTIU),
124            "slli" => sh_assemble!(SLLI),
125            "srai" => sh_assemble!(SRAI),
126            "sraiw" => shw_assemble!(SRAIW),
127            "srli" => sh_assemble!(SRLI),
128            "srliw" => shw_assemble!(SRLIW),
129            "slliw" => shw_assemble!(SLLIW),
130            // register-register instructions
131            "add" => r_assemble!(ADD),
132            "addw" => r_assemble!(ADDW),
133            "subw" => r_assemble!(SUBW),
134            "and" => r_assemble!(AND),
135            "sub" => r_assemble!(SUB),
136            "or" => r_assemble!(OR),
137            "xor" => r_assemble!(XOR),
138            "sllw" => r_assemble!(SLLW),
139            "srl" => r_assemble!(SRL),
140            "sra" => r_assemble!(SRA),
141            "srlw" => r_assemble!(SRLW),
142            "sraw" => r_assemble!(SRAW),
143            "sll" => r_assemble!(SLL),
144            "slt" => r_assemble!(SLT),
145            "sltu" => r_assemble!(SLTU),
146            "mul" => r_assemble!(MUL),
147            "mulh" => r_assemble!(MULH),
148            "mulhsu" => r_assemble!(MULHSU),
149            "mulhu" => r_assemble!(MULHU),
150            "div" => r_assemble!(DIV),
151            "divu" => r_assemble!(DIVU),
152            "rem" => r_assemble!(REM),
153            "remu" => r_assemble!(REMU),
154            "mulw" => r_assemble!(MULW),
155            "divw" => r_assemble!(DIVW),
156            "divuw" => r_assemble!(DIVUW),
157            "remw" => r_assemble!(REMW),
158            "remuw" => r_assemble!(REMUW),
159            // load instructions
160            "lb" => l_assemble!(LB),
161            "lbu" => l_assemble!(LBU),
162            "lhu" => l_assemble!(LHU),
163            "lw" => l_assemble!(LW),
164            "lwu" => l_assemble!(LWU),
165            "lh" => l_assemble!(LH),
166            // store instructions
167            "ld" => l_assemble!(LD),
168            "sd" => s_assemble!(SD),
169            "sw" => s_assemble!(SW),
170            "sh" => s_assemble!(SH),
171            "sb" => s_assemble!(SB),
172            // branch instructions
173            "blt" => b_assemble!(BLT),
174            "beq" => b_assemble!(BEQ),
175            "bne" => b_assemble!(BNE),
176            "bge" => b_assemble!(BGE),
177            "bgeu" => b_assemble!(BGEU),
178            "bltu" => b_assemble!(BLTU),
179            "jalr" => {
180                if operands.len() != 2 {
181                    Err("jalr instruction requires 2 operands".to_owned())
182                } else {
183                    let (base, offset) = parse_address_expression(operands[1])?;
184                    Ok(Instruction::JALR {
185                        dest: IRegister::from_string(operands[0])?,
186                        base,
187                        offset: IImmediate::try_from(offset)?,
188                    })
189                }
190            }
191            "jal" => {
192                if operands.len() != 2 {
193                    Err("jal instruction requires 2 operands".to_owned())
194                } else {
195                    Ok(Instruction::JAL {
196                        dest: IRegister::from_string(operands[0])?,
197                        offset: JImmediate::try_from(parse_int(operands[1])?)?,
198                    })
199                }
200            }
201            "lui" => {
202                if operands.len() != 2 {
203                    Err("lui instruction requires 2 operands".to_owned())
204                } else {
205                    let int: i64 = parse_int(operands[1])?;
206                    if int > 2i64.pow(19) - 1 || int < -2i64.pow(19) {
207                        Err("UImmediate out of range".to_owned())
208                    } else {
209                        Ok(Instruction::LUI {
210                            dest: IRegister::from_string(operands[0])?,
211                            imm: UImmediate::try_from(int)?,
212                        })
213                    }
214                }
215            }
216            "auipc" => {
217                if operands.len() != 2 {
218                    Err("auipc instruction requires 2 operands".to_owned())
219                } else {
220                    let int: i64 = parse_int(operands[1])?;
221                    if int > 2i64.pow(19) - 1 || int < -2i64.pow(19) {
222                        Err("UImmediate out of range".to_owned())
223                    } else {
224                        Ok(Instruction::AUIPC {
225                            dest: IRegister::from_string(operands[0])?,
226                            imm: UImmediate::try_from(int)?,
227                        })
228                    }
229                }
230            }
231            "fence" => {
232                if mnemonics.len() == 1 {
233                    if operands.len() != 2 {
234                        Err("fence instruction requires 2 operands".to_owned())
235                    } else {
236                        let ops =
237                            parse_fence_set(operands[1]) | (parse_fence_set(operands[0]) << 4);
238                        Ok(Instruction::FENCE {
239                            // rd and rs1 are currently unused
240                            rd: IRegister::Zero,
241                            rs1: IRegister::Zero,
242                            ops,
243                            fm: 0, //fm field, always zero for a non-tso fence
244                        })
245                    }
246                } else if mnemonics[1] == "tso" {
247                    if operands.len() != 2 {
248                        Err("fence.tso instruction requires 2 operands".to_owned())
249                    } else {
250                        let ops =
251                            parse_fence_set(operands[1]) | (parse_fence_set(operands[0]) << 4);
252                        if ops != (parse_fence_set("rw") | (parse_fence_set("rw") << 4)) {
253                            Err("fence.tso should be rw,rw".to_owned())
254                        } else {
255                            Ok(Instruction::FENCE {
256                                // rd and rs1 are currently unused
257                                rd: IRegister::Zero,
258                                rs1: IRegister::Zero,
259                                ops,
260                                fm: 0b1000, // tso fence
261                            })
262                        }
263                    }
264                } else if mnemonics[1] == "i" {
265                    if operands.len() != 0 {
266                        Err("fence.i requires 0 operands".to_owned())
267                    } else {
268                        Ok(Instruction::FENCEI)
269                    }
270                } else {
271                    Err("invalid fence".to_owned())
272                }
273            }
274            // LR can't use `amo_assemble!` because it only has two operands
275            "lr" => {
276                if mnemonics.len() == 1 {
277                    Err("lr must have size (w/d)".to_owned())
278                } else if mnemonics.len() == 2 {
279                    if mnemonics[1] == "w" {
280                        Ok(Instruction::LRW {
281                            dest: IRegister::from_string(operands[0])?,
282                            addr: IRegister::from_string(operands[1])?,
283                            aq: false,
284                            rl: false,
285                        })
286                    } else if mnemonics[1] == "d" {
287                        Ok(Instruction::LRD {
288                            dest: IRegister::from_string(operands[0])?,
289                            addr: IRegister::from_string(operands[1])?,
290                            aq: false,
291                            rl: false,
292                        })
293                    } else {
294                        Err("size of lr isntruction must be word (w) or doubleword (d)".to_owned())
295                    }
296                } else if mnemonics.len() == 3 {
297                    let (aq, rl) = match mnemonics[2] {
298                        "" => (false, false),
299                        "aq" => (true, false),
300                        "rl" => (false, true),
301                        "aqrl" => (true, true),
302                        _ => return Err("ordering should be (aq)(rl)".to_owned()),
303                    };
304                    if mnemonics[1] == "w" {
305                        Ok(Instruction::LRW {
306                            dest: IRegister::from_string(operands[0])?,
307                            addr: IRegister::from_string(operands[1])?,
308                            aq,
309                            rl,
310                        })
311                    } else if mnemonics[1] == "d" {
312                        Ok(Instruction::LRD {
313                            dest: IRegister::from_string(operands[0])?,
314                            addr: IRegister::from_string(operands[1])?,
315                            aq,
316                            rl,
317                        })
318                    } else {
319                        Err("size of lr isntruction must be word (w) or doubleword (d)".to_owned())
320                    }
321                } else {
322                    Err(
323                        "lr instruction has too many suffixes, expected lr.size.ordering"
324                            .to_owned(),
325                    )
326                }
327            }
328            "sc" => amo_assemble!(SC),
329            "amoswap" => amo_assemble!(AMOSWAP),
330            "amoadd" => amo_assemble!(AMOADD),
331            "amoxor" => amo_assemble!(AMOXOR),
332            "amoand" => amo_assemble!(AMOAND),
333            "amoor" => amo_assemble!(AMOOR),
334            "amomin" => amo_assemble!(AMOMIN),
335            "amomax" => amo_assemble!(AMOMAX),
336            "amominu" => amo_assemble!(AMOMINU),
337            "amomaxu" => amo_assemble!(AMOMAXU),
338            "flw" => {
339                if operands.len() != 2 {
340                    println!("{:?}", operands);
341                    Err("flw instruction requires 2 operands".to_owned())
342                } else {
343                    let (base, offset) = parse_address_expression(operands[1])?;
344                    Ok(Instruction::FLW {
345                        dest: FRegister::try_from(operands[0])?,
346                        base,
347                        offset: IImmediate::try_from(offset)?,
348                    })
349                }
350            }
351            "fsw" => {
352                if operands.len() != 2 {
353                    println!("{:?}", operands);
354                    Err("fsw instruction requires 2 operands".to_owned())
355                } else {
356                    let (base, offset) = parse_address_expression(operands[1])?;
357                    Ok(Instruction::FSW {
358                        base,
359                        src: FRegister::try_from(operands[0])?,
360                        offset: SImmediate::try_from(offset)?,
361                    })
362                }
363            }
364            "fsqrt" => {
365                if operands.len() != 2 {
366                    Err("fsqrt instruction requires 2 operands".to_owned())
367                } else if mnemonics.len() == 2 {
368                    Ok(Instruction::FSQRTS {
369                        dest: FRegister::try_from(operands[0])?,
370                        src: FRegister::try_from(operands[1])?,
371                        rm: RoundingMode::DYN,
372                    })
373                } else if mnemonics.len() == 3 {
374                    Ok(Instruction::FSQRTS {
375                        dest: FRegister::try_from(operands[0])?,
376                        src: FRegister::try_from(operands[1])?,
377                        rm: RoundingMode::from_str(mnemonics[2])?,
378                    })
379                } else {
380                    Err("fsqrt instruction requires a suffix {s,d}".to_owned())
381                }
382            }
383            "fadd" => fr_assemble!(FADD),
384            "fsub" => fr_assemble!(FSUB),
385            "fmul" => fr_assemble!(FMUL),
386            "fdiv" => fr_assemble!(FDIV),
387            "fmin" => {
388                if operands.len() != 3 {
389                    Err("fmin instruction requires 3 operands".to_owned())
390                } else if mnemonics.len() == 2 {
391                    Ok(Instruction::FMINS {
392                        dest: FRegister::try_from(operands[0])?,
393                        src1: FRegister::try_from(operands[1])?,
394                        src2: FRegister::try_from(operands[2])?,
395                    })
396                } else {
397                    Err("fmin instruction requires a suffix {s,d}".to_owned())
398                }
399            }
400            "fmax" => {
401                if operands.len() != 3 {
402                    Err("fmax instruction requires 3 operands".to_owned())
403                } else if mnemonics.len() == 2 {
404                    Ok(Instruction::FMAXS {
405                        dest: FRegister::try_from(operands[0])?,
406                        src1: FRegister::try_from(operands[1])?,
407                        src2: FRegister::try_from(operands[2])?,
408                    })
409                } else {
410                    Err("fmax instruction requires a suffix {s,d}".to_owned())
411                }
412            }
413            "fcvt" => {
414                if operands.len() != 2 {
415                    Err("fcvt requires 3 operands".to_owned())
416                } else if mnemonics.len() == 3 {
417                    // default rounding mode
418                    match (mnemonics[1], mnemonics[2]) {
419                        ("w", "s") => Ok(Instruction::FCVTWS {
420                            dest: IRegister::from_string(operands[0])?,
421                            src: FRegister::try_from(operands[1])?,
422                            rm: RoundingMode::DYN,
423                        }),
424                        ("wu", "s") => Ok(Instruction::FCVTWUS {
425                            dest: IRegister::from_string(operands[0])?,
426                            src: FRegister::try_from(operands[1])?,
427                            rm: RoundingMode::DYN,
428                        }),
429                        ("s", "w") => Ok(Instruction::FCVTSW {
430                            dest: FRegister::try_from(operands[0])?,
431                            src: IRegister::from_string(operands[1])?,
432                            rm: RoundingMode::DYN,
433                        }),
434                        ("s", "wu") => Ok(Instruction::FCVTSWU {
435                            dest: FRegister::try_from(operands[0])?,
436                            src: IRegister::from_string(operands[1])?,
437                            rm: RoundingMode::DYN,
438                        }),
439                        ("l", "s") => Ok(Instruction::FCVTLS {
440                            dest: IRegister::from_string(operands[0])?,
441                            src: FRegister::try_from(operands[1])?,
442                            rm: RoundingMode::DYN,
443                        }),
444                        ("lu", "s") => Ok(Instruction::FCVTLUS {
445                            dest: IRegister::from_string(operands[0])?,
446                            src: FRegister::try_from(operands[1])?,
447                            rm: RoundingMode::DYN,
448                        }),
449                        ("s", "l") => Ok(Instruction::FCVTSL {
450                            dest: FRegister::try_from(operands[0])?,
451                            src: IRegister::from_string(operands[1])?,
452                            rm: RoundingMode::DYN,
453                        }),
454                        ("s", "lu") => Ok(Instruction::FCVTSLU {
455                            dest: FRegister::try_from(operands[0])?,
456                            src: IRegister::from_string(operands[1])?,
457                            rm: RoundingMode::DYN,
458                        }),
459                        _ => Err("invalid fcvt suffixes".to_owned()),
460                    }
461                } else if mnemonics.len() == 4 {
462                    match (mnemonics[1], mnemonics[2]) {
463                        ("w", "s") => Ok(Instruction::FCVTWS {
464                            dest: IRegister::from_string(operands[0])?,
465                            src: FRegister::try_from(operands[1])?,
466                            rm: RoundingMode::from_str(mnemonics[3])?,
467                        }),
468                        ("wu", "s") => Ok(Instruction::FCVTWUS {
469                            dest: IRegister::from_string(operands[0])?,
470                            src: FRegister::try_from(operands[1])?,
471                            rm: RoundingMode::from_str(mnemonics[3])?,
472                        }),
473                        ("s", "w") => Ok(Instruction::FCVTSW {
474                            dest: FRegister::try_from(operands[0])?,
475                            src: IRegister::from_string(operands[1])?,
476                            rm: RoundingMode::from_str(mnemonics[3])?,
477                        }),
478                        ("s", "wu") => Ok(Instruction::FCVTSWU {
479                            dest: FRegister::try_from(operands[0])?,
480                            src: IRegister::from_string(operands[1])?,
481                            rm: RoundingMode::from_str(mnemonics[3])?,
482                        }),
483                        ("l", "s") => Ok(Instruction::FCVTLS {
484                            dest: IRegister::from_string(operands[0])?,
485                            src: FRegister::try_from(operands[1])?,
486                            rm: RoundingMode::from_str(mnemonics[3])?,
487                        }),
488                        ("lu", "s") => Ok(Instruction::FCVTLUS {
489                            dest: IRegister::from_string(operands[0])?,
490                            src: FRegister::try_from(operands[1])?,
491                            rm: RoundingMode::from_str(mnemonics[3])?,
492                        }),
493                        ("s", "l") => Ok(Instruction::FCVTSL {
494                            dest: FRegister::try_from(operands[0])?,
495                            src: IRegister::from_string(operands[1])?,
496                            rm: RoundingMode::from_str(mnemonics[3])?,
497                        }),
498                        ("s", "lu") => Ok(Instruction::FCVTSLU {
499                            dest: FRegister::try_from(operands[0])?,
500                            src: IRegister::from_string(operands[1])?,
501                            rm: RoundingMode::from_str(mnemonics[3])?,
502                        }),
503                        _ => Err("invalid fcvt suffixes".to_owned()),
504                    }
505                } else {
506                    Err("fcvt should have 2 or 3 suffixes".to_owned())
507                }
508            }
509            "fmv" => {
510                if operands.len() != 2 {
511                    Err("fmv requires 2 operands".to_owned())
512                } else if mnemonics.len() == 3 {
513                    match (mnemonics[1], mnemonics[2]) {
514                        ("x", "w") => Ok(Instruction::FMVXW {
515                            dest: IRegister::from_string(operands[0])?,
516                            src: FRegister::try_from(operands[1])?,
517                        }),
518                        ("w", "x") => Ok(Instruction::FMVWX {
519                            dest: FRegister::try_from(operands[0])?,
520                            src: IRegister::from_string(operands[1])?,
521                        }),
522                        _ => Err("invalid fmv suffixes".to_owned()),
523                    }
524                } else {
525                    Err("fmv requires 2 suffixes".to_owned())
526                }
527            }
528            "feq" => {
529                if operands.len() != 3 {
530                    Err("feq requires 3 operands".to_owned())
531                } else if mnemonics.len() == 2 {
532                    match mnemonics[1] {
533                        "s" => Ok(Instruction::FEQS {
534                            dest: IRegister::from_string(operands[0])?,
535                            src1: FRegister::try_from(operands[1])?,
536                            src2: FRegister::try_from(operands[2])?,
537                        }),
538                        "d" => todo!(),
539                        "q" => todo!(),
540                        "h" => todo!(),
541                        _ => Err("feq requires a suffix {s,d}".to_owned()),
542                    }
543                } else {
544                    Err("feq requires a suffix {s,d}".to_owned())
545                }
546            }
547            "flt" => {
548                if operands.len() != 3 {
549                    Err("flt requires 3 operands".to_owned())
550                } else if mnemonics.len() == 2 {
551                    match mnemonics[1] {
552                        "s" => Ok(Instruction::FLTS {
553                            dest: IRegister::from_string(operands[0])?,
554                            src1: FRegister::try_from(operands[1])?,
555                            src2: FRegister::try_from(operands[2])?,
556                        }),
557                        "d" => todo!(),
558                        "q" => todo!(),
559                        "h" => todo!(),
560                        _ => Err("flt requires a suffix {s,d}".to_owned()),
561                    }
562                } else {
563                    Err("flt requires a suffix {s,d}".to_owned())
564                }
565            }
566            "fle" => {
567                if operands.len() != 3 {
568                    Err("fle requires 3 operands".to_owned())
569                } else if mnemonics.len() == 2 {
570                    match mnemonics[1] {
571                        "s" => Ok(Instruction::FLES {
572                            dest: IRegister::from_string(operands[0])?,
573                            src1: FRegister::try_from(operands[1])?,
574                            src2: FRegister::try_from(operands[2])?,
575                        }),
576                        "d" => todo!(),
577                        "q" => todo!(),
578                        "h" => todo!(),
579                        _ => Err("fle requires a suffix {s,d}".to_owned()),
580                    }
581                } else {
582                    Err("fle requires a suffix {s,d}".to_owned())
583                }
584            }
585            "fclass" => {
586                if operands.len() != 2 {
587                    Err("fclass requires 2 operands".to_owned())
588                } else if mnemonics.len() == 2 {
589                    match mnemonics[1] {
590                        "s" => Ok(Instruction::FCLASSS {
591                            dest: IRegister::from_string(operands[0])?,
592                            src: FRegister::try_from(operands[1])?,
593                        }),
594                        "d" => todo!(),
595                        "q" => todo!(),
596                        "h" => todo!(),
597                        _ => Err("fle requires a suffix {s,d}".to_owned()),
598                    }
599                } else {
600                    Err("fle requires a suffix {s,d}".to_owned())
601                }
602            }
603            "csrrw" => {
604                if operands.len() != 3 {
605                    Err("csrrw requires 3 operands".to_owned())
606                } else {
607                    Ok(Instruction::CSRRW {
608                        dest: IRegister::from_string(operands[0])?,
609                        src: IRegister::from_string(operands[2])?,
610                        csr: CSR::try_from(parse_int(operands[1])?)?,
611                    })
612                }
613            }
614            "csrrs" => {
615                if operands.len() != 3 {
616                    Err("csrrs requires 3 operands".to_owned())
617                } else {
618                    Ok(Instruction::CSRRS {
619                        dest: IRegister::from_string(operands[0])?,
620                        src: IRegister::from_string(operands[2])?,
621                        csr: CSR::try_from(parse_int(operands[1])?)?,
622                    })
623                }
624            }
625            "csrrc" => {
626                if operands.len() != 3 {
627                    Err("csrrc requires 3 operands".to_owned())
628                } else {
629                    Ok(Instruction::CSRRC {
630                        dest: IRegister::from_string(operands[0])?,
631                        src: IRegister::from_string(operands[2])?,
632                        csr: CSR::try_from(parse_int(operands[1])?)?,
633                    })
634                }
635            }
636            "csrrwi" => {
637                if operands.len() != 3 {
638                    Err("csrrwi requires 3 operands".to_owned())
639                } else {
640                    Ok(Instruction::CSRRWI {
641                        dest: IRegister::from_string(operands[0])?,
642                        imm: CSRImmediate::try_from(parse_int(operands[2])?)?,
643                        csr: CSR::try_from(parse_int(operands[1])?)?,
644                    })
645                }
646            }
647            "csrrsi" => {
648                if operands.len() != 3 {
649                    Err("csrrsi requires 3 operands".to_owned())
650                } else {
651                    Ok(Instruction::CSRRSI {
652                        dest: IRegister::from_string(operands[0])?,
653                        imm: CSRImmediate::try_from(parse_int(operands[2])?)?,
654                        csr: CSR::try_from(parse_int(operands[1])?)?,
655                    })
656                }
657            }
658            "csrrci" => {
659                if operands.len() != 3 {
660                    Err("csrrci requires 3 operands".to_owned())
661                } else {
662                    Ok(Instruction::CSRRCI {
663                        dest: IRegister::from_string(operands[0])?,
664                        imm: CSRImmediate::try_from(parse_int(operands[2])?)?,
665                        csr: CSR::try_from(parse_int(operands[1])?)?,
666                    })
667                }
668            }
669            _ => Err(format!("unknown mnemonic: {}", mnemonic)),
670        };
671        x.map(AssemblyResult::I)
672    }
673}
674
675fn compressed_assemble(mnemonics: &[&str], operands: Vec<&str>) -> Result<CInstruction, String> {
676    match mnemonics[0] {
677        "addi4spn" => {
678            if operands.len() != 2 {
679                Err("c.addi4spn requires 2 operands".to_owned())
680            } else {
681                Ok(CInstruction::ADDI4SPN {
682                    dest: CIRegister::try_from(operands[0])?,
683                    imm: CWideImmediate::try_from(parse_int(operands[1])?)?,
684                })
685            }
686        }
687        "fld" => {
688            if operands.len() != 2 {
689                Err("c.fld requires 2 operands".to_owned())
690            } else {
691                let (base, imm) = parse_address_expression_compressed(operands[1])?;
692                Ok(CInstruction::FLD {
693                    dest: CFRegister::try_from(operands[0])?,
694                    base,
695                    offset: CDImmediate::try_from(imm)?,
696                })
697            }
698        }
699        "lw" => {
700            if operands.len() != 2 {
701                Err("c.lw requires 2 operands".to_owned())
702            } else {
703                let (base, imm) = parse_address_expression_compressed(operands[1])?;
704                Ok(CInstruction::LW {
705                    dest: CIRegister::try_from(operands[0])?,
706                    base,
707                    offset: CWImmediate::try_from(imm)?,
708                })
709            }
710        }
711        "ld" => {
712            if operands.len() != 2 {
713                Err("c.ld requires 2 operands".to_owned())
714            } else {
715                let (base, imm) = parse_address_expression_compressed(operands[1])?;
716                Ok(CInstruction::LD {
717                    dest: CIRegister::try_from(operands[0])?,
718                    base,
719                    offset: CDImmediate::try_from(imm)?,
720                })
721            }
722        }
723        "fsd" => {
724            if operands.len() != 2 {
725                Err("c.fsd requires 2 operands".to_owned())
726            } else {
727                let (base, imm) = parse_address_expression_compressed(operands[1])?;
728                Ok(CInstruction::FSD {
729                    src: CFRegister::try_from(operands[0])?,
730                    base,
731                    offset: CDImmediate::try_from(imm)?,
732                })
733            }
734        }
735        "sw" => {
736            if operands.len() != 2 {
737                Err("c.sw requires 2 operands".to_owned())
738            } else {
739                let (base, imm) = parse_address_expression_compressed(operands[1])?;
740                Ok(CInstruction::SW {
741                    src: CIRegister::try_from(operands[0])?,
742                    base,
743                    offset: CWImmediate::try_from(imm)?,
744                })
745            }
746        }
747        "sd" => {
748            if operands.len() != 2 {
749                Err("c.sd requires 2 operands".to_owned())
750            } else {
751                let (base, imm) = parse_address_expression_compressed(operands[1])?;
752                Ok(CInstruction::SD {
753                    src: CIRegister::try_from(operands[0])?,
754                    base,
755                    offset: CDImmediate::try_from(imm)?,
756                })
757            }
758        }
759        "addi" => ci_assemble!(ADDI),
760        "addiw" => ci_assemble!(ADDIW),
761        "li" => ci_assemble!(LI),
762        "addi16sp" => {
763            if operands.len() != 1 {
764                Err("c.addi16sp requires 1 operands".to_owned())
765            } else {
766                let i = parse_int(operands[0])?;
767
768                Ok(CInstruction::ADDI16SP {
769                    imm: C16SPImmediate::try_from(i)?,
770                })
771            }
772        }
773        "lui" => ci_assemble!(LUI),
774        "srli" => {
775            if operands.len() != 2 {
776                Err("c.srli requires 2 operands".to_owned())
777            } else {
778                Ok(CInstruction::SRLI {
779                    dest: CIRegister::try_from(operands[0])?,
780                    shamt: CShamt::try_from(parse_int(operands[1])?)?,
781                })
782            }
783        }
784        "srai" => {
785            if operands.len() != 2 {
786                Err("c.srai requires 2 operands".to_owned())
787            } else {
788                Ok(CInstruction::SRAI {
789                    dest: CIRegister::try_from(operands[0])?,
790                    shamt: CShamt::try_from(parse_int(operands[1])?)?,
791                })
792            }
793        }
794        "andi" => {
795            if operands.len() != 2 {
796                Err("c.andi requires 2 operands".to_owned())
797            } else {
798                Ok(CInstruction::ANDI {
799                    dest: CIRegister::try_from(operands[0])?,
800                    imm: CIImmediate::try_from(parse_int(operands[1])?)?,
801                })
802            }
803        }
804        "sub" => cr_assemble!(SUB),
805        "xor" => cr_assemble!(XOR),
806        "or" => cr_assemble!(OR),
807        "and" => cr_assemble!(AND),
808        "subw" => cr_assemble!(SUBW),
809        "addw" => cr_assemble!(ADDW),
810        "j" => {
811            if operands.len() != 1 {
812                Err("c.j requires 1 operand".to_owned())
813            } else {
814                Ok(CInstruction::J {
815                    offset: CJImmediate::try_from(parse_int(operands[0])?)?,
816                })
817            }
818        }
819        "beqz" => {
820            if operands.len() != 2 {
821                Err("c.beqz requires 2 operands".to_owned())
822            } else {
823                Ok(CInstruction::BEQZ {
824                    src: CIRegister::try_from(operands[0])?,
825                    offset: CBImmediate::try_from(parse_int(operands[1])?)?,
826                })
827            }
828        }
829        "bnez" => {
830            if operands.len() != 2 {
831                Err("c.bne requires 2 operands".to_owned())
832            } else {
833                Ok(CInstruction::BNEZ {
834                    src: CIRegister::try_from(operands[0])?,
835                    offset: CBImmediate::try_from(parse_int(operands[1])?)?,
836                })
837            }
838        }
839        "slli" => {
840            if operands.len() != 2 {
841                Err("c.slli requires 2 operands".to_owned())
842            } else {
843                Ok(CInstruction::SLLI {
844                    dest: IRegister::from_string(operands[0])?,
845                    shamt: CShamt::try_from(parse_int(operands[1])?)?,
846                })
847            }
848        }
849        "fldsp" => {
850            if operands.len() != 2 {
851                Err("c.fldsp requires 2 operands".to_owned())
852            } else {
853                Ok(CInstruction::FLDSP {
854                    dest: FRegister::try_from(operands[0])?,
855                    offset: CDSPImmediate::try_from(parse_int(operands[1])?)?,
856                })
857            }
858        }
859        "ldsp" => {
860            if operands.len() != 2 {
861                Err("c.ldsp requires 2 operands".to_owned())
862            } else {
863                Ok(CInstruction::LDSP {
864                    dest: IRegister::from_string(operands[0])?,
865                    offset: CDSPImmediate::try_from(parse_int(operands[1])?)?,
866                })
867            }
868        }
869        "lwsp" => {
870            if operands.len() != 2 {
871                Err("c.lwsp requires 2 operands".to_owned())
872            } else {
873                Ok(CInstruction::LWSP {
874                    dest: IRegister::from_string(operands[0])?,
875                    offset: CWSPImmediate::try_from(parse_int(operands[1])?)?,
876                })
877            }
878        }
879        "jr" => {
880            if operands.len() != 1 {
881                Err("c.jr requires 1 operand".to_owned())
882            } else {
883                Ok(CInstruction::JR {
884                    src: IRegister::from_string(operands[0])?,
885                })
886            }
887        }
888        "jalr" => {
889            if operands.len() != 1 {
890                Err("c.jalr requires 1 operand".to_owned())
891            } else {
892                Ok(CInstruction::JALR {
893                    src: IRegister::from_string(operands[0])?,
894                })
895            }
896        }
897        "ebreak" => {
898            if operands.len() != 0 {
899                Err("c.jr requires 0 operands".to_owned())
900            } else {
901                Ok(CInstruction::EBREAK)
902            }
903        }
904        "add" => {
905            if operands.len() != 2 {
906                Err("c.add requires 2 operands".to_owned())
907            } else {
908                Ok(CInstruction::ADD {
909                    dest: IRegister::from_string(operands[0])?,
910                    src: IRegister::from_string(operands[1])?,
911                })
912            }
913        }
914        "fsdsp" => {
915            if operands.len() != 2 {
916                Err("c.fsdsp requires 2 operands".to_owned())
917            } else {
918                Ok(CInstruction::FSDSP {
919                    src: FRegister::try_from(operands[0])?,
920                    offset: CSDSPImmediate::try_from(parse_int(operands[1])?)?,
921                })
922            }
923        }
924        "swsp" => {
925            if operands.len() != 2 {
926                Err("c.swsp requires 2 operands".to_owned())
927            } else {
928                Ok(CInstruction::SWSP {
929                    src: IRegister::from_string(operands[0])?,
930                    offset: CSWSPImmediate::try_from(parse_int(operands[1])?)?,
931                })
932            }
933        }
934        "sdsp" => {
935            if operands.len() != 2 {
936                Err("c.sdsp requires 2 operands".to_owned())
937            } else {
938                Ok(CInstruction::SDSP {
939                    src: IRegister::from_string(operands[0])?,
940                    offset: CSDSPImmediate::try_from(parse_int(operands[1])?)?,
941                })
942            }
943        }
944        "mv" => {
945            if operands.len() != 2 {
946                Err("c.mv requires 2 operands".to_owned())
947            } else {
948                Ok(CInstruction::MV {
949                    dest: IRegister::from_string(operands[0])?,
950                    src: IRegister::from_string(operands[1])?,
951                })
952            }
953        }
954        _ => Err(format!(
955            "unknown compressed instruction mnemonic: {}",
956            mnemonics[0]
957        )),
958    }
959}