blob: 1471fd2fc5b21aa4426192b22909c8454ae9c161 [file] [log] [blame]
Philipp Wagner31441082020-07-14 11:17:21 +01001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5`include "prim_assert.sv"
6
7/**
8 * OTBN Controller
9 */
10module otbn_controller
11 import otbn_pkg::*;
12#(
13 // Size of the instruction memory, in bytes
14 parameter int ImemSizeByte = 4096,
15 // Size of the data memory, in bytes
16 parameter int DmemSizeByte = 4096,
17
18 localparam int ImemAddrWidth = prim_util_pkg::vbits(ImemSizeByte),
19 localparam int DmemAddrWidth = prim_util_pkg::vbits(DmemSizeByte)
20) (
21 input logic clk_i,
22 input logic rst_ni,
23
24 input logic start_i, // start the processing at start_addr_i
25 output logic done_o, // processing done, signaled by ECALL
26 input logic [ImemAddrWidth-1:0] start_addr_i,
27
28 // Next instruction selection (to instruction fetch)
29 output logic insn_fetch_req_valid_o,
30 output logic [ImemAddrWidth-1:0] insn_fetch_req_addr_o,
31
32 // Fetched/decoded instruction
33 input logic insn_valid_i,
34 input logic [ImemAddrWidth-1:0] insn_addr_i,
Philipp Wagner31441082020-07-14 11:17:21 +010035
36 // Decoded instruction data, matching the "Decoding" section of the specification.
37 input insn_dec_base_t insn_dec_base_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010038 input insn_dec_bignum_t insn_dec_bignum_i,
39 input insn_dec_shared_t insn_dec_shared_i,
Philipp Wagner31441082020-07-14 11:17:21 +010040
41 // Base register file
42 output logic [4:0] rf_base_wr_addr_o,
43 output logic rf_base_wr_en_o,
44 output logic [31:0] rf_base_wr_data_o,
45
46 output logic [4:0] rf_base_rd_addr_a_o,
Greg Chadwick9afeb5e2020-10-15 17:58:55 +010047 output logic rf_base_rd_en_a_o,
Philipp Wagner31441082020-07-14 11:17:21 +010048 input logic [31:0] rf_base_rd_data_a_i,
49
50 output logic [4:0] rf_base_rd_addr_b_o,
Greg Chadwick9afeb5e2020-10-15 17:58:55 +010051 output logic rf_base_rd_en_b_o,
Philipp Wagner31441082020-07-14 11:17:21 +010052 input logic [31:0] rf_base_rd_data_b_i,
53
Greg Chadwickf7863442020-09-14 18:11:33 +010054 // Bignum register file (WDRs)
55 output logic [4:0] rf_bignum_wr_addr_o,
56 output logic [1:0] rf_bignum_wr_en_o,
57 output logic [WLEN-1:0] rf_bignum_wr_data_o,
58
59 output logic [4:0] rf_bignum_rd_addr_a_o,
60 input logic [WLEN-1:0] rf_bignum_rd_data_a_i,
61
62 output logic [4:0] rf_bignum_rd_addr_b_o,
63 input logic [WLEN-1:0] rf_bignum_rd_data_b_i,
64
Philipp Wagner31441082020-07-14 11:17:21 +010065 // Execution units
Greg Chadwickf7863442020-09-14 18:11:33 +010066
67 // Base ALU
Greg Chadwick9791eed2020-07-22 18:08:28 +010068 output alu_base_operation_t alu_base_operation_o,
69 output alu_base_comparison_t alu_base_comparison_o,
70 input logic [31:0] alu_base_operation_result_i,
Greg Chadwickc8cd4352020-08-14 16:45:23 +010071 input logic alu_base_comparison_result_i,
72
Greg Chadwickf7863442020-09-14 18:11:33 +010073 // Bignum ALU
74 output alu_bignum_operation_t alu_bignum_operation_o,
75 input logic [WLEN-1:0] alu_bignum_operation_result_i,
76
Greg Chadwick94786452020-10-28 18:19:51 +000077 // Bignum MAC
78 output mac_bignum_operation_t mac_bignum_operation_o,
79 input logic [WLEN-1:0] mac_bignum_operation_result_i,
80 output logic mac_bignum_en_o,
81
Greg Chadwickf7863442020-09-14 18:11:33 +010082 // LSU
Greg Chadwickc8cd4352020-08-14 16:45:23 +010083 output logic lsu_load_req_o,
84 output logic lsu_store_req_o,
85 output insn_subset_e lsu_req_subset_o,
86 output logic [DmemAddrWidth-1:0] lsu_addr_o,
87
88 output logic [31:0] lsu_base_wdata_o,
89 output logic [WLEN-1:0] lsu_bignum_wdata_o,
90
91 input logic [31:0] lsu_base_rdata_i,
92 input logic [WLEN-1:0] lsu_bignum_rdata_i,
Rupert Swarbrick40cd9142020-12-02 11:02:17 +000093 input logic lsu_rdata_err_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010094
95 // Internal Special-Purpose Registers (ISPRs)
96 output ispr_e ispr_addr_o,
97 output logic [31:0] ispr_base_wdata_o,
98 output logic [BaseWordsPerWLEN-1:0] ispr_base_wr_en_o,
99 output logic [WLEN-1:0] ispr_bignum_wdata_o,
100 output logic ispr_bignum_wr_en_o,
101 input logic [WLEN-1:0] ispr_rdata_i
Philipp Wagner31441082020-07-14 11:17:21 +0100102);
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100103 otbn_state_e state_q, state_d;
Greg Chadwick28836af2020-07-23 14:35:52 +0100104
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100105 logic stall;
106 logic mem_stall;
Greg Chadwick51f36232020-09-02 15:37:23 +0100107 logic branch_taken;
108 logic [ImemAddrWidth-1:0] branch_target;
109 logic [ImemAddrWidth-1:0] next_insn_addr;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100110
Greg Chadwickf7863442020-09-14 18:11:33 +0100111 csr_e csr_addr;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000112 logic [31:0] csr_rdata_raw;
Greg Chadwickf7863442020-09-14 18:11:33 +0100113 logic [31:0] csr_rdata;
114 logic [BaseWordsPerWLEN-1:0] csr_rdata_mux [32];
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000115 logic [31:0] csr_wdata_raw;
Greg Chadwickf7863442020-09-14 18:11:33 +0100116 logic [31:0] csr_wdata;
117
118 wsr_e wsr_addr;
119 logic [WLEN-1:0] wsr_wdata;
120
121 ispr_e ispr_addr_base;
122 logic [$clog2(BaseWordsPerWLEN)-1:0] ispr_word_addr_base;
123 logic [BaseWordsPerWLEN-1:0] ispr_word_sel_base;
124
125 ispr_e ispr_addr_bignum;
126
127 logic ispr_wr_insn;
128
Greg Chadwickae8e6452020-10-02 12:04:15 +0100129 // Computed increments for indirect register index and memory address in BN.LID/BN.SID/BN.MOVR
130 // instructions.
131 logic [4:0] rf_base_rd_data_a_inc;
132 logic [4:0] rf_base_rd_data_b_inc;
133 logic [DmemAddrWidth-1:0] rf_base_rd_data_a_wlen_word_inc;
134
135 // Output of mux taking the above increments as inputs and choosing one to write back to base
136 // register file with appropriate zero extension and padding to give a 32-bit result.
137 logic [31:0] increment_out;
138
Greg Chadwick53c95862020-10-14 17:58:38 +0100139 // Loop control, used to start a new loop
140 logic loop_start;
141 logic [11:0] loop_bodysize;
142 logic [31:0] loop_iterations;
143
144 // Loop generated jumps. The loop controller asks to jump when execution reaches the end of a loop
145 // body that hasn't completed all of its iterations.
146 logic loop_jump;
147 logic [ImemAddrWidth-1:0] loop_jump_addr;
148
Greg Chadwick94786452020-10-28 18:19:51 +0000149 logic [WLEN-1:0] mac_bignum_rf_wr_data;
150
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100151 // Stall a cycle on loads to allow load data writeback to happen the following cycle. Stall not
152 // required on stores as there is no response to deal with.
153 // TODO: Possibility of error response on store? Probably still don't need to stall in that case
154 // just ensure incoming store error stops anything else happening.
155 assign mem_stall = lsu_load_req_o;
156
157 assign stall = mem_stall;
Greg Chadwick0cefd542020-12-03 15:41:59 +0000158 assign done_o = insn_valid_i && insn_dec_shared_i.ecall_insn;
Philipp Wagner31441082020-07-14 11:17:21 +0100159
Greg Chadwick51f36232020-09-02 15:37:23 +0100160 // Branch taken when there is a valid branch instruction and comparison passes or a valid jump
161 // instruction (which is always taken)
Philipp Wagnerdc946522020-12-03 10:52:58 +0000162 assign branch_taken = insn_valid_i &
163 ((insn_dec_shared_i.branch_insn & alu_base_comparison_result_i) |
164 insn_dec_shared_i.jump_insn);
Greg Chadwick51f36232020-09-02 15:37:23 +0100165 // Branch target computed by base ALU (PC + imm)
166 // TODO: Implement error on branch out of range
167 assign branch_target = alu_base_operation_result_i[ImemAddrWidth-1:0];
168
169 assign next_insn_addr = insn_addr_i + 'd4;
170
Philipp Wagner31441082020-07-14 11:17:21 +0100171 always_comb begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100172 state_d = state_q;
Greg Chadwick28836af2020-07-23 14:35:52 +0100173 insn_fetch_req_valid_o = 1'b0;
174 insn_fetch_req_addr_o = start_addr_i;
175
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100176 // TODO: Harden state machine
Philipp Wagner31441082020-07-14 11:17:21 +0100177 // TODO: Jumps/branches
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100178 unique case (state_q)
179 OtbnStateHalt: begin
180 if (start_i) begin
181 state_d = OtbnStateRun;
182 insn_fetch_req_addr_o = start_addr_i;
Rupert Swarbrick333ca692020-10-09 15:04:40 +0100183 insn_fetch_req_valid_o = 1'b1;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100184 end
185 end
186 OtbnStateRun: begin
187 insn_fetch_req_valid_o = 1'b1;
188
Greg Chadwick0cefd542020-12-03 15:41:59 +0000189 if (done_o) begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100190 state_d = OtbnStateHalt;
191 insn_fetch_req_valid_o = 1'b0;
192 end else begin
193 // When stalling refetch the same instruction to keep decode inputs constant
194 if (stall) begin
Greg Chadwick51f36232020-09-02 15:37:23 +0100195 state_d = OtbnStateStall;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100196 insn_fetch_req_addr_o = insn_addr_i;
197 end else begin
Greg Chadwick51f36232020-09-02 15:37:23 +0100198 if (branch_taken) begin
199 insn_fetch_req_addr_o = branch_target;
Greg Chadwick53c95862020-10-14 17:58:38 +0100200 end else if (loop_jump) begin
201 insn_fetch_req_addr_o = loop_jump_addr;
Greg Chadwick51f36232020-09-02 15:37:23 +0100202 end else begin
203 insn_fetch_req_addr_o = next_insn_addr;
204 end
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100205 end
206 end
207 end
208 OtbnStateStall: begin
209 // Only ever stall for a single cycle
210 // TODO: Any more than one cycle stall cases?
211 insn_fetch_req_valid_o = 1'b1;
Greg Chadwick51f36232020-09-02 15:37:23 +0100212 insn_fetch_req_addr_o = next_insn_addr;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100213 state_d = OtbnStateRun;
214 end
215 default: ;
216 endcase
Philipp Wagner31441082020-07-14 11:17:21 +0100217 end
218
Philipp Wagnerdc946522020-12-03 10:52:58 +0000219 `ASSERT(ControllerStateValid, state_q inside {OtbnStateHalt, OtbnStateRun, OtbnStateStall})
Greg Chadwick51f36232020-09-02 15:37:23 +0100220 // Branch only takes effect in OtbnStateRun so must not go into stall state for branch
221 // instructions.
Philipp Wagnerdc946522020-12-03 10:52:58 +0000222 `ASSERT(NoStallOnBranch,
223 insn_valid_i & insn_dec_shared_i.branch_insn |-> state_q != OtbnStateStall)
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100224
Greg Chadwick28836af2020-07-23 14:35:52 +0100225 always_ff @(posedge clk_i or negedge rst_ni) begin
226 if (!rst_ni) begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100227 state_q <= OtbnStateHalt;
Greg Chadwick28836af2020-07-23 14:35:52 +0100228 end else begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100229 state_q <= state_d;
Greg Chadwick28836af2020-07-23 14:35:52 +0100230 end
231 end
232
Greg Chadwick53c95862020-10-14 17:58:38 +0100233 otbn_loop_controller #(
234 .ImemAddrWidth(ImemAddrWidth)
235 ) u_otbn_loop_controller (
236 .clk_i,
237 .rst_ni,
238
239 .insn_addr_i,
240 .next_insn_addr_i (next_insn_addr),
241
242 .loop_start_i (loop_start),
243 .loop_bodysize_i (loop_bodysize),
244 .loop_iterations_i (loop_iterations),
245
246 .loop_jump_o (loop_jump),
247 .loop_jump_addr_o (loop_jump_addr),
248 .loop_err_o ()
249 );
250
251 assign loop_start = insn_valid_i & insn_dec_shared_i.loop_insn;
252 assign loop_bodysize = insn_dec_base_i.loop_bodysize;
253 assign loop_iterations = insn_dec_base_i.loop_immediate ? insn_dec_base_i.i : rf_base_rd_data_a_i;
254
Greg Chadwickae8e6452020-10-02 12:04:15 +0100255 // Compute increments which can be optionally applied to indirect register accesses and memory
256 // addresses in BN.LID/BN.SID/BN.MOVR instructions.
257 assign rf_base_rd_data_a_inc = rf_base_rd_data_a_i[4:0] + 1'b1;
258 assign rf_base_rd_data_b_inc = rf_base_rd_data_b_i[4:0] + 1'b1;
259 assign rf_base_rd_data_a_wlen_word_inc = {rf_base_rd_data_a_i[DmemAddrWidth-1:5] + 1'b1, 5'b0};
260
261 // Choose increment to write back to base register file, only one increment can be written as
262 // there is only one write port. Note that where an instruction is incrementing the indirect
263 // reference to its destination register (insn_dec_bignum_i.d_inc) that reference is read on the
264 // B read port so the B increment is written back.
265 always_comb begin
266 unique case (1'b1)
267 insn_dec_bignum_i.a_inc: begin
268 increment_out = {27'b0, rf_base_rd_data_a_inc};
269 end
270 insn_dec_bignum_i.b_inc: begin
271 increment_out = {27'b0, rf_base_rd_data_b_inc};
272 end
273 insn_dec_bignum_i.d_inc: begin
274 increment_out = {27'b0, rf_base_rd_data_b_inc};
275 end
276 insn_dec_bignum_i.a_wlen_word_inc: begin
277 increment_out = {{32-DmemAddrWidth{1'b0}}, rf_base_rd_data_a_wlen_word_inc};
278 end
Pirmin Vogele97cac02020-11-02 12:28:50 +0100279 default: begin
280 // Whenever increment_out is written back to the register file, exactly one of the
281 // increment selector signals is high. To prevent the automatic inference of latches in
282 // case nothing is written back (rf_wdata_sel != RfWdSelIncr) and to save logic, we choose
283 // a valid output as default.
284 increment_out = {27'b0, rf_base_rd_data_a_inc};
285 end
Greg Chadwickae8e6452020-10-02 12:04:15 +0100286 endcase
287 end
288
289 always_comb begin
290 rf_base_rd_addr_a_o = insn_dec_base_i.a;
Greg Chadwickef411792020-12-01 17:44:34 +0000291 rf_base_rd_en_a_o = insn_dec_base_i.rf_ren_a & insn_valid_i;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100292 rf_base_rd_addr_b_o = insn_dec_base_i.b;
Greg Chadwickef411792020-12-01 17:44:34 +0000293 rf_base_rd_en_b_o = insn_dec_base_i.rf_ren_b & insn_valid_i;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100294 rf_base_wr_addr_o = insn_dec_base_i.d;
295
296 if (insn_dec_shared_i.subset == InsnSubsetBignum) begin
297 unique case (1'b1)
298 insn_dec_bignum_i.a_inc,
299 insn_dec_bignum_i.a_wlen_word_inc: begin
300 rf_base_wr_addr_o = insn_dec_base_i.a;
301 end
302
303 insn_dec_bignum_i.b_inc,
304 insn_dec_bignum_i.d_inc: begin
305 rf_base_wr_addr_o = insn_dec_base_i.b;
306 end
307 default: ;
308 endcase
309 end
310 end
Philipp Wagner31441082020-07-14 11:17:21 +0100311
312 // Base ALU Operand A MUX
313 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100314 unique case (insn_dec_base_i.op_a_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100315 OpASelRegister: alu_base_operation_o.operand_a = rf_base_rd_data_a_i;
316 OpASelZero: alu_base_operation_o.operand_a = '0;
317 OpASelCurrPc: alu_base_operation_o.operand_a = {{(32 - ImemAddrWidth){1'b0}}, insn_addr_i};
318 default: alu_base_operation_o.operand_a = rf_base_rd_data_a_i;
Philipp Wagner31441082020-07-14 11:17:21 +0100319 endcase
320 end
321
322 // Base ALU Operand B MUX
323 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100324 unique case (insn_dec_base_i.op_b_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100325 OpBSelRegister: alu_base_operation_o.operand_b = rf_base_rd_data_b_i;
326 OpBSelImmediate: alu_base_operation_o.operand_b = insn_dec_base_i.i;
327 default: alu_base_operation_o.operand_b = rf_base_rd_data_b_i;
Philipp Wagner31441082020-07-14 11:17:21 +0100328 endcase
329 end
330
Greg Chadwicke177f172020-09-09 14:46:03 +0100331 assign alu_base_operation_o.op = insn_dec_base_i.alu_op;
Philipp Wagner31441082020-07-14 11:17:21 +0100332
Greg Chadwick9791eed2020-07-22 18:08:28 +0100333 assign alu_base_comparison_o.operand_a = rf_base_rd_data_a_i;
334 assign alu_base_comparison_o.operand_b = rf_base_rd_data_b_i;
Greg Chadwicke177f172020-09-09 14:46:03 +0100335 assign alu_base_comparison_o.op = insn_dec_base_i.comparison_op;
Greg Chadwick9791eed2020-07-22 18:08:28 +0100336
Philipp Wagner31441082020-07-14 11:17:21 +0100337 // Register file write MUX
Greg Chadwick121847e2020-09-02 15:31:28 +0100338 // Suppress write for loads when controller isn't in stall state as load data for writeback is
339 // only available in the stall state.
Greg Chadwickf6f35962020-11-02 17:32:08 +0000340 assign rf_base_wr_en_o = insn_valid_i & insn_dec_base_i.rf_we &
Greg Chadwickcf048242020-10-02 15:28:42 +0100341 ~(insn_dec_shared_i.ld_insn & (state_q != OtbnStateStall));
Philipp Wagner31441082020-07-14 11:17:21 +0100342
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100343 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100344 unique case (insn_dec_base_i.rf_wdata_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100345 RfWdSelEx: rf_base_wr_data_o = alu_base_operation_result_i;
346 RfWdSelLsu: rf_base_wr_data_o = lsu_base_rdata_i;
347 RfWdSelNextPc: rf_base_wr_data_o = {{(32-ImemAddrWidth){1'b0}}, next_insn_addr};
348 RfWdSelIspr: rf_base_wr_data_o = csr_rdata;
349 RfWdSelIncr: rf_base_wr_data_o = increment_out;
350 default: rf_base_wr_data_o = alu_base_operation_result_i;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100351 endcase
352 end
353
Greg Chadwickae8e6452020-10-02 12:04:15 +0100354 assign rf_bignum_rd_addr_a_o = insn_dec_bignum_i.rf_a_indirect ? rf_base_rd_data_a_i[4:0] :
355 insn_dec_bignum_i.a;
356
357 assign rf_bignum_rd_addr_b_o = insn_dec_bignum_i.rf_b_indirect ? rf_base_rd_data_b_i[4:0] :
358 insn_dec_bignum_i.b;
Greg Chadwickf7863442020-09-14 18:11:33 +0100359
360 assign alu_bignum_operation_o.operand_a = rf_bignum_rd_data_a_i;
361
362 // Base ALU Operand B MUX
363 always_comb begin
Greg Chadwick94786452020-10-28 18:19:51 +0000364 unique case (insn_dec_bignum_i.alu_op_b_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100365 OpBSelRegister: alu_bignum_operation_o.operand_b = rf_bignum_rd_data_b_i;
366 OpBSelImmediate: alu_bignum_operation_o.operand_b = insn_dec_bignum_i.i;
367 default: alu_bignum_operation_o.operand_b = rf_bignum_rd_data_b_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100368 endcase
369 end
370
371 assign alu_bignum_operation_o.op = insn_dec_bignum_i.alu_op;
Greg Chadwick94786452020-10-28 18:19:51 +0000372 assign alu_bignum_operation_o.shift_right = insn_dec_bignum_i.alu_shift_right;
373 assign alu_bignum_operation_o.shift_amt = insn_dec_bignum_i.alu_shift_amt;
374 assign alu_bignum_operation_o.flag_group = insn_dec_bignum_i.alu_flag_group;
375 assign alu_bignum_operation_o.sel_flag = insn_dec_bignum_i.alu_sel_flag;
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000376 assign alu_bignum_operation_o.alu_flag_en = insn_dec_bignum_i.alu_flag_en;
377 assign alu_bignum_operation_o.mac_flag_en = insn_dec_bignum_i.mac_flag_en;
Greg Chadwickf7863442020-09-14 18:11:33 +0100378
Greg Chadwick94786452020-10-28 18:19:51 +0000379 assign mac_bignum_operation_o.operand_a = rf_bignum_rd_data_a_i;
380 assign mac_bignum_operation_o.operand_b = rf_bignum_rd_data_b_i;
381 assign mac_bignum_operation_o.operand_a_qw_sel = insn_dec_bignum_i.mac_op_a_qw_sel;
382 assign mac_bignum_operation_o.operand_b_qw_sel = insn_dec_bignum_i.mac_op_b_qw_sel;
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000383 assign mac_bignum_operation_o.wr_hw_sel_upper = insn_dec_bignum_i.mac_wr_hw_sel_upper;
Greg Chadwick94786452020-10-28 18:19:51 +0000384 assign mac_bignum_operation_o.pre_acc_shift_imm = insn_dec_bignum_i.mac_pre_acc_shift;
385 assign mac_bignum_operation_o.zero_acc = insn_dec_bignum_i.mac_zero_acc;
386 assign mac_bignum_operation_o.shift_acc = insn_dec_bignum_i.mac_shift_out;
387
388 assign mac_bignum_en_o = insn_dec_bignum_i.mac_en & insn_valid_i;
389
390
391 // Bignum Register file write control
392
393 always_comb begin
394 // By default write nothing
395 rf_bignum_wr_en_o = 2'b00;
396
397 // Only write if enabled
Greg Chadwickf6f35962020-11-02 17:32:08 +0000398 if (insn_valid_i && insn_dec_bignum_i.rf_we) begin
Greg Chadwick94786452020-10-28 18:19:51 +0000399 if (insn_dec_bignum_i.mac_en && insn_dec_bignum_i.mac_shift_out) begin
400 // Special handling for BN.MULQACC.SO, only enable upper or lower half depending on
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000401 // mac_wr_hw_sel_upper.
402 rf_bignum_wr_en_o = insn_dec_bignum_i.mac_wr_hw_sel_upper ? 2'b10 : 2'b01;
Greg Chadwick94786452020-10-28 18:19:51 +0000403 end else if (insn_dec_shared_i.ld_insn) begin
404 // Special handling for BN.LID. Load data is requested in the first cycle of the instruction
405 // (where state_q == OtbnStateRun) and is available in the second cycle following the
406 // request (where state_q == OtbnStateStall), so only enable writes for BN.LID when in
407 // OtbnStateStall.
408 if (state_q == OtbnStateStall) begin
409 rf_bignum_wr_en_o = 2'b11;
410 end
411 end else begin
412 // For everything else write both halves immediately.
413 rf_bignum_wr_en_o = 2'b11;
414 end
415 end
416 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100417
Greg Chadwickae8e6452020-10-02 12:04:15 +0100418 assign rf_bignum_wr_addr_o = insn_dec_bignum_i.rf_d_indirect ? rf_base_rd_data_b_i[4:0] :
419 insn_dec_bignum_i.d;
Greg Chadwickf7863442020-09-14 18:11:33 +0100420
Greg Chadwick94786452020-10-28 18:19:51 +0000421 // For the shift-out variant of BN.MULQACC the bottom half of the MAC result is written to one
Philipp Wagnerdc946522020-12-03 10:52:58 +0000422 // half of a desintation register specified by the instruction (mac_wr_hw_sel_upper). The bottom
423 // half of the MAC result must be placed in the appropriate half of the write data (the RF only
424 // accepts write data for the top half in the top half of the write data input). Otherwise
425 // (shift-out to bottom half and all other BN.MULQACC instructions) simply pass the MAC result
426 // through unchanged as write data.
Greg Chadwick94786452020-10-28 18:19:51 +0000427 assign mac_bignum_rf_wr_data[WLEN-1:WLEN/2] =
Philipp Wagnerdc946522020-12-03 10:52:58 +0000428 insn_dec_bignum_i.mac_wr_hw_sel_upper &&
429 insn_dec_bignum_i.mac_shift_out ? mac_bignum_operation_result_i[WLEN/2-1:0] :
430 mac_bignum_operation_result_i[WLEN-1:WLEN/2];
Greg Chadwick94786452020-10-28 18:19:51 +0000431
432 assign mac_bignum_rf_wr_data[WLEN/2-1:0] = mac_bignum_operation_result_i[WLEN/2-1:0];
433
Greg Chadwickf7863442020-09-14 18:11:33 +0100434 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100435 unique case (insn_dec_bignum_i.rf_wdata_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100436 RfWdSelEx: rf_bignum_wr_data_o = alu_bignum_operation_result_i;
437 RfWdSelLsu: rf_bignum_wr_data_o = lsu_bignum_rdata_i;
438 RfWdSelIspr: rf_bignum_wr_data_o = ispr_rdata_i;
Greg Chadwick94786452020-10-28 18:19:51 +0000439 RfWdSelMac: rf_bignum_wr_data_o = mac_bignum_rf_wr_data;
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100440 default: rf_bignum_wr_data_o = alu_bignum_operation_result_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100441 endcase
442 end
443
444 // CSR/WSR/ISPR handling
445 // ISPRs (Internal Special Purpose Registers) are the internal registers. CSRs and WSRs are the
446 // ISA visible versions of those registers in the base and bignum ISAs respectively.
447
448 assign csr_addr = csr_e'(insn_dec_base_i.i[11:0]);
449
450 always_comb begin
451 ispr_addr_base = IsprMod;
452 ispr_word_addr_base = '0;
453
454 unique case (csr_addr)
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000455 CsrFlags, CsrFg0, CsrFg1 : begin
Greg Chadwickf7863442020-09-14 18:11:33 +0100456 ispr_addr_base = IsprFlags;
457 ispr_word_addr_base = '0;
458 end
459 CsrMod0,CsrMod1,CsrMod2,CsrMod3,CsrMod4,CsrMod5,CsrMod6,CsrMod7: begin
460 ispr_addr_base = IsprMod;
461 ispr_word_addr_base = csr_addr[2:0];
462 end
463 CsrRnd: begin
464 ispr_addr_base = IsprRnd;
465 ispr_word_addr_base = '0;
466 end
467 // TODO: Illegal addr handling
468 default: ;
469 endcase
470 end
471
472 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_ispr_word_sel_base
473 assign ispr_word_sel_base[i_word] = ispr_word_addr_base == i_word;
474 end
475
476 for (genvar i_bit = 0; i_bit < 32; i_bit++) begin : g_csr_rdata_mux
477 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_csr_rdata_mux_inner
Philipp Wagnerdc946522020-12-03 10:52:58 +0000478 assign csr_rdata_mux[i_bit][i_word] =
479 ispr_rdata_i[i_word*32 + i_bit] & ispr_word_sel_base[i_word];
Greg Chadwickf7863442020-09-14 18:11:33 +0100480 end
481
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000482 assign csr_rdata_raw[i_bit] = |csr_rdata_mux[i_bit];
Greg Chadwickf7863442020-09-14 18:11:33 +0100483 end
484
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000485 // Specialised read data handling for CSR reads where raw read data needs modification.
486 always_comb begin
487 csr_rdata = csr_rdata_raw;
488
489 unique case(csr_addr)
490 // For FG0/FG1 select out appropriate bits from FLAGS ISPR and pad the rest with zeros.
491 CsrFg0: csr_rdata = {28'b0, csr_rdata_raw[3:0]};
492 CsrFg1: csr_rdata = {28'b0, csr_rdata_raw[7:4]};
493 default: ;
494 endcase
495 end
496
Philipp Wagnerdc946522020-12-03 10:52:58 +0000497 assign csr_wdata_raw = insn_dec_shared_i.ispr_rs_insn ? csr_rdata | rf_base_rd_data_a_i :
498 rf_base_rd_data_a_i;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000499
500 // Specialised write data handling for CSR writes where raw write data needs modification.
501 always_comb begin
502 csr_wdata = csr_wdata_raw;
503
504 unique case(csr_addr)
505 // For FG0/FG1 only modify relevant part of FLAGS ISPR.
506 CsrFg0: csr_wdata = {24'b0, csr_rdata_raw[7:4], csr_wdata_raw[3:0]};
507 CsrFg1: csr_wdata = {24'b0, csr_wdata_raw[3:0], csr_rdata_raw[3:0]};
508 default: ;
509 endcase
510 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100511
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000512 // ISPR RS (read and set) must not be combined with ISPR RD or WR (read or write). ISPR RD and
513 // WR (read and write) is allowed.
514 `ASSERT(NoIsprRorWAndRs, insn_valid_i |-> ~(insn_dec_shared_i.ispr_rs_insn &
515 (insn_dec_shared_i.ispr_rd_insn |
516 insn_dec_shared_i.ispr_wr_insn)))
517
518
Greg Chadwickf7863442020-09-14 18:11:33 +0100519 assign wsr_addr = wsr_e'(insn_dec_bignum_i.i[WsrNumWidth-1:0]);
520
521 always_comb begin
522 ispr_addr_bignum = IsprMod;
523
524 unique case (wsr_addr)
525 WsrMod: ispr_addr_bignum = IsprMod;
526 WsrRnd: ispr_addr_bignum = IsprRnd;
527 WsrAcc: ispr_addr_bignum = IsprAcc;
528 default: ;
529 endcase
530 end
531
Philipp Wagnerdc946522020-12-03 10:52:58 +0000532 assign wsr_wdata = insn_dec_shared_i.ispr_rs_insn ? ispr_rdata_i | rf_bignum_rd_data_a_i :
533 rf_bignum_rd_data_a_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100534
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000535 assign ispr_wr_insn = insn_dec_shared_i.ispr_wr_insn | insn_dec_shared_i.ispr_rs_insn;
Greg Chadwickf7863442020-09-14 18:11:33 +0100536
Philipp Wagnerdc946522020-12-03 10:52:58 +0000537 assign ispr_addr_o = insn_dec_shared_i.subset == InsnSubsetBase ? ispr_addr_base :
538 ispr_addr_bignum;
Greg Chadwickf7863442020-09-14 18:11:33 +0100539 assign ispr_base_wdata_o = csr_wdata;
Greg Chadwickf6f35962020-11-02 17:32:08 +0000540 assign ispr_base_wr_en_o =
541 {BaseWordsPerWLEN{(insn_dec_shared_i.subset == InsnSubsetBase) & ispr_wr_insn & insn_valid_i}}
542 & ispr_word_sel_base;
543
Greg Chadwickf7863442020-09-14 18:11:33 +0100544 assign ispr_bignum_wdata_o = wsr_wdata;
Greg Chadwickf6f35962020-11-02 17:32:08 +0000545 assign ispr_bignum_wr_en_o = (insn_dec_shared_i.subset == InsnSubsetBignum) & ispr_wr_insn
546 & insn_valid_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100547
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100548 // TODO: Add error on unaligned/out of bounds
Greg Chadwickf7863442020-09-14 18:11:33 +0100549 assign lsu_load_req_o = insn_valid_i & insn_dec_shared_i.ld_insn & (state_q == OtbnStateRun);
550 assign lsu_store_req_o = insn_valid_i & insn_dec_shared_i.st_insn & (state_q == OtbnStateRun);
551 assign lsu_req_subset_o = insn_dec_shared_i.subset;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100552
Greg Chadwickae8e6452020-10-02 12:04:15 +0100553 assign lsu_addr_o = alu_base_operation_result_i[DmemAddrWidth-1:0];
554 assign lsu_base_wdata_o = rf_base_rd_data_b_i;
555 assign lsu_bignum_wdata_o = rf_bignum_rd_data_b_i;
Greg Chadwick6ab8d952020-10-30 12:13:34 +0000556
557 // RF Read enables for bignum RF are unused for now. Future security hardening work may make use
558 // of them.
559 logic unused_rf_ren_a_bignum;
560 logic unused_rf_ren_b_bignum;
561
562 assign unused_rf_ren_a_bignum = insn_dec_bignum_i.rf_ren_a;
563 assign unused_rf_ren_b_bignum = insn_dec_bignum_i.rf_ren_b;
564
565 // TODO: Implement error handling
Rupert Swarbrick40cd9142020-12-02 11:02:17 +0000566 logic unused_lsu_rdata_err;
Greg Chadwick6ab8d952020-10-30 12:13:34 +0000567 assign unused_lsu_rdata_err = lsu_rdata_err_i;
568
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000569 // Unused for now, may be used in later security hardening work
570 logic unused_ispr_rd_insn;
571 assign unused_ispr_rd_insn = insn_dec_shared_i.ispr_rd_insn;
572
Philipp Wagner31441082020-07-14 11:17:21 +0100573endmodule