diff --git a/README.md b/README.md index e82ab3e..31d5faa 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,6 @@ A small RISC-V emulator written in Rust. - [x] Zaamo standard extension - [ ] F standard extension - [ ] D standard extension -- [ ] C standard extension +- [x] C standard extension - [x] Zihintpause standard extension diff --git a/src/inst.rs b/src/inst.rs index f709ef4..8f45cf4 100644 --- a/src/inst.rs +++ b/src/inst.rs @@ -244,17 +244,13 @@ impl Display for Inst { Inst::Sb { offset, src, base } => write!(f, "sb {src}, {}({base})", offset as i32), Inst::Sh { offset, src, base } => write!(f, "sh {src}, {}({base})", offset as i32), Inst::Sw { offset, src, base } => write!(f, "sw {src}, {}({base})", offset as i32), - Inst::Addi { - imm, - dest: rd, - src1: rs1, - } => { - if rs1.0 == 0 { - write!(f, "li {rd}, {}", imm as i32) - } else if imm == 0 { - write!(f, "mv {rd}, {rs1}") + Inst::Addi { imm, dest, src1 } => { + if dest.0 == 0 && src1.0 == 0 { + write!(f, "nop") + } else if src1.0 == 0 { + write!(f, "li {dest}, {}", imm as i32) } else { - write!(f, "addi {rd}, {rs1}, {}", imm as i32) + write!(f, "addi {dest}, {src1}, {}", imm as i32) } } Inst::Slti { @@ -297,7 +293,13 @@ impl Display for Inst { dest, src1: rs1, } => write!(f, "srai {dest}, {rs1}, {}", imm as i32), - Inst::Add { dest, src1, src2 } => write!(f, "add {dest}, {src1}, {src2}"), + Inst::Add { dest, src1, src2 } => { + if src1.0 == 0 { + write!(f, "mv {dest}, {src2}") + } else { + write!(f, "add {dest}, {src1}, {src2}") + } + } Inst::Sub { dest, src1, src2 } => write!(f, "sub {dest}, {src1}, {src2}"), Inst::Sll { dest, src1, src2 } => write!(f, "sll {dest}, {src1}, {src2}"), Inst::Slt { dest, src1, src2 } => write!(f, "slt {dest}, {src1}, {src2}"), @@ -501,10 +503,14 @@ impl InstCodeC { fn funct3(self) -> u32 { self.extract(13..=15) } + fn funct2(self) -> u32 { + self.extract(10..=11) + } /// rd/rs1 (7..=11) fn rd(self) -> Reg { Reg(self.extract(7..=11) as u32) } + /// rs2 (2..=6) fn rs2(self) -> Reg { Reg(self.extract(2..=6) as u32) } @@ -552,6 +558,12 @@ impl Inst { let inst = match code.quadrant() { // C0 0b00 => match code.funct3() { + // C.ADDI4SPN -> addi \rd', sp, \imm + 0b000 => Inst::Addi { + imm: code.immediate_u(&[(5..=5, 3), (6..=6, 2), (7..=10, 6), (11..=12, 4)]), + dest: code.rs2_short(), + src1: Reg::SP, + }, // C.LW -> lw \dest \offset(\base) 0b010 => Inst::Lw { offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]), @@ -594,6 +606,76 @@ impl Inst { dest: code.rd(), src1: Reg::ZERO, }, + // Arithmetic instructions + 0b100 => { + let bit12 = code.extract(12..=12); + match code.funct2() { + // C.SRLI -> srli \rd', \rd', \imm + 0b00 => { + if bit12 != 0 { + return Err(Status::IllegalInstruction(code.into(), "imm")); + } + + Inst::Srli { + imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]), + dest: code.rs1_short(), + src1: code.rs1_short(), + } + } + // C.SRAI -> srai \rd', \rd', \imm + 0b01 => { + if bit12 != 0 { + return Err(Status::IllegalInstruction(code.into(), "imm")); + } + + Inst::Srai { + imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]), + dest: code.rs1_short(), + src1: code.rs1_short(), + } + } + // C.ANDI -> andi \rd', \rd', \imm + 0b10 => Inst::Andi { + imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]), + dest: code.rs1_short(), + src1: code.rs1_short(), + }, + 0b11 => { + if bit12 != 0 { + return Err(Status::IllegalInstruction(code.into(), "bit 12")); + } + let funct2 = code.extract(5..=6); + match funct2 { + // C.SUB -> sub \rd', \rd', \rs2' + 0b00 => Inst::Sub { + dest: code.rs1_short(), + src1: code.rs1_short(), + src2: code.rs2_short(), + }, + // C.XOR -> xor \rd', \rd', \rs2' + 0b01 => Inst::Xor { + dest: code.rs1_short(), + src1: code.rs1_short(), + src2: code.rs2_short(), + }, + // C.OR -> or \rd', \rd', \rs2' + 0b10 => Inst::Or { + dest: code.rs1_short(), + src1: code.rs1_short(), + src2: code.rs2_short(), + }, + // C.AND -> and \rd', \rd', \rs2' + 0b11 => Inst::And { + dest: code.rs1_short(), + src1: code.rs1_short(), + src2: code.rs2_short(), + }, + _ => unreachable!("only two bits"), + } + } + _ => unreachable!("only two bits"), + } + } // C.J -> jal zero, \offset 0b101 => Inst::Jal { offset: code.immediate_s(&[ @@ -662,6 +744,17 @@ impl Inst { }, // C2 0b10 => match code.funct3() { + // C.SLLI -> slli \rd, \rd, \imm + 0b000 => { + if code.extract(12..=12) != 0 { + return Err(Status::IllegalInstruction(code.into(), "imm")); + } + Inst::Slli { + imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]), + dest: code.rd(), + src1: code.rd(), + } + } // C.LWSP -> lw \reg \offset(sp) 0b010 => { let dest = code.rd(); @@ -681,14 +774,23 @@ impl Inst { let rd_rs1 = code.rd(); match (bit, rd_rs1.0, rs2.0) { // C.JR -> jalr zero, 0(\rs1) - (0, _, 0) if rd_rs1.0 != 0 => Inst::Jalr { - offset: 0, - base: rd_rs1, - dest: Reg::ZERO, + (0, _, 0) => { + if rd_rs1.0 == 0 { + return Err(Status::IllegalInstruction(code.into(), "rs1")); + } + Inst::Jalr { + offset: 0, + base: rd_rs1, + dest: Reg::ZERO, + } + } + // C.MV -> add \rd, x0, \rs2 + (0, _, _) => Inst::Add { + dest: code.rd(), + src1: Reg::ZERO, + src2: code.rs2(), }, - // C.MV - (0, _, _) if rd_rs1.0 != 0 && rs2.0 != 0 => todo!(), - // C.EBREAK + // C.EBREAK -> ebreak (1, 0, 0) => Inst::Ebreak, // C.JALR -> jalr ra, 0(\rs1) (1, _, 0) if rd_rs1.0 != 0 => Inst::Jalr { @@ -696,11 +798,11 @@ impl Inst { base: rd_rs1, dest: Reg::RA, }, - // C.ADD - (1, _, _) if rd_rs1.0 != 0 && rs2.0 != 0 => Inst::Add { - dest: todo!(), - src1: todo!(), - src2: todo!(), + // C.ADD -> add \rd, \rd, \rs2 + (1, _, _) => Inst::Add { + dest: rd_rs1, + src1: rd_rs1, + src2: rs2, }, _ => return Err(Status::IllegalInstruction(code.into(), "inst")), } diff --git a/tests/check/int_comp.S b/tests/check/int_comp.S index a56c99e..317535b 100644 --- a/tests/check/int_comp.S +++ b/tests/check/int_comp.S @@ -62,6 +62,10 @@ START_TEST CASE xor 0b101, 0b100, 0b001 CASE sll, 2, 1, 4 + CASE sll, 2, 20, 2097152 + CASE sll, 2, 30, 2147483648 + CASE sll, 2, 31, 0 + CASER sll, 2, 32, 2 # error for immediate CASE sll, 0, 10, 0 CASE sll, 10, 0, 10 CASE sll, -1, 31, -2147483648