Skip to content

Commit 6ee367f

Browse files
committed
Day83 - RISCV Data Memory
1 parent fcb6406 commit 6ee367f

7 files changed

+303
-0
lines changed

day83/design.sv

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
`include "riscv_fetch.sv"
2+
`include "riscv_decode.sv"
3+
`include "riscv_regfile.sv"
4+
`include "riscv_execute.sv"
5+
`include "riscv_dmem.sv"
6+
7+
module riscv_top (
8+
input wire clk,
9+
input wire reset
10+
);
11+
12+
// Instantiate and connect all the submodules
13+
14+
endmodule

day83/riscv_decode.sv

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
module riscv_decode (
2+
input logic[31:0] if_dec_instr_i,
3+
output logic[4:0] rs1_o,
4+
output logic[4:0] rs2_o,
5+
output logic[4:0] rd_o,
6+
output logic[6:0] op_o,
7+
output logic[2:0] funct3_o,
8+
output logic[6:0] funct7_o,
9+
output logic is_r_type_o,
10+
output logic is_i_type_o,
11+
output logic is_s_type_o,
12+
output logic is_b_type_o,
13+
output logic is_u_type_o,
14+
output logic is_j_type_o,
15+
output logic[11:0] i_type_imm_o,
16+
output logic[11:0] s_type_imm_o,
17+
output logic[11:0] b_type_imm_o,
18+
output logic[19:0] u_type_imm_o,
19+
output logic[19:0] j_type_imm_o
20+
);
21+
22+
assign rd_o = if_dec_instr_i[11:7];
23+
assign rs1_o = if_dec_instr_i[19:15];
24+
assign rs2_o = if_dec_instr_i[24:20];
25+
assign op_o = if_dec_instr_i[6:0];
26+
assign funct3_o = if_dec_instr_i[14:12];
27+
assign funct7_o = if_dec_instr_i[31:25];
28+
29+
// Decode the type of the instruction
30+
always_comb begin
31+
is_r_type_o = 1'b0;
32+
is_i_type_o = 1'b0;
33+
is_s_type_o = 1'b0;
34+
is_b_type_o = 1'b0;
35+
is_u_type_o = 1'b0;
36+
is_j_type_o = 1'b0;
37+
case (op_o)
38+
7'h33 : is_r_type_o = 1'b1;
39+
// I-type data processing
40+
// I-type LW
41+
// JALR
42+
7'h13,
43+
7'h03,
44+
7'h67 : is_i_type_o = 1'b1;
45+
7'h23 : is_s_type_o = 1'b1;
46+
7'h63 : is_b_type_o = 1'b1;
47+
7'h6F : is_j_type_o = 1'b1;
48+
endcase
49+
end
50+
51+
assign i_type_imm_o[11:0] = if_dec_instr_i[31:20];
52+
assign s_type_imm_o[11:0] = {if_dec_instr_i[31:25], if_dec_instr_i[11:7]};
53+
assign b_type_imm_o[11:0] = {if_dec_instr_i[31], if_dec_instr_i[7], if_dec_instr_i[30:25],
54+
if_dec_instr_i[11:8]};
55+
assign u_type_imm_o[19:0] = if_dec_instr_i[31:12];
56+
assign j_type_imm_o[19:0] = {if_dec_instr_i[31], if_dec_instr_i[19:12], if_dec_instr_i[20],
57+
if_dec_instr_i[30:21]};
58+
59+
endmodule

day83/riscv_dmem.sv

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// APB Master for the data memory unit
2+
module riscv_dmem (
3+
input wire clk,
4+
input wire reset,
5+
6+
input wire ex_dmem_valid_i, // Mem operation is valid
7+
input wire[31:0] ex_dmem_addr_i,
8+
input wire[31:0] ex_dmem_wdata_i,
9+
input wire ex_dmem_wnr_i, // 1 - write, 0 - read
10+
11+
// ------------------------------------------------------------
12+
// APB Interface to memory
13+
// ------------------------------------------------------------
14+
output wire psel_o,
15+
output wire penable_o,
16+
output wire[31:0] paddr_o,
17+
output wire pwrite_o,
18+
output wire[31:0] pwdata_o,
19+
input wire pready_i,
20+
input wire[31:0] prdata_i,
21+
// ------------------------------------------------------------
22+
// Data output
23+
// ------------------------------------------------------------
24+
output logic[31:0] dmem_data_o,
25+
output logic dmem_done_o
26+
);
27+
28+
// Enum for the APB state
29+
typedef enum logic[1:0] {ST_IDLE = 2'b00, ST_SETUP = 2'b01, ST_ACCESS = 2'b10} apb_state_t;
30+
31+
apb_state_t nxt_state;
32+
apb_state_t state_q;
33+
logic [31:0] if_pc_q;
34+
35+
always_ff @(posedge clk or posedge reset)
36+
if (reset)
37+
state_q <= ST_IDLE;
38+
else
39+
state_q <= nxt_state;
40+
41+
always_comb begin
42+
nxt_state = state_q;
43+
case (state_q)
44+
ST_IDLE : nxt_state = ex_dmem_valid_i ? ST_SETUP : ST_IDLE;
45+
ST_SETUP : nxt_state = ST_ACCESS;
46+
ST_ACCESS : begin
47+
if (pready_i) nxt_state = ST_IDLE;
48+
end
49+
endcase
50+
end
51+
52+
assign psel_o = (state_q == ST_SETUP) | (state_q == ST_ACCESS);
53+
assign penable_o = (state_q == ST_ACCESS);
54+
assign pwrite_o = ex_dmem_wnr_i;
55+
assign paddr_o = ex_dmem_addr_i; // Memory address
56+
assign pwdata_o = ex_dmem_wdata_i;
57+
58+
assign dmem_done_o = penable_o && pready_i;
59+
assign dmem_data_o = prdata_i;
60+
61+
endmodule

day83/riscv_execute.sv

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module riscv_execute (
2+
input wire [31:0] opr_a_i,
3+
input wire [31:0] opr_b_i,
4+
input wire [3:0] op_sel_i,
5+
output wire [31:0] ex_res_o
6+
);
7+
8+
logic [31:0] alu_res;
9+
logic signed [31:0] sign_opr_a;
10+
logic signed [31:0] sign_opr_b;
11+
12+
assign sign_opr_a = opr_a_i;
13+
assign sign_opr_b = opr_b_i;
14+
15+
// Supported Operations
16+
localparam OP_ADD = 4'b0000;
17+
localparam OP_SUB = 4'b0001;
18+
localparam OP_SLL = 4'b0010;
19+
localparam OP_LSR = 4'b0011;
20+
localparam OP_ASR = 4'b0100;
21+
localparam OP_OR = 4'b0101;
22+
localparam OP_AND = 4'b0110;
23+
localparam OP_XOR = 4'b0111;
24+
localparam OP_EQL = 4'b1000;
25+
localparam OP_ULT = 4'b1001;
26+
localparam OP_UGT = 4'b1010;
27+
localparam OP_SLT = 4'b1011;
28+
localparam OP_SGT = 4'b1100;
29+
30+
always_comb begin
31+
alu_res = 32'h0;
32+
case (op_sel_i)
33+
OP_ADD: alu_res = opr_a_i + opr_b_i;
34+
OP_SUB: alu_res = opr_a_i - opr_b_i;
35+
OP_SLL: alu_res = opr_a_i << opr_b_i[4:0];
36+
OP_LSR: alu_res = opr_a_i >> opr_b_i[4:0];
37+
OP_ASR: alu_res = sign_opr_a >>> opr_b_i[4:0];
38+
OP_OR: alu_res = opr_a_i | opr_b_i;
39+
OP_AND: alu_res = opr_a_i & opr_b_i;
40+
OP_XOR: alu_res = opr_a_i ^ opr_b_i;
41+
OP_EQL: alu_res = {31'h0, opr_a_i == opr_b_i};
42+
OP_ULT: alu_res = {31'h0, opr_a_i < opr_b_i};
43+
OP_UGT: alu_res = {31'h0, opr_a_i >= opr_b_i};
44+
OP_SLT: alu_res = {31'h0, sign_opr_a < sign_opr_b};
45+
OP_SGT: alu_res = {31'h0, sign_opr_a >= sign_opr_b};
46+
endcase
47+
end
48+
49+
assign ex_res_o = alu_res;
50+
51+
endmodule

day83/riscv_fetch.sv

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// APB Master for the instruction fetch unit
2+
module riscv_fetch (
3+
input wire clk,
4+
input wire reset,
5+
6+
input wire instr_done_i,
7+
8+
// ------------------------------------------------------------
9+
// APB Interface to memory
10+
// ------------------------------------------------------------
11+
output wire psel_o,
12+
output wire penable_o,
13+
output wire[31:0] paddr_o,
14+
output wire pwrite_o,
15+
output wire[31:0] pwdata_o,
16+
input wire pready_i,
17+
input wire[31:0] prdata_i,
18+
// ------------------------------------------------------------
19+
// Instruction output
20+
// ------------------------------------------------------------
21+
output logic if_dec_valid_o,
22+
output logic[31:0] if_dec_instr_o,
23+
input wire[31:0] ex_if_pc_i
24+
);
25+
26+
// Enum for the APB state
27+
typedef enum logic[1:0] {ST_IDLE = 2'b00, ST_SETUP = 2'b01, ST_ACCESS = 2'b10} apb_state_t;
28+
29+
apb_state_t nxt_state;
30+
apb_state_t state_q;
31+
logic [31:0] if_pc_q;
32+
logic nxt_dec_valid;
33+
34+
always_ff @(posedge clk or posedge reset)
35+
if (reset)
36+
state_q <= ST_IDLE;
37+
else
38+
state_q <= nxt_state;
39+
40+
always_comb begin
41+
nxt_state = state_q;
42+
case (state_q)
43+
// Memory responses may not be single cycle. Wait for the
44+
// memory request to complete before requesting the next
45+
// instruction
46+
ST_IDLE : nxt_state = instr_done_i ? ST_SETUP : ST_IDLE;
47+
ST_SETUP : nxt_state = ST_ACCESS;
48+
ST_ACCESS : begin
49+
if (pready_i) nxt_state = ST_IDLE;
50+
end
51+
endcase
52+
end
53+
54+
assign psel_o = (state_q == ST_SETUP) | (state_q == ST_ACCESS);
55+
assign penable_o = (state_q == ST_ACCESS);
56+
assign pwrite_o = 1'b0; // No writes to IMEM
57+
assign paddr_o = if_pc_q; // Current instruction counter
58+
assign pwdata_o = 32'h0;
59+
60+
// Start from 0x8000_0000 on reset
61+
always_ff @(posedge clk or posedge reset)
62+
if (reset)
63+
if_pc_q <= 32'h8000_0000;
64+
else
65+
if_pc_q <= ex_if_pc_i;
66+
67+
// Capture the read data as the current instruction opcode
68+
always_ff @(posedge clk or posedge reset)
69+
if (reset) begin
70+
if_dec_instr_o <= 32'h0;
71+
end else if (penable_o && pready_i) begin
72+
if_dec_instr_o <= prdata_i;
73+
end
74+
75+
always_ff @(posedge clk or posedge reset)
76+
if (reset) begin
77+
if_dec_valid_o <= 1'b0;
78+
end else if ((penable_o && pready_i) | if_dec_valid_o) begin
79+
if_dec_valid_o <= nxt_dec_valid;
80+
end
81+
82+
// Set valid on:
83+
// - Valid APB transfer and clear it next cycle if no valid transfer
84+
// and if the flag was set
85+
assign nxt_dec_valid = (penable_o && pready_i);
86+
87+
endmodule

day83/riscv_regfile.sv

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module riscv_regfile (
2+
input wire clk,
3+
input wire reset,
4+
5+
// Single write address
6+
input wire rf_wr_en_i,
7+
input wire[4:0] rf_wr_addr_i,
8+
input wire[31:0] rf_wr_data_i,
9+
10+
// Two read addresses
11+
input wire[4:0] rf_rd_p0_i,
12+
input wire[4:0] rf_rd_p1_i,
13+
output wire[31:0] rf_rd_p0_data_o,
14+
output wire[31:0] rf_rd_p1_data_o,
15+
);
16+
17+
// Register file
18+
logic [31:0] reg_file [31:0];
19+
20+
// Write logic
21+
always_ff @(posedge clk)
22+
if (rf_wr_en_i)
23+
reg_file[rf_wr_addr_i] <= rf_wr_data_i;
24+
25+
// Read logic
26+
assign rf_rd_p0_data_o = 32'(|rf_rd_p0_i) & reg_file[rf_rd_p0_i];
27+
assign rf_rd_p0_data_o = 32'(|rf_rd_p1_i) & reg_file[rf_rd_p1_i];
28+
29+
endmodule

day83/testbench.sv

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Code your testbench here
2+
// or browse Examples

0 commit comments

Comments
 (0)