riscv_codec/
assembly.rs

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
54/// Converts a string representing operations into a fence u8
55fn 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
92/// Constructs an `Instruction` from a line of assembly.
93pub 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            // register-immediate instructions
121            "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            // register-register instructions
135            "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            // load instructions
164            "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            // store instructions
171            "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            // branch instructions
177            "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 and rs1 are currently unused
244                            rd: IRegister::Zero,
245                            rs1: IRegister::Zero,
246                            ops,
247                            fm: 0, //fm field, always zero for a non-tso fence
248                        })
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 and rs1 are currently unused
261                                rd: IRegister::Zero,
262                                rs1: IRegister::Zero,
263                                ops,
264                                fm: 0b1000, // tso fence
265                            })
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 can't use `amo_assemble!` because it only has two operands
279            "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                    // default rounding mode
414                    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}