mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 21:57:11 -04:00
Added initial decoder implementation
This commit is contained in:
parent
5ccee278b7
commit
88b5e1d9ab
6 changed files with 448 additions and 127 deletions
2
Makefile
2
Makefile
|
@ -12,7 +12,7 @@ agents = tb/agents/fu_if/fu_if.sv tb/agents/fu_if/fu_if_agent_pkg.sv \
|
|||
|
||||
# this list contains the standalone components
|
||||
src = alu.sv tb/sequences/alu_sequence_pkg.sv tb/env/alu_env_pkg.sv tb/test/alu_lib_pkg.sv tb/alu_tb.sv \
|
||||
issue_read_operands.sv
|
||||
issue_read_operands.sv decoder.sv
|
||||
|
||||
# Search here for include files (e.g.: non-standalone components)
|
||||
incdir = ./includes
|
||||
|
|
168
decoder.sv
Normal file
168
decoder.sv
Normal file
|
@ -0,0 +1,168 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module decoder (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic [63:0] pc_i, // PC from IF
|
||||
input logic [31:0] instruction_i, // instruction from IF
|
||||
input exception ex_i, // if an exception occured in if
|
||||
output scoreboard_entry instruction_o, // scoreboard entry to scoreboard
|
||||
output logic illegal_instr_o
|
||||
);
|
||||
instruction instr;
|
||||
assign instr = instruction'(instruction_i);
|
||||
imm_sel_t imm_select;
|
||||
|
||||
logic [63:0] imm_i_type;
|
||||
logic [63:0] imm_iz_type;
|
||||
logic [63:0] imm_s_type;
|
||||
logic [63:0] imm_sb_type;
|
||||
logic [63:0] imm_u_type;
|
||||
logic [63:0] imm_uj_type;
|
||||
logic [63:0] imm_z_type;
|
||||
logic [63:0] imm_s2_type;
|
||||
logic [63:0] imm_bi_type;
|
||||
logic [63:0] imm_s3_type;
|
||||
logic [63:0] imm_vs_type;
|
||||
logic [63:0] imm_vu_type;
|
||||
|
||||
always_comb begin : decoder
|
||||
|
||||
imm_select = NOIMM;
|
||||
illegal_instr_o = 1'b0;
|
||||
instruction_o.valid = 1'b0;
|
||||
instruction_o.ex = ex_i;
|
||||
instruction_o.fu = NONE;
|
||||
instruction_o.op = ADD;
|
||||
instruction_o.rs1 = 5'b0;
|
||||
instruction_o.rs2 = 5'b0;
|
||||
instruction_o.rd = 5'b0;
|
||||
instruction_o.pc = pc_i;
|
||||
|
||||
if (~ex_i.valid) begin
|
||||
case (instr.rtype.opcode)
|
||||
OPCODE_SYSTEM: begin
|
||||
// TODO: Implement
|
||||
end
|
||||
|
||||
OPCODE_FENCE: begin
|
||||
// TODO: Implement
|
||||
end
|
||||
|
||||
OPCODE_OP: begin
|
||||
instruction_o.fu = ALU;
|
||||
instruction_o.rs1 = instr.rtype.rs1;
|
||||
instruction_o.rs2 = instr.rtype.rs2;
|
||||
instruction_o.rd = instr.rtype.rd;
|
||||
|
||||
unique case ({instr.rtype.funct7, instr.rtype.funct3})
|
||||
{6'b00_0000, 3'b000}: instruction_o.op = ADD; // Add
|
||||
{6'b10_0000, 3'b000}: instruction_o.op = SUB; // Sub
|
||||
{6'b00_0000, 3'b010}: instruction_o.op = SLTS; // Set Lower Than
|
||||
{6'b00_0000, 3'b011}: instruction_o.op = SLTU; // Set Lower Than Unsigned
|
||||
{6'b00_0000, 3'b100}: instruction_o.op = XORL; // Xor
|
||||
{6'b00_0000, 3'b110}: instruction_o.op = ORL; // Or
|
||||
{6'b00_0000, 3'b111}: instruction_o.op = ANDL; // And
|
||||
{6'b00_0000, 3'b001}: instruction_o.op = SLL; // Shift Left Logical
|
||||
{6'b00_0000, 3'b101}: instruction_o.op = SRL; // Shift Right Logical
|
||||
{6'b10_0000, 3'b101}: instruction_o.op = SRA; // Shift Right Arithmetic
|
||||
default: begin
|
||||
illegal_instr_o = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
OPCODE_OP32: begin
|
||||
|
||||
end
|
||||
|
||||
OPCODE_OPIMM: begin
|
||||
imm_select = IIMM;
|
||||
end
|
||||
|
||||
OPCODE_OPIMM32: begin
|
||||
imm_select = IIMM;
|
||||
end
|
||||
|
||||
OPCODE_STORE: begin
|
||||
imm_select = SIMM;
|
||||
end
|
||||
|
||||
OPCODE_LOAD: begin
|
||||
imm_select = IIMM;
|
||||
end
|
||||
|
||||
OPCODE_BRANCH: begin
|
||||
imm_select = BIMM;
|
||||
end
|
||||
|
||||
OPCODE_JALR: begin
|
||||
imm_select = UIMM;
|
||||
end
|
||||
|
||||
OPCODE_JAL: begin
|
||||
imm_select = JIMM;
|
||||
end
|
||||
|
||||
OPCODE_AUIPC: begin
|
||||
imm_select = UIMM;
|
||||
end
|
||||
|
||||
OPCODE_LUI: begin
|
||||
imm_select = UIMM;
|
||||
end
|
||||
|
||||
default: illegal_instr_o = 1'b1;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin : sign_extend
|
||||
imm_i_type = { {52 {instruction_i[31]}}, instruction_i[31:20] };
|
||||
imm_iz_type = { 52'b0, instruction_i[31:20] };
|
||||
imm_s_type = { {52 {instruction_i[31]}}, instruction_i[31:25], instruction_i[11:7] };
|
||||
imm_sb_type = { {51 {instruction_i[31]}}, instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 };
|
||||
imm_u_type = { {32 {instruction_i[31]}}, instruction_i[31:12], 12'b0 }; // JAL, AUIPC, sign extended to 64 bit
|
||||
imm_uj_type = { {44 {instruction_i[31]}}, instruction_i[19:12], instruction_i[20], instruction_i[30:21], 1'b0 };
|
||||
// imm_z_type = { 59'b0, instruction_i[`REG_S1] };
|
||||
imm_s2_type = { 59'b0, instruction_i[24:20] };
|
||||
imm_bi_type = { {59{instruction_i[24]}}, instruction_i[24:20] };
|
||||
imm_s3_type = { 59'b0, instruction_i[29:25] };
|
||||
imm_vs_type = { {58 {instruction_i[24]}}, instruction_i[24:20], instruction_i[25] };
|
||||
imm_vu_type = { 58'b0, instruction_i[24:20], instruction_i[25] };
|
||||
|
||||
// NOIMM, PCIMM, IIMM, SIMM, BIMM, BIMM, UIMM, JIMM
|
||||
// select immediate
|
||||
case (imm_select)
|
||||
PCIMM: begin
|
||||
instruction_o.imm = pc_i;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
IIMM: begin
|
||||
instruction_o.imm = imm_i_type;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
SIMM: begin
|
||||
instruction_o.imm = imm_s_type;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
BIMM: begin
|
||||
instruction_o.imm = imm_bi_type;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
UIMM: begin
|
||||
instruction_o.imm = imm_u_type;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
JIMM: begin
|
||||
instruction_o.imm = imm_uj_type;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
instruction_o.imm = 64'b0;
|
||||
instruction_o.use_imm = 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -10,70 +10,137 @@
|
|||
*/
|
||||
package ariane_pkg;
|
||||
|
||||
// ---------------
|
||||
// Fetch Stage
|
||||
// ---------------
|
||||
// ---------------
|
||||
// Fetch Stage
|
||||
// ---------------
|
||||
|
||||
// Only use struct when signals have same direction
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
logic [63:0] branch_target_address;
|
||||
logic valid;
|
||||
} btb;
|
||||
// Only use struct when signals have same direction
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
logic [63:0] branch_target_address;
|
||||
logic valid;
|
||||
} btb;
|
||||
|
||||
// input to the fetch stage
|
||||
typedef struct packed {
|
||||
logic [63:0] ra; // return address
|
||||
logic is_call; // is call - pop from stack
|
||||
logic is_return; // is return - push on stack
|
||||
} ras;
|
||||
// input to the fetch stage
|
||||
typedef struct packed {
|
||||
logic [63:0] ra; // return address
|
||||
logic is_call; // is call - pop from stack
|
||||
logic is_return; // is return - push on stack
|
||||
} ras;
|
||||
|
||||
// exception
|
||||
typedef struct packed {
|
||||
logic [63:0] epc;
|
||||
logic [63:0] cause;
|
||||
logic valid;
|
||||
} exception;
|
||||
// exception
|
||||
typedef struct packed {
|
||||
logic [63:0] epc;
|
||||
logic [63:0] cause;
|
||||
logic valid;
|
||||
} exception;
|
||||
|
||||
// miss-predict
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
logic valid; // is miss-predict
|
||||
} misspredict;
|
||||
// miss-predict
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
logic valid; // is miss-predict
|
||||
} misspredict;
|
||||
|
||||
typedef enum logic[3:0] {
|
||||
NONE, ALU, MULT, LSU, CSR
|
||||
} fu_t;
|
||||
typedef enum logic[3:0] {
|
||||
NONE, ALU, MULT, LSU, CSR
|
||||
} fu_t;
|
||||
|
||||
// ---------------
|
||||
// EX Stage
|
||||
// ---------------
|
||||
// ---------------
|
||||
// EX Stage
|
||||
// ---------------
|
||||
|
||||
typedef enum logic [7:0] { ADD, SUB, ADDW, SUBW, // basic ALU op
|
||||
XORL, ORL, ANDL, // logic operations
|
||||
SRA, SRL, SLL, SRLW, SLLW, SRAW, // shifts
|
||||
LTS, LTU, LES, LEU, GTS, GTU, GES, GEU, EQ, NE, // comparisons
|
||||
SLTS, SLTU, SLETS, SLETU, // set lower than operations
|
||||
MRET, SRET, URET, ECALL, WRITE, READ, SET, CLEAR, // CSR functions
|
||||
LD, SD, LW, SW, LH, SH, LB, SB, LBU, SBU // LSU functions
|
||||
} alu_op;
|
||||
typedef enum logic [7:0] { ADD, SUB, ADDW, SUBW, // basic ALU op
|
||||
XORL, ORL, ANDL, // logic operations
|
||||
SRA, SRL, SLL, SRLW, SLLW, SRAW, // shifts
|
||||
LTS, LTU, LES, LEU, GTS, GTU, GES, GEU, EQ, NE, // comparisons
|
||||
SLTS, SLTU, SLETS, SLETU, // set lower than operations
|
||||
MRET, SRET, URET, ECALL, WRITE, READ, SET, CLEAR, // CSR functions
|
||||
LD, SD, LW, SW, LH, SH, LB, SB, LBU, SBU // LSU functions
|
||||
} alu_op;
|
||||
|
||||
// ---------------
|
||||
// ID/EX/WB Stage
|
||||
// ---------------
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
fu_t fu;
|
||||
alu_op op;
|
||||
logic [4:0] rs1;
|
||||
logic [4:0] rs2;
|
||||
logic [4:0] rd;
|
||||
logic [63:0] result;
|
||||
logic valid;
|
||||
logic use_imm;
|
||||
logic [63:0] imm; // maybe we can get this into the results field
|
||||
exception ex; // the PC is redundant here
|
||||
} scoreboard_entry;
|
||||
|
||||
// --------------------
|
||||
// Instruction Types
|
||||
// --------------------
|
||||
typedef struct packed {
|
||||
logic [6:0] opcode;
|
||||
logic [11:7] rd;
|
||||
logic [14:12] funct3;
|
||||
logic [19:15] rs1;
|
||||
logic [24:20] rs2;
|
||||
logic [31:25] funct7;
|
||||
} rtype;
|
||||
|
||||
typedef struct packed {
|
||||
logic [6:0] opcode;
|
||||
logic [11:7] rd;
|
||||
logic [14:12] funct3;
|
||||
logic [19:15] rs1;
|
||||
logic [31:20] imm;
|
||||
} itype;
|
||||
|
||||
typedef struct packed {
|
||||
logic [6:0] opcode;
|
||||
logic [11:7] imm0;
|
||||
logic [14:12] funct3;
|
||||
logic [19:15] rs1;
|
||||
logic [24:20] rs2;
|
||||
logic [31:25] imm1;
|
||||
} stype;
|
||||
|
||||
typedef struct packed {
|
||||
logic [6:0] opcode;
|
||||
logic [11:7] rd;
|
||||
logic [31:12] funct3;
|
||||
} utype;
|
||||
|
||||
typedef union packed {
|
||||
logic [31:0] instr;
|
||||
rtype rtype;
|
||||
itype itype;
|
||||
stype stype;
|
||||
utype utype;
|
||||
} instruction;
|
||||
|
||||
// --------------------
|
||||
// Opcodes
|
||||
// --------------------
|
||||
localparam OPCODE_SYSTEM = 7'h73;
|
||||
localparam OPCODE_FENCE = 7'h0f;
|
||||
localparam OPCODE_OP = 7'h33;
|
||||
localparam OPCODE_OP32 = 7'h3B;
|
||||
localparam OPCODE_OPIMM = 7'h13;
|
||||
localparam OPCODE_OPIMM32 = 7'h1B;
|
||||
localparam OPCODE_STORE = 7'h23;
|
||||
localparam OPCODE_LOAD = 7'h03;
|
||||
localparam OPCODE_BRANCH = 7'h63;
|
||||
localparam OPCODE_JALR = 7'h67;
|
||||
localparam OPCODE_JAL = 7'h6f;
|
||||
localparam OPCODE_AUIPC = 7'h17;
|
||||
localparam OPCODE_LUI = 7'h37;
|
||||
|
||||
// --------------------
|
||||
// Immediate select
|
||||
// --------------------
|
||||
typedef enum logic[3:0] {
|
||||
NOIMM, PCIMM, IIMM, SIMM, BIMM, UIMM, JIMM
|
||||
} imm_sel_t;
|
||||
|
||||
// ---------------
|
||||
// ID/EX/WB Stage
|
||||
// ---------------
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
fu_t fu;
|
||||
alu_op op;
|
||||
logic [4:0] rs1;
|
||||
logic [4:0] rs2;
|
||||
logic [4:0] rd;
|
||||
logic [63:0] result;
|
||||
logic valid;
|
||||
logic use_imm;
|
||||
logic [63:0] imm; // maybe we can get this into the results field
|
||||
exception ex; // the PC is redundant here
|
||||
} scoreboard_entry;
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -51,10 +51,20 @@ module issue_read_operands (
|
|||
);
|
||||
logic stall; // stall signal, we do not want to fetch any more entries
|
||||
logic fu_busy; // functional unit is busy
|
||||
scoreboard_entry sbe_n, sbe_q; // instruction register (ID <-> EX)
|
||||
logic [63:0] operand_a_regfile_n, operand_a_regfile_q, operand_b_regfile_n, operand_b_regfile_q; // operands coming from regfile
|
||||
logic [63:0] operand_a_regfile, operand_b_regfile; // operands coming from regfile
|
||||
|
||||
// output flipflop (ID <-> EX)
|
||||
logic [63:0] operand_a_n, operand_a_q, operand_b_n, operand_b_q;
|
||||
logic alu_valid_n, alu_valid_q;
|
||||
alu_op operator_n, operator_q;
|
||||
|
||||
// forwarding signals
|
||||
logic forward_rs1, forward_rs2;
|
||||
|
||||
assign operand_a_o = operand_a_q;
|
||||
assign operand_b_o = operand_b_q;
|
||||
assign operator_o = operator_q;
|
||||
assign alu_valid_o = alu_valid_q;
|
||||
// ---------------
|
||||
// Issue Stage
|
||||
// ---------------
|
||||
|
@ -63,7 +73,6 @@ module issue_read_operands (
|
|||
// We also need to check if there is an unresolved branch in the scoreboard.
|
||||
always_comb begin : issue
|
||||
// default assignment
|
||||
sbe_n = sbe_q;
|
||||
issue_ack_o = 1'b0;
|
||||
// check that we didn't stall, that the instruction we got is valid
|
||||
// and that the functional unit we need is not busy
|
||||
|
@ -71,7 +80,6 @@ module issue_read_operands (
|
|||
// check that the corresponding functional unit is not busy
|
||||
// no other instruction has the same destination register -> fetch the instruction
|
||||
if (rd_clobber_i[issue_instr_i.rd] == NONE) begin
|
||||
sbe_n = issue_instr_i;
|
||||
issue_ack_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
@ -98,7 +106,6 @@ module issue_read_operands (
|
|||
// ---------------
|
||||
// Register stage
|
||||
// ---------------
|
||||
assign operator_o = sbe_q.op;
|
||||
// check that all operands are available, otherwise stall
|
||||
// forward corresponding register
|
||||
always_comb begin : operands_available
|
||||
|
@ -106,12 +113,12 @@ module issue_read_operands (
|
|||
// operand forwarding signals
|
||||
forward_rs1 = 1'b0;
|
||||
forward_rs2 = 1'b0;
|
||||
// address needs to be applied one cycle earlier
|
||||
// poll the scoreboard for those values
|
||||
rs1_o = issue_instr_i.rs1;
|
||||
rs2_o = issue_instr_i.rs2;
|
||||
// 1. check if the source registers are clobberd
|
||||
// 2. poll the scoreboard
|
||||
if (rd_clobber_i[sbe_q.rs1] != NONE) begin
|
||||
if (rd_clobber_i[issue_instr_i.rs1] != NONE) begin
|
||||
// the operand is available, forward it
|
||||
if (rs1_valid_i)
|
||||
forward_rs1 = 1'b1;
|
||||
|
@ -120,7 +127,7 @@ module issue_read_operands (
|
|||
|
||||
end
|
||||
|
||||
if (rd_clobber_i[sbe_q.rs2] != NONE) begin
|
||||
if (rd_clobber_i[issue_instr_i.rs2] != NONE) begin
|
||||
// the operand is available, forward it
|
||||
if (rs2_valid_i)
|
||||
forward_rs2 = 1'b1;
|
||||
|
@ -133,35 +140,35 @@ module issue_read_operands (
|
|||
// Forwarding/Output MUX
|
||||
always_comb begin : forwarding
|
||||
// default is regfile
|
||||
operand_a_o = operand_a_regfile_q;
|
||||
operand_b_o = operand_b_regfile_q;
|
||||
operand_a_n = operand_a_regfile;
|
||||
operand_b_n = operand_b_regfile;
|
||||
|
||||
// or should we forward
|
||||
if (forward_rs1) begin
|
||||
operand_a_o = rs1_i;
|
||||
operand_a_n = rs1_i;
|
||||
end
|
||||
|
||||
if (forward_rs2) begin
|
||||
operand_b_o = rs2_i;
|
||||
operand_b_n = rs2_i;
|
||||
end
|
||||
|
||||
// or is it an immediate (including PC)
|
||||
if (sbe_q.use_imm) begin
|
||||
operand_b_o = sbe_q.imm;
|
||||
if (issue_instr_i.use_imm) begin
|
||||
operand_b_n = issue_instr_i.imm;
|
||||
end
|
||||
|
||||
end
|
||||
// FU select
|
||||
always_comb begin : unit_valid
|
||||
alu_valid_o = 1'b0;
|
||||
alu_valid_n = alu_valid_q;
|
||||
lsu_valid_o = 1'b0;
|
||||
mult_valid_o = 1'b0;
|
||||
// Exception pass through
|
||||
// if an exception has occurred simply pass it through
|
||||
if (~sbe_q.ex.valid) begin
|
||||
case (sbe_q.fu)
|
||||
if (~issue_instr_i.ex.valid) begin
|
||||
case (issue_instr_i.fu)
|
||||
ALU:
|
||||
alu_valid_o = 1'b1;
|
||||
alu_valid_n = 1'b1;
|
||||
MULT:
|
||||
mult_valid_o = 1'b1;
|
||||
LSU:
|
||||
|
@ -183,10 +190,10 @@ module issue_read_operands (
|
|||
.test_en_i ( test_en_i ),
|
||||
|
||||
.raddr_a_i ( issue_instr_i.rs1 ),
|
||||
.rdata_a_o ( operand_a_regfile_n ),
|
||||
.rdata_a_o ( operand_a_regfile ),
|
||||
|
||||
.raddr_b_i ( issue_instr_i.rs2 ),
|
||||
.rdata_b_o ( operand_b_regfile_n ),
|
||||
.rdata_b_o ( operand_b_regfile ),
|
||||
|
||||
.waddr_a_i ( waddr_a_i ),
|
||||
.wdata_a_i ( wdata_a_i ),
|
||||
|
@ -196,13 +203,15 @@ module issue_read_operands (
|
|||
// Registers
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if(~rst_ni) begin
|
||||
sbe_q <= '{default: 0};
|
||||
operand_a_regfile_q <= '{default: 0};
|
||||
operand_b_regfile_q <= '{default: 0};
|
||||
operand_a_q <= '{default: 0};
|
||||
operand_b_q <= '{default: 0};
|
||||
alu_valid_q <= 1'b0;
|
||||
operator_q <= ADD;
|
||||
end else begin
|
||||
sbe_q <= sbe_n;
|
||||
operand_a_regfile_q <= operand_a_regfile_n;
|
||||
operand_b_regfile_q <= operand_b_regfile_n;
|
||||
operand_a_q <= operand_a_n;
|
||||
operand_b_q <= operand_b_n;
|
||||
alu_valid_q <= alu_valid_n;
|
||||
operator_q <= operator_n;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
100
regfile_ff.sv
Executable file
100
regfile_ff.sv
Executable file
|
@ -0,0 +1,100 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2017 ETH Zurich, University of Bologna //
|
||||
// All rights reserved. //
|
||||
// //
|
||||
// This code is under development and not yet released to the public. //
|
||||
// Until it is released, the code is under the copyright of ETH Zurich //
|
||||
// and the University of Bologna, and may contain unpublished work. //
|
||||
// Any reuse/redistribution should only be under explicit permission. //
|
||||
// //
|
||||
// Bug fixes and contributions will eventually be released under the //
|
||||
// SolderPad open hardware license and under the copyright of ETH Zurich //
|
||||
// and the University of Bologna. //
|
||||
// //
|
||||
// Engineer: Francesco Conti - f.conti@unibo.it //
|
||||
// //
|
||||
// Additional contributions by: //
|
||||
// Markus Wegmann - markus.wegmann@technokrat.ch //
|
||||
// //
|
||||
// Design Name: RISC-V register file //
|
||||
// Project Name: zero-riscy //
|
||||
// Language: SystemVerilog //
|
||||
// //
|
||||
// Description: Register file with 31 or 15x 32 bit wide registers. //
|
||||
// Register 0 is fixed to 0. This register file is based on //
|
||||
// flip flops. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module regfile
|
||||
#(
|
||||
parameter DATA_WIDTH = 32
|
||||
)
|
||||
(
|
||||
// Clock and Reset
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
|
||||
input logic test_en_i,
|
||||
|
||||
//Read port R1
|
||||
input logic [4:0] raddr_a_i,
|
||||
output logic [DATA_WIDTH-1:0] rdata_a_o,
|
||||
|
||||
//Read port R2
|
||||
input logic [4:0] raddr_b_i,
|
||||
output logic [DATA_WIDTH-1:0] rdata_b_o,
|
||||
|
||||
|
||||
// Write port W1
|
||||
input logic [4:0] waddr_a_i,
|
||||
input logic [DATA_WIDTH-1:0] wdata_a_i,
|
||||
input logic we_a_i
|
||||
|
||||
);
|
||||
|
||||
localparam ADDR_WIDTH = 5;
|
||||
localparam NUM_WORDS = 2**ADDR_WIDTH;
|
||||
|
||||
logic [NUM_WORDS-1:0][DATA_WIDTH-1:0] rf_reg;
|
||||
logic [NUM_WORDS-1:0] we_a_dec;
|
||||
|
||||
always_comb
|
||||
begin : we_a_decoder
|
||||
for (int i = 0; i < NUM_WORDS; i++) begin
|
||||
if (waddr_a_i == i)
|
||||
we_a_dec[i] = we_a_i;
|
||||
else
|
||||
we_a_dec[i] = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
|
||||
// loop from 1 to NUM_WORDS-1 as R0 is nil
|
||||
for (i = 1; i < NUM_WORDS; i++)
|
||||
begin : rf_gen
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin : register_write_behavioral
|
||||
if (rst_n==1'b0) begin
|
||||
rf_reg[i] <= 'b0;
|
||||
end else begin
|
||||
if (we_a_dec[i])
|
||||
rf_reg[i] <= wdata_a_i;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// R0 is nil
|
||||
assign rf_reg[0] = '0;
|
||||
|
||||
endgenerate
|
||||
|
||||
assign rdata_a_o = rf_reg[raddr_a_i];
|
||||
assign rdata_b_o = rf_reg[raddr_b_i];
|
||||
|
||||
endmodule
|
|
@ -54,11 +54,7 @@ dtype [NR_ENTRIES-1:0] mem_q, mem_n;
|
|||
logic [BITS_ENTRIES-1:0] issue_pointer_n, issue_pointer_q, // points to the instruction currently in issue
|
||||
commit_pointer_n, commit_pointer_q, // points to the instruction currently in commit
|
||||
top_pointer_n, top_pointer_q, top_pointer_qq; // points to the top of the scoreboard, an empty slot, top pointer two cycles ago
|
||||
// rd clobber register
|
||||
logic [31:0][$bits(fu_t)-1:0] rd_clobber_n, rd_clobber_q;
|
||||
// register read stage
|
||||
logic [63:0] rs1_n, rs1_q, rs2_n, rs2_q;
|
||||
logic rs1_valid_n, rs1_valid_q, rs2_valid_n, rs2_valid_q;
|
||||
|
||||
logic pointer_overflow;
|
||||
logic empty;
|
||||
logic reset_condition;
|
||||
|
@ -69,11 +65,7 @@ assign reset_condition = top_pointer_q == top_pointer_qq;
|
|||
assign pointer_overflow = (top_pointer_q <= commit_pointer_q && ~reset_condition) ? 1'b1 : 1'b0;
|
||||
assign full_o = (reset_condition) ? 1'b0 : (commit_pointer_q == top_pointer_q);
|
||||
assign empty = (pointer_overflow) ? 1'b0 : (commit_pointer_q == top_pointer_q);
|
||||
assign rd_clobber_o = rd_clobber_q;
|
||||
assign rs1_o = rs1_q;
|
||||
assign rs2_o = rs2_q;
|
||||
assign rs1_valid_o = rs1_valid_q;
|
||||
assign rs2_valid_o = rs2_valid_q;
|
||||
|
||||
// rd_clobber output: output currently clobbered destination registers
|
||||
// but only between commit and issue pointer
|
||||
// normal case: overflow case:
|
||||
|
@ -85,31 +77,31 @@ assign rs2_valid_o = rs2_valid_q;
|
|||
// |_________________________|<- top pointer |_________________________|
|
||||
//
|
||||
always_comb begin : clobber_output
|
||||
rd_clobber_n = rd_clobber_q;
|
||||
rd_clobber_o = '{default: 0};
|
||||
// excluding issue, the issue pointer points to the instruction which is currently not issued
|
||||
// but might be issued as soon as the issue unit acknowledges
|
||||
if (commit_pointer_q < issue_pointer_q) begin
|
||||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
// non overflowed case, depicted on the left
|
||||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q && i[BITS_ENTRIES-1:0] < issue_pointer_q)
|
||||
rd_clobber_n[mem_q[i].rd] = mem_q[i].fu;
|
||||
rd_clobber_o[mem_q[i].rd] = mem_q[i].fu;
|
||||
end
|
||||
end else begin // the issue pointer has overflowed, invert logic, depicted on the right
|
||||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q || i[BITS_ENTRIES-1:0] < issue_pointer_q)
|
||||
rd_clobber_n[mem_q[i].rd] = mem_q[i].fu;
|
||||
rd_clobber_o[mem_q[i].rd] = mem_q[i].fu;
|
||||
end
|
||||
end
|
||||
// // the zero register is always free
|
||||
rd_clobber_n[0] = NONE;
|
||||
// the zero register is always free
|
||||
rd_clobber_o[0] = NONE;
|
||||
end
|
||||
// read operand interface: same logic as register file, including a valid file
|
||||
always_comb begin : read_operands
|
||||
|
||||
rs1_n = rs1_q;
|
||||
rs2_n = rs2_q;
|
||||
rs1_valid_n = rs1_valid_q;
|
||||
rs2_valid_n = rs2_valid_q;
|
||||
rs1_o = 64'b0;
|
||||
rs2_o = 64'b0;
|
||||
rs1_valid_o = 1'b0;
|
||||
rs2_valid_o = 1'b0;
|
||||
|
||||
if (commit_pointer_q < issue_pointer_q) begin
|
||||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
|
@ -117,12 +109,12 @@ always_comb begin : read_operands
|
|||
// look at the appropriate fields and look whether there was an
|
||||
// instruction that wrote the rd field before, first for RS1 and then for RS2
|
||||
if (mem_q[i[BITS_ENTRIES-1:0]].rd == rs1_i) begin
|
||||
rs1_n = mem_q[i].result;
|
||||
rs1_valid_n = mem_q[i].valid;
|
||||
rs1_o = mem_q[i].result;
|
||||
rs1_valid_o = mem_q[i].valid;
|
||||
// do the same for rs2
|
||||
end else if (mem_q[i].rd == rs2_i) begin
|
||||
rs2_n = mem_q[i].result;
|
||||
rs2_valid_n = mem_q[i].valid;
|
||||
rs2_o = mem_q[i].result;
|
||||
rs2_valid_o = mem_q[i].valid;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -131,21 +123,21 @@ always_comb begin : read_operands
|
|||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q || i[BITS_ENTRIES-1:0] < issue_pointer_q) begin
|
||||
// same as above but for the overflowed pointer case
|
||||
if (mem_q[i[BITS_ENTRIES-1:0]].rd == rs1_i) begin
|
||||
rs1_n = mem_q[i].result;
|
||||
rs1_valid_n = mem_q[i].valid;
|
||||
rs1_o = mem_q[i].result;
|
||||
rs1_valid_o = mem_q[i].valid;
|
||||
// do the same for rs2
|
||||
end else if (mem_q[i[BITS_ENTRIES-1:0]].rd == rs2_i) begin
|
||||
rs2_n = mem_q[i].result;
|
||||
rs2_valid_n = mem_q[i].valid;
|
||||
rs2_o = mem_q[i].result;
|
||||
rs2_valid_o = mem_q[i].valid;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
// make sure we didn't read the zero register
|
||||
if (rs1_i == '0)
|
||||
rs1_valid_n = 1'b0;
|
||||
rs1_valid_o = 1'b0;
|
||||
if (rs2_i == '0)
|
||||
rs2_valid_n = 1'b0;
|
||||
rs2_valid_o = 1'b0;
|
||||
end
|
||||
// push new decoded instruction: if still empty space push the instruction to the scoreboard
|
||||
// write-back instruction: update value of RD register in scoreboard
|
||||
|
@ -230,33 +222,18 @@ end
|
|||
// sequential process
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : sequential
|
||||
if(~rst_ni) begin
|
||||
rd_clobber_q <= '{default: 0};
|
||||
rs1_q <= 64'b0;
|
||||
rs2_q <= 64'b0;
|
||||
rs1_valid_q <= 1'b0;
|
||||
rs2_valid_q <= 1'b0;
|
||||
issue_pointer_q <= '{default: 0};
|
||||
commit_pointer_q <= '{default: 0};
|
||||
top_pointer_q <= '{default: 0};
|
||||
top_pointer_qq <= '{default: 0};
|
||||
mem_q <= '{default: 0};
|
||||
end else if (flush_i) begin // reset pointers on flush
|
||||
rd_clobber_q <= '{default: 0};
|
||||
rs1_q <= 64'b0;
|
||||
rs2_q <= 64'b0;
|
||||
rs1_valid_q <= 1'b0;
|
||||
rs2_valid_q <= 1'b0;
|
||||
issue_pointer_q <= '{default: 0};
|
||||
commit_pointer_q <= '{default: 0};
|
||||
top_pointer_q <= '{default: 0};
|
||||
top_pointer_qq <= '{default: 0};
|
||||
mem_q <= '{default: 0};
|
||||
end else begin
|
||||
rs1_q <= rs1_n;
|
||||
rs2_q <= rs2_n;
|
||||
rs1_valid_q <= rs1_valid_n;
|
||||
rs2_valid_q <= rs2_valid_n;
|
||||
rd_clobber_q <= rd_clobber_n;
|
||||
issue_pointer_q <= issue_pointer_n;
|
||||
commit_pointer_q <= commit_pointer_n;
|
||||
top_pointer_q <= top_pointer_n;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue