Skip to content

Commit

Permalink
feat: Add instruction implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
howjmay committed Feb 9, 2024
1 parent 0db5cad commit 01fa6ac
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 110 deletions.
188 changes: 82 additions & 106 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct CPU {
pub xregs: registers::XREGS,
pc: u64,

bus: memory::BUS,
pub bus: memory::BUS,
}

impl CPU {
Expand Down Expand Up @@ -50,7 +50,7 @@ impl CPU {
BGEU => exec_bgeu(self, instr),
_ => panic!(),
},
LOAD => match (funct3) {
LOAD => match funct3 {
LB => exec_lb(self, instr),
LH => exec_lh(self, instr),
LW => exec_lw(self, instr),
Expand All @@ -60,20 +60,20 @@ impl CPU {
LWU => exec_lwu(self, instr),
_ => panic!(),
},
S_TYPE => match (funct3) {
S_TYPE => match funct3 {
SB => exec_sb(self, instr),
SH => exec_sh(self, instr),
SW => exec_sw(self, instr),
SD => exec_sd(self, instr),
_ => panic!(),
},
I_TYPE => match (funct3) {
I_TYPE => match funct3 {
ADDI => exec_addi(self, instr),
SLLI => exec_slli(self, instr),
SLTI => exec_slti(self, instr),
SLTIU => exec_sltiu(self, instr),
XORI => exec_xori(self, instr),
SRI => match (funct7) {
SRI => match funct7 {
SRLI => exec_srli(self, instr),
SRAI => exec_srai(self, instr),
_ => panic!(),
Expand All @@ -84,8 +84,8 @@ impl CPU {
panic!("malformed I type instruction");
}
},
R_TYPE => match (funct3) {
ADDSUB => match (funct7) {
R_TYPE => match funct3 {
ADDSUB => match funct7 {
ADD => exec_add(self, instr),
SUB => exec_sub(self, instr),
_ => (),
Expand All @@ -94,7 +94,7 @@ impl CPU {
SLT => exec_slt(self, instr),
SLTU => exec_sltu(self, instr),
XOR => exec_xor(self, instr),
SR => match (funct7) {
SR => match funct7 {
SRL => exec_srl(self, instr),
SRA => exec_sra(self, instr),
_ => (),
Expand All @@ -111,107 +111,83 @@ impl CPU {
}
}

fn rd(instr: u32) -> u32 {
return (instr >> 7) & 0x1f; // rd in bits 11..7
}
fn rs1(instr: u32) -> u32 {
return (instr >> 15) & 0x1f; // rs1 in bits 19..15
}
fn rs2(instr: u32) -> u32 {
return (instr >> 20) & 0x1f; // rs2 in bits 24..20
}

fn imm_I(instr: u32) -> u32 {
return (instr & 0xfff00000) >> 20;
}

// uint64_t imm_S(uint32_t inst) {
// // imm[11:5] = inst[31:25], imm[4:0] = inst[11:7]
// return ((int64_t)(int32_t)(inst & 0xfe000000) >> 20)
// | ((inst >> 7) & 0x1f);
// }
// uint64_t imm_B(uint32_t inst) {
// // imm[12|10:5|4:1|11] = inst[31|30:25|11:8|7]
// return ((int64_t)(int32_t)(inst & 0x80000000) >> 19)
// | ((inst & 0x80) << 4) // imm[11]
// | ((inst >> 20) & 0x7e0) // imm[10:5]
// | ((inst >> 7) & 0x1e); // imm[4:1]
// }
// uint64_t imm_U(uint32_t inst) {
// // imm[31:12] = inst[31:12]
// return (int64_t)(int32_t)(inst & 0xfffff999);
// }
// uint64_t imm_J(uint32_t inst) {
// // imm[20|10:1|11|19:12] = inst[31|30:21|20|19:12]
// return (uint64_t)((int64_t)(int32_t)(inst & 0x80000000) >> 11)
// | (inst & 0xff000) // imm[19:12]
// | ((inst >> 9) & 0x800) // imm[11]
// | ((inst >> 20) & 0x7fe); // imm[10:1]
// }

// uint32_t shamt(uint32_t inst) {
// // shamt(shift amount) only required for immediate shift instructions
// // shamt[4:5] = imm[5:0]
// return (uint32_t) (imm_I(inst) & 0x1f); // TODO: 0x1f / 0x3f ?
// }

// uint64_t csr(uint32_t inst) {
// // csr[11:0] = inst[31:20]
// return ((inst & 0xfff00000) >> 20);
// }

// RV32I
// see page 64 at https://riscv.org/wp-content/uploads/2016/06/riscv-spec-v2.1.pdf
pub fn exec_lui(cpu: &CPU, instr: u32) {}
pub fn exec_auipc(cpu: &CPU, instr: u32) {}
pub fn exec_jal(cpu: &CPU, instr: u32) {}
pub fn exec_jalr(cpu: &CPU, instr: u32) {}
pub fn exec_beq(cpu: &CPU, instr: u32) {}
pub fn exec_bne(cpu: &CPU, instr: u32) {}
pub fn exec_blt(cpu: &CPU, instr: u32) {}
pub fn exec_bge(cpu: &CPU, instr: u32) {}
pub fn exec_bltu(cpu: &CPU, instr: u32) {}
pub fn exec_bgeu(cpu: &CPU, instr: u32) {}
pub fn exec_lb(cpu: &CPU, instr: u32) {}
pub fn exec_lh(cpu: &CPU, instr: u32) {}
pub fn exec_lw(cpu: &CPU, instr: u32) {}
pub fn exec_ld(cpu: &CPU, instr: u32) {}
pub fn exec_lbu(cpu: &CPU, instr: u32) {}
pub fn exec_lhu(cpu: &CPU, instr: u32) {}
pub fn exec_lwu(cpu: &CPU, instr: u32) {}
pub fn exec_sb(cpu: &CPU, instr: u32) {}
pub fn exec_sh(cpu: &CPU, instr: u32) {}
pub fn exec_sw(cpu: &CPU, instr: u32) {}
pub fn exec_sd(cpu: &CPU, instr: u32) {}
pub fn exec_lui(cpu: &mut CPU, instr: u32) {}
pub fn exec_auipc(cpu: &mut CPU, instr: u32) {}
pub fn exec_jal(cpu: &mut CPU, instr: u32) {}
pub fn exec_jalr(cpu: &mut CPU, instr: u32) {}
pub fn exec_beq(cpu: &mut CPU, instr: u32) {}
pub fn exec_bne(cpu: &mut CPU, instr: u32) {}
pub fn exec_blt(cpu: &mut CPU, instr: u32) {}
pub fn exec_bge(cpu: &mut CPU, instr: u32) {}
pub fn exec_bltu(cpu: &mut CPU, instr: u32) {}
pub fn exec_bgeu(cpu: &mut CPU, instr: u32) {}
pub fn exec_lb(cpu: &mut CPU, instr: u32) {}
pub fn exec_lh(cpu: &mut CPU, instr: u32) {}
pub fn exec_lw(cpu: &mut CPU, instr: u32) {}
pub fn exec_ld(cpu: &mut CPU, instr: u32) {}
pub fn exec_lbu(cpu: &mut CPU, instr: u32) {}
pub fn exec_lhu(cpu: &mut CPU, instr: u32) {}
pub fn exec_lwu(cpu: &mut CPU, instr: u32) {}
pub fn exec_sb(cpu: &mut CPU, instr: u32) {}
pub fn exec_sh(cpu: &mut CPU, instr: u32) {}
pub fn exec_sw(cpu: &mut CPU, instr: u32) {}
pub fn exec_sd(cpu: &mut CPU, instr: u32) {}
pub fn exec_addi(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] + imm as u64;
}
pub fn exec_slti(cpu: &CPU, instr: u32) {}
pub fn exec_sltiu(cpu: &CPU, instr: u32) {}
pub fn exec_xori(cpu: &CPU, instr: u32) {}
pub fn exec_ori(cpu: &CPU, instr: u32) {}
pub fn exec_andi(cpu: &CPU, instr: u32) {}
pub fn exec_slli(cpu: &CPU, instr: u32) {}
pub fn exec_srli(cpu: &CPU, instr: u32) {}
pub fn exec_srai(cpu: &CPU, instr: u32) {}
pub fn exec_add(cpu: &CPU, instr: u32) {}
pub fn exec_sub(cpu: &CPU, instr: u32) {}
pub fn exec_sll(cpu: &CPU, instr: u32) {}
pub fn exec_slt(cpu: &CPU, instr: u32) {}
pub fn exec_sltu(cpu: &CPU, instr: u32) {}
pub fn exec_xor(cpu: &CPU, instr: u32) {}
pub fn exec_srl(cpu: &CPU, instr: u32) {}
pub fn exec_sra(cpu: &CPU, instr: u32) {}
pub fn exec_or(cpu: &CPU, instr: u32) {}
pub fn exec_and(cpu: &CPU, instr: u32) {}
pub fn exec_fence(cpu: &CPU, instr: u32) {}
pub fn exec_fence_i(cpu: &CPU, instr: u32) {}
pub fn exec_ecall(cpu: &CPU, instr: u32) {}
pub fn exec_ebreak(cpu: &CPU, instr: u32) {}
pub fn exec_csrrw(cpu: &CPU, instr: u32) {}
pub fn exec_csrrs(cpu: &CPU, instr: u32) {}
pub fn exec_csrrc(cpu: &CPU, instr: u32) {}
pub fn exec_csrrwi(cpu: &CPU, instr: u32) {}
pub fn exec_csrrsi(cpu: &CPU, instr: u32) {}
pub fn exec_csrrci(cpu: &CPU, instr: u32) {}
pub fn exec_slti(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] =
((cpu.xregs.regs[rs1(instr) as usize] as i64) < (imm as i64)) as u64;
}
pub fn exec_sltiu(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] < imm as u64) as u64;
}
pub fn exec_xori(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] ^ imm as u64;
}
pub fn exec_ori(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] | imm as u64;
}
pub fn exec_andi(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] & imm as u64;
}
pub fn exec_slli(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] << imm as u64;
}
pub fn exec_srli(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] >> imm as u64;
}
pub fn exec_srai(cpu: &mut CPU, instr: u32) {
let imm = imm_I(instr);
cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i64 >> imm) as u64;
}
pub fn exec_add(cpu: &mut CPU, instr: u32) {}
pub fn exec_sub(cpu: &mut CPU, instr: u32) {}
pub fn exec_sll(cpu: &mut CPU, instr: u32) {}
pub fn exec_slt(cpu: &mut CPU, instr: u32) {}
pub fn exec_sltu(cpu: &mut CPU, instr: u32) {}
pub fn exec_xor(cpu: &mut CPU, instr: u32) {}
pub fn exec_srl(cpu: &mut CPU, instr: u32) {}
pub fn exec_sra(cpu: &mut CPU, instr: u32) {}
pub fn exec_or(cpu: &mut CPU, instr: u32) {}
pub fn exec_and(cpu: &mut CPU, instr: u32) {}
pub fn exec_fence(cpu: &mut CPU, instr: u32) {}
pub fn exec_fence_i(cpu: &mut CPU, instr: u32) {}
pub fn exec_ecall(cpu: &mut CPU, instr: u32) {}
pub fn exec_ebreak(cpu: &mut CPU, instr: u32) {}
pub fn exec_csrrw(cpu: &mut CPU, instr: u32) {}
pub fn exec_csrrs(cpu: &mut CPU, instr: u32) {}
pub fn exec_csrrc(cpu: &mut CPU, instr: u32) {}
pub fn exec_csrrwi(cpu: &mut CPU, instr: u32) {}
pub fn exec_csrrsi(cpu: &mut CPU, instr: u32) {}
pub fn exec_csrrci(cpu: &mut CPU, instr: u32) {}
50 changes: 50 additions & 0 deletions src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,53 @@ pub const CSRRC: u32 = 0x03;
pub const CSRRWI: u32 = 0x05;
pub const CSRRSI: u32 = 0x06;
pub const CSRRCI: u32 = 0x07;

pub fn rd(instr: u32) -> u32 {
return (instr >> 7) & 0x1f; // rd in bits 11..7
}
pub fn rs1(instr: u32) -> u32 {
return (instr >> 15) & 0x1f; // rs1 in bits 19..15
}
pub fn rs2(instr: u32) -> u32 {
return (instr >> 20) & 0x1f; // rs2 in bits 24..20
}

pub fn shamt(instr: u32) -> u32 {
// shamt[4:5] = imm[5:0]
return (imm_I(instr) & 0x1f) as u32;
}

pub fn csr(instr: u32) -> u64 {
// csr[11:0] = inst[31:20]
return ((instr & 0xfff00000) >> 20) as u64;
}

pub fn imm_B(instr: u32) -> u64 {
// imm[12|10:5|4:1|11] = inst[31|30:25|11:8|7]
return ((instr & 0x80000000) >> 19) as u64
| ((instr & 0x80) << 4) as u64 // imm[11]
| ((instr >> 20) & 0x7e0) as u64 // imm[10:5]
| ((instr >> 7) & 0x1e) as u64; // imm[4:1]
}

pub fn imm_S(instr: u32) -> u64 {
// imm[11:5] = inst[31:25], imm[4:0] = inst[11:7]
return ((instr & 0xfe000000) >> 20) as u64 | ((instr >> 7) & 0x1f) as u64;
}

pub fn imm_I(instr: u32) -> i32 {
return ((instr & 0xfff00000) as i32 >> 20);
}

pub fn imm_U(instr: u32) -> u64 {
// imm[31:12] = inst[31:12]
return (instr & 0xfffff999) as u64;
}

pub fn imm_J(instr: u32) -> u64 {
// imm[20|10:1|11|19:12] = inst[31|30:21|20|19:12]
return ((instr & 0x80000000) >> 11) as u64
| (instr & 0xff000) as u64 // imm[19:12]
| ((instr >> 9) & 0x800) as u64 // imm[11]
| ((instr >> 20) & 0x7fe) as u64; // imm[10:1]
}
Loading

0 comments on commit 01fa6ac

Please sign in to comment.