aboutsummaryrefslogtreecommitdiff
path: root/core/rtl/exe.sv
blob: c39807a707758927978d98e647b64816c821eebe (plain) (blame)
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
module exe (
  input  logic               clk,
  input  logic               rst,

  //-----------------
  // Decode Interface
  //-----------------
  input  logic               idu_exe_instrVld_ID,

  // Register Access
  input  logic               idu_exe_rs1Vld_ID,
  input  logic [REG_IDX-1:0] idu_exe_rs1Idx_ID,
  input  logic               idu_exe_rs2Vld_ID,
  input  logic [REG_IDX-1:0] idu_exe_rs2Idx_ID,

  // Branch Type
  input  logic               idu_exe_instrJmp_ID,
  input  logic               idu_exe_instrBr_ID,

  // ALU information
  input  alu_op_t            idu_exe_aluOp_ID,

  // Passthrough Information
  input  mem_op_t            idu_exe_instrMemOp_ID,
  input  mem_size_t          idu_exe_instrMemSize_ID,
  input  rd_data_sel_t       idu_exe_instrRdDataSel_ID,

  //-----------------
  // Memory Interface
  //-----------------
  // ALU Result information
  output logic [WORD_WID-1:0] exe_mem_aluOpOut_EXE,
  // Stall
  input  logic                mem_exe_stallVld_EXE,
  // Memory Information
  output mem_op_t             exe_mem_instrMemOp_EXE,
  output mem_size_t           exe_mem_instrMemSize_EXE,
  // Passthrough information
  output rd_data_sel_t        exe_mem_instrRdDataSel_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

);

  logic                instrVld_EXE;

  // 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;

  // Reg File
  logic [NUM_REG-1:1] [WORD_WID-1:0] regData_XXX;

  // Stall Signal
  assign stallVld_ID = exe_mem_instrVld_EXE & ~mem_exe_stallVld_EXE;

  //--------------------
  // Decode Output Flops
  //--------------------

  // Flop Decode information
  AFFR #(.WIDTH(1))        AFFR_EXE_instrVld (.q(exe_mem_instrVld_EXE), .d(idu_exe_instrVld_ID), .en(stallVld_ID), .clk(clk), rst(rst));
  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
  //--------------
  assign rs1WrFwd_ID = wb_exe_rdWrVld_WB & (idu_exe_rs1Idx_ID == wb_exe_rdIdx_WB);
  assign rs2WrFwd_ID = wb_exe_rdWrVld_WB & (idu_exe_rs2Idx_ID == wb_exe_rdIdx_WB);

  always_ff @(posedge clk) begin
    // RS1 Read Port with Forwarding
    if (instrRs1Vld_ID) begin
      if (idx_exe_rs1Idx == REG_IDX'0)                          // X0 Register
        idu_exe_rs1Data_EXE <= WORD_SIZE'0;
      else if (rs1WrFwd_ID) begin                               // Write Foward
        idu_exe_rs1Data_EXE <= wb_exe_rdData_WB;
      else                                                      // Normal Read
        idu_exe_rs1Data_EXE <= regData_XXX[idu_exe_rs1Idx_ID];
    end

    // RS2 Read Port with Forwarding
    if (instrRs2Vld_ID) begin
      if (idx_exe_rs2Idx == REG_IDX'0)                          // X0 Register
        idu_exe_rs2Data_EXE <= WORD_WID'0;
      else if (rs2WrFwd_ID) begin                               // Write Foward
        idu_exe_rs2Data_EXE <= wb_exe_rdData_WB;
      else                                                      // Normal Read
        idu_exe_rs2Data_EXE <= regData_XXX[idu_exe_rs1Idx_ID];
    end

    // RD Write Port
    if (wb_exe_rdWrVld_WB & (~|wb_exe_rdIdx_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 with sign bit
  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;
  assign exe_ifu_brTaken_EXE = (brTaken_EXE & idu_exe_instrBr_ID) | idu_exe_instrJmp_ID;


  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(brTaken_EXE),
      .sel(idu_exe_brOp_ID)
  );

  //---------------------
  // Pipeline passthrough
  //---------------------

  // Memory
  AFF #(.DTYPE(mem_op_t)) AFF_EXE_instRdDataSel (
    .q(exe_mem_instrMemOp_EXE),
    .d(idu_exe_instrMemOp_ID),
    .en(stallVld_ID),
    .clk(clk)
  );

  AFF #(.DTYPE(mem_op_size_t)) AFF_EXE_instMemSize (
    .q(exe_mem_instrMemSize_EXE),
    .d(idu_exe_instrMemSize_ID),
    .en(stallVld_ID),
    .clk(clk)
  );

  // Write Back
  AFF #(.DTYPE(rd_data_sel_t)) AFF_EXE_instRdDataSel (
    .q(exe_mem_instrRdDataSel_EXE),
    .d(idu_exe_instrRdDataSel_ID),
    .en(stallVld_ID),
    .clk(clk)
  );

endmodule