Skip to content

Commit 4a92c3f

Browse files
authored
Merge pull request #5 from howjmay/basic
feat: Add branch instructions
2 parents b066371 + be76276 commit 4a92c3f

File tree

5 files changed

+353
-88
lines changed

5 files changed

+353
-88
lines changed

src/cpu.rs

+86-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::memory;
44
use crate::opcode::*;
55
use crate::registers;
66

7-
#[derive(Debug)]
7+
#[derive(Debug, Clone, Copy)]
88
pub struct CPU {
99
// integer registers
1010
pub xregs: registers::XREGS,
@@ -54,7 +54,6 @@ impl CPU {
5454
LB => exec_lb(self, instr),
5555
LH => exec_lh(self, instr),
5656
LW => exec_lw(self, instr),
57-
LD => exec_ld(self, instr),
5857
LBU => exec_lbu(self, instr),
5958
LHU => exec_lhu(self, instr),
6059
LWU => exec_lwu(self, instr),
@@ -64,7 +63,6 @@ impl CPU {
6463
SB => exec_sb(self, instr),
6564
SH => exec_sh(self, instr),
6665
SW => exec_sw(self, instr),
67-
SD => exec_sd(self, instr),
6866
_ => panic!(),
6967
},
7068
I_TYPE => match funct3 {
@@ -115,7 +113,7 @@ impl CPU {
115113
// see page 64 at https://riscv.org/wp-content/uploads/2016/06/riscv-spec-v2.1.pdf
116114
pub fn exec_lui(cpu: &mut CPU, instr: u32) {
117115
let imm = (imm_u(instr) as i32) as u32;
118-
cpu.xregs.regs[rd(instr) as usize] = imm;
116+
cpu.xregs.regs[rd(instr) as usize] = imm | (cpu.xregs.regs[rd(instr) as usize] & 0xfff);
119117
}
120118
pub fn exec_auipc(cpu: &mut CPU, instr: u32) {
121119
let imm = imm_u(instr) as i32;
@@ -132,23 +130,87 @@ pub fn exec_jalr(cpu: &mut CPU, instr: u32) {
132130
// ignore the last 1 bit with 0xfffffffe
133131
cpu.pc = (cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32 & 0xfffffffe;
134132
}
135-
pub fn exec_beq(cpu: &mut CPU, instr: u32) {}
136-
pub fn exec_bne(cpu: &mut CPU, instr: u32) {}
137-
pub fn exec_blt(cpu: &mut CPU, instr: u32) {}
138-
pub fn exec_bge(cpu: &mut CPU, instr: u32) {}
139-
pub fn exec_bltu(cpu: &mut CPU, instr: u32) {}
140-
pub fn exec_bgeu(cpu: &mut CPU, instr: u32) {}
141-
pub fn exec_lb(cpu: &mut CPU, instr: u32) {}
142-
pub fn exec_lh(cpu: &mut CPU, instr: u32) {}
143-
pub fn exec_lw(cpu: &mut CPU, instr: u32) {}
144-
pub fn exec_ld(cpu: &mut CPU, instr: u32) {}
145-
pub fn exec_lbu(cpu: &mut CPU, instr: u32) {}
146-
pub fn exec_lhu(cpu: &mut CPU, instr: u32) {}
147-
pub fn exec_lwu(cpu: &mut CPU, instr: u32) {}
133+
pub fn exec_beq(cpu: &mut CPU, instr: u32) {
134+
let imm = imm_b(instr) as i32;
135+
if cpu.xregs.regs[rs1(instr) as usize] == cpu.xregs.regs[rs2(instr) as usize] {
136+
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
137+
}
138+
}
139+
pub fn exec_bne(cpu: &mut CPU, instr: u32) {
140+
let imm = imm_b(instr) as i32;
141+
if cpu.xregs.regs[rs1(instr) as usize] != cpu.xregs.regs[rs2(instr) as usize] {
142+
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
143+
}
144+
}
145+
pub fn exec_blt(cpu: &mut CPU, instr: u32) {
146+
let imm = imm_b(instr) as i32;
147+
if (cpu.xregs.regs[rs1(instr) as usize] as i32) < (cpu.xregs.regs[rs2(instr) as usize] as i32) {
148+
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
149+
}
150+
}
151+
pub fn exec_bge(cpu: &mut CPU, instr: u32) {
152+
let imm = imm_b(instr) as i32;
153+
if (cpu.xregs.regs[rs1(instr) as usize] as i32) >= (cpu.xregs.regs[rs2(instr) as usize] as i32)
154+
{
155+
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
156+
}
157+
}
158+
pub fn exec_bltu(cpu: &mut CPU, instr: u32) {
159+
let imm = imm_b(instr) as i32;
160+
if cpu.xregs.regs[rs1(instr) as usize] < cpu.xregs.regs[rs2(instr) as usize] {
161+
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
162+
}
163+
}
164+
pub fn exec_bgeu(cpu: &mut CPU, instr: u32) {
165+
let imm = imm_b(instr) as i32;
166+
if cpu.xregs.regs[rs1(instr) as usize] >= rs2(instr) {
167+
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
168+
}
169+
}
170+
pub fn exec_lb(cpu: &mut CPU, instr: u32) {
171+
let imm = imm_i(instr) as i32;
172+
let load_i8 = cpu.bus.load(
173+
(cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32,
174+
8,
175+
) as i32;
176+
cpu.xregs.regs[rd(instr) as usize] = ((load_i8 << 26) >> 26) as u32;
177+
}
178+
pub fn exec_lh(cpu: &mut CPU, instr: u32) {
179+
let imm = imm_i(instr) as i32;
180+
let load_i16 = cpu.bus.load(
181+
(cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32,
182+
16,
183+
) as i32;
184+
cpu.xregs.regs[rd(instr) as usize] = ((load_i16 << 16) >> 16) as u32;
185+
}
186+
pub fn exec_lw(cpu: &mut CPU, instr: u32) {
187+
let imm = imm_i(instr) as i32;
188+
cpu.xregs.regs[rd(instr) as usize] = cpu.bus.load(
189+
(cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32,
190+
32,
191+
);
192+
}
193+
pub fn exec_lbu(cpu: &mut CPU, instr: u32) {
194+
let imm = imm_i(instr) as u32;
195+
cpu.xregs.regs[rd(instr) as usize] = cpu
196+
.bus
197+
.load(cpu.xregs.regs[rs1(instr) as usize].wrapping_add(imm), 8);
198+
}
199+
pub fn exec_lhu(cpu: &mut CPU, instr: u32) {
200+
let imm = imm_i(instr) as u32;
201+
cpu.xregs.regs[rd(instr) as usize] = cpu
202+
.bus
203+
.load(cpu.xregs.regs[rs1(instr) as usize].wrapping_add(imm), 16);
204+
}
205+
pub fn exec_lwu(cpu: &mut CPU, instr: u32) {
206+
let imm = imm_i(instr) as u32;
207+
cpu.xregs.regs[rd(instr) as usize] = cpu
208+
.bus
209+
.load(cpu.xregs.regs[rs1(instr) as usize].wrapping_add(imm), 32);
210+
}
148211
pub fn exec_sb(cpu: &mut CPU, instr: u32) {}
149212
pub fn exec_sh(cpu: &mut CPU, instr: u32) {}
150213
pub fn exec_sw(cpu: &mut CPU, instr: u32) {}
151-
pub fn exec_sd(cpu: &mut CPU, instr: u32) {}
152214
pub fn exec_addi(cpu: &mut CPU, instr: u32) {
153215
let imm = imm_i(instr);
154216
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] + imm as u32;
@@ -176,15 +238,18 @@ pub fn exec_andi(cpu: &mut CPU, instr: u32) {
176238
}
177239
pub fn exec_slli(cpu: &mut CPU, instr: u32) {
178240
let imm = imm_i(instr);
179-
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] << imm as u32;
241+
// shift-by-immediate takes only the lower 5 bits
242+
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] << (imm & 0x1f) as u32;
180243
}
181244
pub fn exec_srli(cpu: &mut CPU, instr: u32) {
182245
let imm = imm_i(instr);
183-
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] >> imm as u32;
246+
// shift-by-immediate takes only the lower 5 bits
247+
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] >> (imm & 0x1f) as u32;
184248
}
185249
pub fn exec_srai(cpu: &mut CPU, instr: u32) {
186250
let imm = imm_i(instr);
187-
cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i32 >> imm) as u32;
251+
cpu.xregs.regs[rd(instr) as usize] =
252+
(cpu.xregs.regs[rs1(instr) as usize] as i32 >> (imm & 0x1f)) as u32;
188253
}
189254
pub fn exec_add(cpu: &mut CPU, instr: u32) {
190255
cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i32

src/memory.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pub const MEM_BASE: u32 = 0x80000000; // defined in QEMU
44
pub const MEM_SIZE: u32 = 1024;
55

6-
#[derive(Debug)]
6+
#[derive(Debug, Clone, Copy)]
77
pub struct BUS {
88
mem: MEMORY,
99
}
@@ -20,7 +20,7 @@ impl BUS {
2020
}
2121
}
2222

23-
#[derive(Debug)]
23+
#[derive(Debug, Clone, Copy)]
2424
pub struct MEMORY {
2525
mem: [u8; MEM_SIZE as usize],
2626
}

src/registers.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use core::fmt;
44

5+
#[derive(Clone, Copy)]
56
pub struct XREGS {
67
pub regs: [u32; 32],
78
}

0 commit comments

Comments
 (0)