1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
module exe (
input logic clk,
input logic rst,
//-----------------
// Decode Interface
//-----------------
input logic idu_exe_rs1Vld_EXE,
input logic [REG_IDX-1:0] idu_exe_rs1Idx_EXE,
input logic idu_exe_rs2Vld_EXE,
input logic [REG_IDX-1:0] idu_exe_rs2Idx_EXE,
input alu_op_t idu_exe_aluOp_EXE,
//-----------------
// Memory Interface
//-----------------
output logic [WORD_WID-1:0] exe_mem_aluOpOut_EXE,
//-----------------------
// Fetch Branch Interface
//-----------------------
output logic exe_ifu_brRes_EXE,
output logic exe_ifu_brTaken_EXE,
output logic [WORD_WID-1:0] exe_ifu_brPC_EXE,
//--------------------
// Writeback Interface
//--------------------
input logic wb_exe_rdVld_WB,
input logic [ REG_IDX-1:0] wb_exe_rdIdx_WB,
input logic [WORD_WID-1:0] wb_exe_rdData_WB
);
// Alu
logic [WORD_WID-1:0] aluSumDiff_EXE;
logic [WORD_WID-1:0] aluSumDiffIn1_EXE;
logic [WORD_WID-1:0] aluSumDiffIn2_EXE;
logic [WORD_WID-1:0] aluLeftShft_EXE;
logic [WORD_WID-1:0] aluRightShft_EXE;
logic [WORD_WID-1:0] aluRightShftUsign_EXE;
logic [WORD_WID-1:0] aluRightShftSext_EXE;
logic [WORD_WID-1:0] aluCmp_EXE;
logic [WORD_WID-1:0] aluCmpSign_EXE;
logic [WORD_WID-1:0] aluCmpUsign_EXE;
logic aluCmpMsbDiff_EXE;
logic aluCmpLowUsign_EXE;
// Branch Resolution
logic [ 5:0] brResChoice_EXE;
//--------------------
// Decode Output Flops
//--------------------
assign stallVld_ID = ~exe_idu_exeRdy_EXE;
// Flop Decode information
AFF #( .DTYPE(alu_op_t) ) AFF_EXE_aluOp ( .q(idu_exe_aluOp_EXE), .d(idu_exe_aluOp_ID), .en(stallVld_ID), .clk(clk) );
AFF #( .WIDTH(WORD_WID) ) AFF_EXE_pc ( .q(idu_exe_pc_EXE), .d(idu_exe_pc_ID), .en(stallVld_ID), .clk(clk) );
AFF #( .WIDTH(1) ) AFF_EXE_instrJmp ( .q(idu_exe_instrJmp_EXE), .d(idu_exe_instrJmp_ID), .en(stallVld_ID), .clk(clk) );
AFF #( .WIDTH(1) ) AFF_EXE_brRes ( .q(idu_exe_brRes_EXE), .d(brResNxt_EXEM1), .en(stallVld_ID), .clk(clk) );
//--------------
// Register File
//--------------
// FIXME: Add support for the zero register
always_ff @(posedge clk) begin
// RS1 Read Port with Forwarding
if (instrRs1Vld_ID) begin
idu_exe_rs1Data_EXE <= (wb_exe_rdVld_WB & (idu_exe_rs1Idx_ID == wb_exe_rdIdx_WB)) ? wb_exe_rdData_WB : regData_XXX[idu_exe_rs1Idx_ID];
end
// RS2 Read Port with Forwarding
if (instrRdVld_ID) begin
idu_exe_rs2Data_EXE <= (wb_exe_rdVld_WB & (idu_exe_rs1Idx_ID == wb_exe_rdIdx_WB)) ? wb_exe_rdData_WB : regData_XXX[idu_exe_rs2Idx_ID];
end
// RD Write Port
if (wb_exe_rdData_WB) begin
regData_XXX[wb_exe_rdIdx_WB] <= wb_exe_rdData_WB;
end
end
//----
// ALU
//----
// Operand Selection
assign aluIn1_EXE = (aluOp_EXE.rs1Sel == PC) ? pc_EXE : // PC for AUIPC, JAL
(aluOp_EXE.rs1Sel == ZERO) ? WORD_WID'(0) : // 0 for LUI
rs1Data_EXE; // RS1 for other operations
assign aluIn2_EXE = (aluOp_EXE.rs2Sel == RS2) ? rs2Data_EXE : // RS2 for R type operations
aluOp_EXE.immediate; // Immediate for all other operations
// Two's complement negation of aluIn2 if func7 is set (subtract)
assign aluSumDiffIn1_EXE = aluIn1_EXE;
assign aluSumDiffIn2_EXE = ({WORD_WID{aluOp_EXE.func7}} ^ aluIn2_EXE) + aluOp_EXE.func7;
assign aluSumDiff_EXE = aluSumDiffIn1_EXE + aluSumDiffIn2_EXE;
// Shifter, TODO: Explicit signed barrel shifter
assign aluRightShftUsign_EXE = aluIn1_EXE >> aluIn2_EXE[4:0];
assign aluRightShftSext_EXE = ~({WORD_WID{1'b1}} >> aluIn2_EXE[4:0]);
assign aluRightShft_EXE = aluRightShftUsgn_EXE | (aluRightShftSext_EXE & {WORD_WID{aluOp_EXE.func7}});
FLIP #(
.WIDTH(WORD_WID)
) EXE_aluLeftShft (
.in (aluRightShftUsign_EXE),
.out(aluLeftShft_EXE)
);
// Set Less Than
assign aluCmpMsbDiff_EXE = aluIn2_EXE ^ aluIn1_EXE;
assign aluCmpLowUsign_EXE = aluIn1_EXE[WORD_WID-2:0] < aluIn2_EXE[WORD_WID-2:0];
assign aluCmpSign_EXE = aluCmpMsbDiff_EXE ? aluIn1_EXE[WORD_WID-1] : aluCmpLowUsign_EXE; // If diff signs (MSB) and in1 negative, then in1 < 0 < in2, else compare low bits
assign aluCmpUSign_EXE = aluCmpMsbDiff_EXE ? aluIn2_EXE[WORD_WID-1] : aluCmpLowUsign_EXE; // If diff MSB and MSB in2[31] == 1, then in1 < in2, else compare low bits
// Bitwise Operations
assign aluXor_EXE = aluIn1_EXE ^ aluIn2_EXE;
assign aluOr_EXE = aluIn1_EXE | aluIn2_EXE;
assign aluAnd_EXE = aluIn1_EXE & aluIn2_EXE;
// ALU Operation Select
assign aluOpRes_EXE[0] = aluSumDiff_EXE;
assign aluOpRes_EXE[1] = aluLeftShft_EXE;
assign aluOpRes_EXE[2] = {(WORD_WID - 1)'(0), aluCmpSign_EXE};
assign aluOpRes_EXE[3] = {(WORD_WID - 1)'(0), aluCmpUSign_EXE};
assign aluOpRes_EXE[4] = aluXor_EXE;
assign aluOpRes_EXE[5] = aluRightShft_EXE;
assign aluOpRes_EXE[6] = aluOr_EXE;
assign aluOpRes_EXE[7] = aluAnd_EXE;
EMUX #(
.WIDTH (WORD_WID),
.INPUTS(8)
) EMUX_exe_aluOpSel (
.in (aluOpResults_EXE),
.out(aluOpOut_EXE),
.sel(aluOp_EXE.func3)
);
// rd is either PC from jump instr or alu output
assign exe_mem_rdData_EXE = instrJmp_EXE ? pc_EXE : aluOpOut_EXE;
//------------------
// Branch Resolution
//------------------
assign exe_ifu_brPC_EXE = aluOpOut_EXE;
assign exe_ifu_brRes_EXE = brRes_EXE; // FIXME: Only send this once after a branch is processed until stall is lifted
assign brResChoice_EXE[0] = ~|aluXor_EXE;
assign brResChoice_EXE[1] = |aluXor_EXE;
assign brResChoice_EXE[2] = aluCmpSign_EXE;
assign brResChoice_EXE[3] = ~aluCmpSign_EXE;
assign brResChoice_EXE[4] = aluCmpUSign_EXE;
assign brResChoice_EXE[5] = ~aluCmpUSign_EXE;
EMUX #(
.WIDTH (1),
.INPUTS(6)
) EMUX_exe_aluOpSel (
.in (brResChoice_EXE),
.out(exe_ifu_brTaken_EXE),
.sel(idu_exe_brOp_ID)
);
//---------------------
// Pipeline passthrough
//---------------------
endmodule
|