Pipelined Core
Pipelined Core
`define _core_v
`include "system.sv"
`include "base.sv"
`include "memory_io.sv"
`include "memory.sv"
module core(
input logic clk
,input logic reset
,input logic [`word_address_size-1:0] reset_pc
,output memory_io_req inst_mem_req
,input memory_io_rsp inst_mem_rsp
,output memory_io_req data_mem_req
,input memory_io_rsp data_mem_rsp
);
word pc;
// fetch register
always_ff @(posedge clk) begin
if(reset) begin
fetch_r <= reset_pc;
end else if (fetch_en) begin
fetch_r <= fetch_n;
end else if (!fetch_valid) begin
fetch_r <= '0;
end
end
alu_op_t alu_op;
// register file
logic [31:0] rs1_data;
logic [31:0] rs2_data;
logic [31:0] rd_data;
register_file get_reg_value (
.clk(clk),
.reset(reset),
.rs1(inst_mem_rsp.data[19:15]), // rs1
.rs2(inst_mem_rsp.data[24:20]), // rs2
.rd(wb_rd), // rd, destination register
.write_enable(wb_write_enable),
.write_data(wb_write_data),
.rs1_data(rs1_data),
.rs2_data(rs2_data),
.rd_data(rd_data)
);
logic decode_flush;
end
// Compute Immediate
case (decode_n.opcode)
7'b0010011, 7'b0000011, 7'b1100111: // I-Type, and jalr
decode_n.imm = {{20{inst_mem_rsp.data[31]}},
inst_mem_rsp.data[31:20]};
7'b1100011: // B-Type
decode_n.imm = {{19{inst_mem_rsp.data[31]}}, inst_mem_rsp.data[7],
inst_mem_rsp.data[30:25], inst_mem_rsp.data[11:8], 1'b0};
default:
decode_n.imm = 32'b0;
endcase
end
// hazard detection
// dependencies rs1 or rs2 equals the rd in ex, mem, or wb.
// structural hazard: instr_mem_rsp.valid or data_mem_rsp.valid does not go high
logic hazard_appear;
logic exe_r_rd;
logic mem_r_rd;
always_comb begin
hazard_appear = 1'b0;
if (!inst_mem_rsp.valid)
hazard_appear = 1'b1;
assign exe_en = !hazard_appear; // Also, 1 for now, later add hazard detection
always_comb begin
exe_valid = !exe_flush && decode_valid;
end
exe_n.funct3 = decode_r.funct3;
exe_n.rs2_data = decode_r.rs2_data;
exe_n.rd = decode_r.rd;
exe_n.opcode = decode_r.opcode;
// ALU operations
case (decode_r.alu_op)
// Arithmetic and Logic Operations
ALU_ADD: exe_n.alu_result = executed_operand1 + executed_operand2;
ALU_SUB: exe_n.alu_result = executed_operand1 - executed_operand2;
ALU_SLL: exe_n.alu_result = executed_operand1 <<
executed_operand2[4:0];
ALU_SRA: exe_n.alu_result = executed_operand1 >>>
executed_operand2[4:0];
ALU_AND: exe_n.alu_result = executed_operand1 & executed_operand2;
ALU_OR: exe_n.alu_result = executed_operand1 | executed_operand2;
ALU_XOR: exe_n.alu_result = executed_operand1 ^ executed_operand2;
ALU_AUIPC: exe_n.alu_result = decode_r.pc + executed_operand2;
ALU_LUI: exe_n.alu_result = executed_operand2;
// Load and Store Address Calculation
ALU_LOAD, ALU_STORE: exe_n.mem_address = decode_r.rs1_data +
decode_r.imm;
// Branch Operations
ALU_BRCH: begin
case (decode_r.funct3)
3'b000: exe_n.branch_taken = (decode_r.rs1_data == decode_r.rs2_data);
// BEQ
3'b001: exe_n.branch_taken = (decode_r.rs1_data !=
decode_r.rs2_data); // BNE
3'b100: exe_n.branch_taken = ($signed(decode_r.rs1_data) <
$signed(decode_r.rs2_data)); // BLT
3'b101: exe_n.branch_taken = ($signed(decode_r.rs1_data) >=
$signed(decode_r.rs2_data)); // BGE
3'b110: exe_n.branch_taken = (decode_r.rs1_data < decode_r.rs2_data); //
BLTU
3'b111: exe_n.branch_taken = (decode_r.rs1_data >=
decode_r.rs2_data); // BGEU
default: exe_n.branch_taken = 1'b0;
endcase
exe_n.jump_target = decode_r.pc + decode_r.imm;
end
// Jumps
ALU_JAL: begin
exe_n.jump_target = decode_r.pc + decode_r.imm;
exe_n.alu_result = decode_r.pc + 4;
end
ALU_JALR: begin
exe_n.jump_target = (decode_r.rs1_data + decode_r.imm) & ~1;
exe_n.alu_result = decode_r.pc + 4;
end
// pc combinational control
// next_pc_fetch and fetch.n available
// as soom as decode_r is available
case (decode_r.opcode)
7'b1101111, 7'b1100111: begin // jal, jalr
next_pc_fetch = exe_n.jump_target;
end
end
// memory-writeback data tranisition
typedef struct packed {
logic [2:0] funct3;
logic [31:0] alu_result;
logic [4:0] rd;
logic [6:0] opcode;
} mem_reg;
// Default assignments
data_mem_req.valid = 1'b0;
data_mem_req.do_read = 4'b0000;
data_mem_req.do_write = 4'b0000;
data_mem_req.addr = exe_r.mem_address;
data_mem_req.data = exe_r.rs2_data;// data to store
// Load
if (exe_r.opcode == 7'b0000011) begin
data_mem_req.valid = 1'b1;
data_mem_req.do_read = 4'b1111; // Read full word
end
// Store Instructions
if (exe_r.opcode == 7'b0100011) begin
data_mem_req.valid = 1'b1;
case (exe_r.funct3)
3'b000: data_mem_req.do_write = 4'b0001; // SB
3'b001: data_mem_req.do_write = 4'b0011; // SH
3'b010: data_mem_req.do_write = 4'b1111; // SW
default: data_mem_req.do_write = 4'b0000;
endcase
end
end
case (mem_r.opcode)
7'b0000011: begin // loads
if (data_mem_rsp.valid) begin
case (mem_r.funct3)
3'b000: wb_write_data = {{24{data_mem_rsp.data[7]}},
data_mem_rsp.data[7:0]}; // LB
3'b001: wb_write_data = {{16{data_mem_rsp.data[15]}},
data_mem_rsp.data[15:0]}; // LH
3'b010: wb_write_data = data_mem_rsp.data; // LW
3'b100: wb_write_data = {24'b0, data_mem_rsp.data[7:0]}; // LBU
3'b101: wb_write_data = {16'b0, data_mem_rsp.data[15:0]}; //
LHU
default: wb_write_data = 32'b0;
endcase
wb_write_enable = 1'b1;
end
else begin
wb_write_enable = 1'b0;
end
end
7'b0110011, // R-type
7'b0010011, // I-type
7'b1101111, // JAL
7'b1100111, // JALR
7'b0110111, // LUI
7'b0010111: // AUIPC
begin
wb_write_data = mem_r.alu_result;
wb_write_enable = 1'b1;
end
default: begin
wb_write_enable = 1'b0;
wb_write_data = 32'b0;
end
endcase
end else if (!wb_valid) begin
wb_write_enable = 1'b0;
wb_write_data = 32'b0;
wb_rd = '0;
end
end
integer cnt = 0;
always_ff @(negedge clk) begin
$display("---------------next cycle----------------------------------");
$display("Cycle: %d ", cnt);
$display("");
$display("fetch part info: ---------");
$display("n pc: %x, r pc: %x", fetch_n.pc, fetch_r.pc);
$display("branch taken: %b", exe_n.branch_taken);
$display("");
$display("decode part info: --------");
$display("instr back : %b", inst_mem_rsp.data);
$display("decode_n reg: ");
$display("pc: %x", decode_n.pc);
$display("opcode: %b, rd: %d, rs1: %d, rs2: %d,", decode_n.opcode,
decode_n.rd, decode_n.rs1, decode_n.rs2);
$display("f3: %b, f7: %b", decode_n.funct3, decode_n.funct7);
$display("rs1 data: %d, rs2 data: %d", decode_n.rs1_data, decode_n.rs2_data);
$display("imm: %d", decode_n.imm);
$display("alu_op: %s", alu_op_to_string(decode_n.alu_op));
$display("decode_r reg: ");
$display("pc: %x", decode_r.pc);
$display("opcode: %b, rd: %d, rs1: %d, rs2: %d,", decode_r.opcode, decode_r.rd,
decode_r.rs1, decode_r.rs2);
$display("f3: %b, f7: %b", decode_r.funct3, decode_r.funct7);
$display("rs1 data: %d, rs2 data: %d", decode_r.rs1_data, decode_r.rs2_data);
$display("imm: %d", decode_r.imm);
$display("alu_op: %s", alu_op_to_string(decode_r.alu_op));
$display("");
$display("exe part info: -----------");
$display("next pc fetch: %x", next_pc_fetch);
$display("oprand1: %d, operand2: %d", executed_operand1,
executed_operand2);
$display("exe_n reg: ");
$display("opcode: %b", exe_n.opcode);
$display("alu_result: %d, rd: %d", exe_n.alu_result, exe_n.rd);
$display("branch taken: %b, jump target: %x", exe_n.branch_taken,
exe_n.jump_target);
$display("data to store: %d, addr to access: %x", exe_n.rs2_data,
exe_n.mem_address);
$display("exe_r reg: ");
$display("opcode: %b", exe_r.opcode);
$display("alu_result: %d, rd: %d", exe_r.alu_result, exe_r.rd);
$display("branch taken: %b, jump target: %x", exe_r.branch_taken,
exe_r.jump_target);
$display("data to store: %d, addr to access: %x", exe_r.rs2_data,
exe_r.mem_address);
$display("");
$display("mem part info: -----------");
$display("just move data forward and operating mem req");
$display("");
$display("wb part info: ------------");
$display("write enable: %b, rd: %d", wb_write_enable, wb_rd);
$display("wb_write_data: %d", wb_write_data);
$display("opcode: %b, alu_result: %d", mem_r.opcode, mem_r.alu_result);
if (cnt == 20) begin
$finish;
end
endmodule
module register_file (
input logic clk,
input logic reset,
input logic [4:0] rs1,
input logic [4:0] rs2,
input logic [4:0] rd,
input logic write_enable,
input logic [31:0] write_data,
output logic [31:0] rs1_data,
output logic [31:0] rs2_data,
output logic [31:0] rd_data
);
// register 2d array, where each register has width [31:0]
// and the 2d array has 32 registers [31:0]
logic [31:0][31:0] registers;
// read operations
always_comb begin
end
// write operation
always_ff @(posedge clk)begin
if (reset) begin
for(int i = 0; i < 32; i++) begin
registers[i] <= 32'b0;
end
end else if (write_enable && rd != 0) begin
registers[rd] <= write_data;
end
end
endmodule
`endif