blob: 8df4811706ac7517b97923fcef08c249697365af [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
Greg Chadwickd3154ec2020-09-24 12:03:23 +010024 input logic start_i, // start the processing at start_addr_i
25 output logic done_o, // processing done, signaled by ECALL or error occurring
26
27 output err_code_e err_code_o, // valid when done_o is asserted
28
Philipp Wagner31441082020-07-14 11:17:21 +010029 input logic [ImemAddrWidth-1:0] start_addr_i,
30
31 // Next instruction selection (to instruction fetch)
32 output logic insn_fetch_req_valid_o,
33 output logic [ImemAddrWidth-1:0] insn_fetch_req_addr_o,
Greg Chadwickd3154ec2020-09-24 12:03:23 +010034 // Error from fetch requested last cycle
35 input logic insn_fetch_err_i,
Philipp Wagner31441082020-07-14 11:17:21 +010036
37 // Fetched/decoded instruction
38 input logic insn_valid_i,
Greg Chadwickd3154ec2020-09-24 12:03:23 +010039 input logic insn_illegal_i,
Philipp Wagner31441082020-07-14 11:17:21 +010040 input logic [ImemAddrWidth-1:0] insn_addr_i,
Philipp Wagner31441082020-07-14 11:17:21 +010041
42 // Decoded instruction data, matching the "Decoding" section of the specification.
43 input insn_dec_base_t insn_dec_base_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010044 input insn_dec_bignum_t insn_dec_bignum_i,
45 input insn_dec_shared_t insn_dec_shared_i,
Philipp Wagner31441082020-07-14 11:17:21 +010046
47 // Base register file
48 output logic [4:0] rf_base_wr_addr_o,
49 output logic rf_base_wr_en_o,
50 output logic [31:0] rf_base_wr_data_o,
51
52 output logic [4:0] rf_base_rd_addr_a_o,
Greg Chadwick9afeb5e2020-10-15 17:58:55 +010053 output logic rf_base_rd_en_a_o,
Philipp Wagner31441082020-07-14 11:17:21 +010054 input logic [31:0] rf_base_rd_data_a_i,
Philipp Wagner31441082020-07-14 11:17:21 +010055 output logic [4:0] rf_base_rd_addr_b_o,
Greg Chadwick9afeb5e2020-10-15 17:58:55 +010056 output logic rf_base_rd_en_b_o,
Philipp Wagner31441082020-07-14 11:17:21 +010057 input logic [31:0] rf_base_rd_data_b_i,
58
Greg Chadwickd3154ec2020-09-24 12:03:23 +010059 input logic rf_base_call_stack_err_i,
60
Greg Chadwickf7863442020-09-14 18:11:33 +010061 // Bignum register file (WDRs)
62 output logic [4:0] rf_bignum_wr_addr_o,
63 output logic [1:0] rf_bignum_wr_en_o,
64 output logic [WLEN-1:0] rf_bignum_wr_data_o,
65
66 output logic [4:0] rf_bignum_rd_addr_a_o,
67 input logic [WLEN-1:0] rf_bignum_rd_data_a_i,
68
69 output logic [4:0] rf_bignum_rd_addr_b_o,
70 input logic [WLEN-1:0] rf_bignum_rd_data_b_i,
71
Philipp Wagner31441082020-07-14 11:17:21 +010072 // Execution units
Greg Chadwickf7863442020-09-14 18:11:33 +010073
74 // Base ALU
Greg Chadwick9791eed2020-07-22 18:08:28 +010075 output alu_base_operation_t alu_base_operation_o,
76 output alu_base_comparison_t alu_base_comparison_o,
77 input logic [31:0] alu_base_operation_result_i,
Greg Chadwickc8cd4352020-08-14 16:45:23 +010078 input logic alu_base_comparison_result_i,
79
Greg Chadwickf7863442020-09-14 18:11:33 +010080 // Bignum ALU
81 output alu_bignum_operation_t alu_bignum_operation_o,
82 input logic [WLEN-1:0] alu_bignum_operation_result_i,
83
Greg Chadwick94786452020-10-28 18:19:51 +000084 // Bignum MAC
85 output mac_bignum_operation_t mac_bignum_operation_o,
86 input logic [WLEN-1:0] mac_bignum_operation_result_i,
87 output logic mac_bignum_en_o,
88
Greg Chadwickf7863442020-09-14 18:11:33 +010089 // LSU
Greg Chadwickc8cd4352020-08-14 16:45:23 +010090 output logic lsu_load_req_o,
91 output logic lsu_store_req_o,
92 output insn_subset_e lsu_req_subset_o,
93 output logic [DmemAddrWidth-1:0] lsu_addr_o,
94
95 output logic [31:0] lsu_base_wdata_o,
96 output logic [WLEN-1:0] lsu_bignum_wdata_o,
97
98 input logic [31:0] lsu_base_rdata_i,
99 input logic [WLEN-1:0] lsu_bignum_rdata_i,
Rupert Swarbrick40cd9142020-12-02 11:02:17 +0000100 input logic lsu_rdata_err_i,
Greg Chadwickf7863442020-09-14 18:11:33 +0100101
102 // Internal Special-Purpose Registers (ISPRs)
103 output ispr_e ispr_addr_o,
104 output logic [31:0] ispr_base_wdata_o,
105 output logic [BaseWordsPerWLEN-1:0] ispr_base_wr_en_o,
106 output logic [WLEN-1:0] ispr_bignum_wdata_o,
107 output logic ispr_bignum_wr_en_o,
108 input logic [WLEN-1:0] ispr_rdata_i
Philipp Wagner31441082020-07-14 11:17:21 +0100109);
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100110 otbn_state_e state_q, state_d, state_raw;
111
112 logic err;
113 logic done_complete;
114
115 logic insn_fetch_req_valid_raw;
Greg Chadwick28836af2020-07-23 14:35:52 +0100116
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100117 logic stall;
118 logic mem_stall;
Greg Chadwick51f36232020-09-02 15:37:23 +0100119 logic branch_taken;
120 logic [ImemAddrWidth-1:0] branch_target;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100121 logic branch_target_overflow;
Greg Chadwick51f36232020-09-02 15:37:23 +0100122 logic [ImemAddrWidth-1:0] next_insn_addr;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100123 logic next_insn_addr_overflow;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100124
Greg Chadwickf7863442020-09-14 18:11:33 +0100125 csr_e csr_addr;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000126 logic [31:0] csr_rdata_raw;
Greg Chadwickf7863442020-09-14 18:11:33 +0100127 logic [31:0] csr_rdata;
128 logic [BaseWordsPerWLEN-1:0] csr_rdata_mux [32];
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000129 logic [31:0] csr_wdata_raw;
Greg Chadwickf7863442020-09-14 18:11:33 +0100130 logic [31:0] csr_wdata;
131
132 wsr_e wsr_addr;
133 logic [WLEN-1:0] wsr_wdata;
134
135 ispr_e ispr_addr_base;
136 logic [$clog2(BaseWordsPerWLEN)-1:0] ispr_word_addr_base;
137 logic [BaseWordsPerWLEN-1:0] ispr_word_sel_base;
138
139 ispr_e ispr_addr_bignum;
140
141 logic ispr_wr_insn;
142
Greg Chadwickae8e6452020-10-02 12:04:15 +0100143 // Computed increments for indirect register index and memory address in BN.LID/BN.SID/BN.MOVR
144 // instructions.
145 logic [4:0] rf_base_rd_data_a_inc;
146 logic [4:0] rf_base_rd_data_b_inc;
147 logic [DmemAddrWidth-1:0] rf_base_rd_data_a_wlen_word_inc;
148
149 // Output of mux taking the above increments as inputs and choosing one to write back to base
150 // register file with appropriate zero extension and padding to give a 32-bit result.
151 logic [31:0] increment_out;
152
Greg Chadwick53c95862020-10-14 17:58:38 +0100153 // Loop control, used to start a new loop
154 logic loop_start;
155 logic [11:0] loop_bodysize;
156 logic [31:0] loop_iterations;
157
158 // Loop generated jumps. The loop controller asks to jump when execution reaches the end of a loop
159 // body that hasn't completed all of its iterations.
160 logic loop_jump;
161 logic [ImemAddrWidth-1:0] loop_jump_addr;
162
Greg Chadwick94786452020-10-28 18:19:51 +0000163 logic [WLEN-1:0] mac_bignum_rf_wr_data;
164
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100165 logic csr_illegal_addr, wsr_illegal_addr, ispr_illegal_addr;
166 logic imem_addr_err, loop_err, ispr_err;
167 logic dmem_addr_err, dmem_addr_unaligned_base, dmem_addr_unaligned_bignum, dmem_addr_overflow;
168
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100169 // Stall a cycle on loads to allow load data writeback to happen the following cycle. Stall not
170 // required on stores as there is no response to deal with.
171 // TODO: Possibility of error response on store? Probably still don't need to stall in that case
172 // just ensure incoming store error stops anything else happening.
173 assign mem_stall = lsu_load_req_o;
174
175 assign stall = mem_stall;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100176
177 // OTBN is done (raising the 'done' interrupt) either when it executes an ecall or an error
178 // occurs. The ecall triggered done is factored out as `done_complete` to avoid logic loops in the
179 // error handling logic.
180 assign done_complete = (insn_valid_i && insn_dec_shared_i.ecall_insn);
181 assign done_o = done_complete | err;
Philipp Wagner31441082020-07-14 11:17:21 +0100182
Greg Chadwick51f36232020-09-02 15:37:23 +0100183 // Branch taken when there is a valid branch instruction and comparison passes or a valid jump
184 // instruction (which is always taken)
Philipp Wagnerdc946522020-12-03 10:52:58 +0000185 assign branch_taken = insn_valid_i &
186 ((insn_dec_shared_i.branch_insn & alu_base_comparison_result_i) |
187 insn_dec_shared_i.jump_insn);
Greg Chadwick51f36232020-09-02 15:37:23 +0100188 // Branch target computed by base ALU (PC + imm)
Greg Chadwick51f36232020-09-02 15:37:23 +0100189 assign branch_target = alu_base_operation_result_i[ImemAddrWidth-1:0];
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100190 assign branch_target_overflow = |alu_base_operation_result_i[31:ImemAddrWidth];
Greg Chadwick51f36232020-09-02 15:37:23 +0100191
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100192 assign {next_insn_addr_overflow, next_insn_addr} = insn_addr_i + 'd4;
Greg Chadwick51f36232020-09-02 15:37:23 +0100193
Philipp Wagner31441082020-07-14 11:17:21 +0100194 always_comb begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100195 // `state_raw` and `insn_fetch_req_valid_raw` are the values of `state_d` and
196 // `insn_fetch_req_valid_o` before any errors are considered.
197 state_raw = state_q;
198 insn_fetch_req_valid_raw = 1'b0;
199 insn_fetch_req_addr_o = start_addr_i;
Greg Chadwick28836af2020-07-23 14:35:52 +0100200
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100201 // TODO: Harden state machine
Philipp Wagner31441082020-07-14 11:17:21 +0100202 // TODO: Jumps/branches
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100203 unique case (state_q)
204 OtbnStateHalt: begin
205 if (start_i) begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100206 state_raw = OtbnStateRun;
207 insn_fetch_req_addr_o = start_addr_i;
208 insn_fetch_req_valid_raw = 1'b1;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100209 end
210 end
211 OtbnStateRun: begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100212 insn_fetch_req_valid_raw = 1'b1;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100213
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100214 if (done_complete) begin
215 state_raw = OtbnStateHalt;
216 insn_fetch_req_valid_raw = 1'b0;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100217 end else begin
218 // When stalling refetch the same instruction to keep decode inputs constant
219 if (stall) begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100220 state_raw = OtbnStateStall;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100221 insn_fetch_req_addr_o = insn_addr_i;
222 end else begin
Greg Chadwick51f36232020-09-02 15:37:23 +0100223 if (branch_taken) begin
224 insn_fetch_req_addr_o = branch_target;
Greg Chadwick53c95862020-10-14 17:58:38 +0100225 end else if (loop_jump) begin
226 insn_fetch_req_addr_o = loop_jump_addr;
Greg Chadwick51f36232020-09-02 15:37:23 +0100227 end else begin
228 insn_fetch_req_addr_o = next_insn_addr;
229 end
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100230 end
231 end
232 end
233 OtbnStateStall: begin
234 // Only ever stall for a single cycle
235 // TODO: Any more than one cycle stall cases?
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100236 insn_fetch_req_valid_raw = 1'b1;
237 insn_fetch_req_addr_o = next_insn_addr;
238 state_raw = OtbnStateRun;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100239 end
240 default: ;
241 endcase
Philipp Wagner31441082020-07-14 11:17:21 +0100242 end
243
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100244 // On any error immediately halt and suppress any Imem request.
245 assign state_d = err ? OtbnStateHalt : state_raw;
246 assign insn_fetch_req_valid_o = err ? 1'b0 : insn_fetch_req_valid_raw;
247
248 // Determine if there are any errors related to the Imem fetch address.
249 always_comb begin
250 imem_addr_err = 1'b0;
251
252 if (insn_fetch_req_valid_raw) begin
253 if (|insn_fetch_req_addr_o[1:0]) begin
254 // Imem address is unaligned
255 imem_addr_err = 1'b1;
256 end else if (branch_taken) begin
257 imem_addr_err = branch_target_overflow;
258 end else begin
259 imem_addr_err = next_insn_addr_overflow;
260 end
261 end
262 end
263
264 // Err signal and code generation and prioritisation
265 always_comb begin
266 err = 1'b1;
267 err_code_o = ErrCodeNoError;
268
269 if (insn_fetch_err_i) begin
270 err_code_o = ErrCodeFatalImem;
271 end else if (lsu_rdata_err_i) begin
272 err_code_o = ErrCodeFatalDmem;
273 end else if (insn_illegal_i) begin
274 err_code_o = ErrCodeIllegalInsn;
275 end else if (ispr_err) begin
276 err_code_o = ErrCodeIllegalInsn;
277 end else if (dmem_addr_err) begin
278 err_code_o = ErrCodeBadDataAddr;
279 end else if (loop_err) begin
280 err_code_o = ErrCodeLoop;
281 end else if (rf_base_call_stack_err_i) begin
282 err_code_o = ErrCodeCallStack;
283 end else if (imem_addr_err) begin
284 err_code_o = ErrCodeBadInsnAddr;
285 end else begin
286 err = 1'b0;
287 err_code_o = ErrCodeNoError;
288 end
289 end
290
291 `ASSERT(ErrCodeOnErr, err |-> err_code_o != ErrCodeNoError)
292
Philipp Wagnerdc946522020-12-03 10:52:58 +0000293 `ASSERT(ControllerStateValid, state_q inside {OtbnStateHalt, OtbnStateRun, OtbnStateStall})
Greg Chadwick51f36232020-09-02 15:37:23 +0100294 // Branch only takes effect in OtbnStateRun so must not go into stall state for branch
295 // instructions.
Philipp Wagnerdc946522020-12-03 10:52:58 +0000296 `ASSERT(NoStallOnBranch,
297 insn_valid_i & insn_dec_shared_i.branch_insn |-> state_q != OtbnStateStall)
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100298
Greg Chadwick28836af2020-07-23 14:35:52 +0100299 always_ff @(posedge clk_i or negedge rst_ni) begin
300 if (!rst_ni) begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100301 state_q <= OtbnStateHalt;
Greg Chadwick28836af2020-07-23 14:35:52 +0100302 end else begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100303 state_q <= state_d;
Greg Chadwick28836af2020-07-23 14:35:52 +0100304 end
305 end
306
Greg Chadwick53c95862020-10-14 17:58:38 +0100307 otbn_loop_controller #(
308 .ImemAddrWidth(ImemAddrWidth)
309 ) u_otbn_loop_controller (
310 .clk_i,
311 .rst_ni,
312
313 .insn_addr_i,
314 .next_insn_addr_i (next_insn_addr),
315
316 .loop_start_i (loop_start),
317 .loop_bodysize_i (loop_bodysize),
318 .loop_iterations_i (loop_iterations),
319
320 .loop_jump_o (loop_jump),
321 .loop_jump_addr_o (loop_jump_addr),
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100322 .loop_err_o (loop_err),
Greg Chadwick53c95862020-10-14 17:58:38 +0100323 );
324
325 assign loop_start = insn_valid_i & insn_dec_shared_i.loop_insn;
326 assign loop_bodysize = insn_dec_base_i.loop_bodysize;
327 assign loop_iterations = insn_dec_base_i.loop_immediate ? insn_dec_base_i.i : rf_base_rd_data_a_i;
328
Greg Chadwickae8e6452020-10-02 12:04:15 +0100329 // Compute increments which can be optionally applied to indirect register accesses and memory
330 // addresses in BN.LID/BN.SID/BN.MOVR instructions.
331 assign rf_base_rd_data_a_inc = rf_base_rd_data_a_i[4:0] + 1'b1;
332 assign rf_base_rd_data_b_inc = rf_base_rd_data_b_i[4:0] + 1'b1;
333 assign rf_base_rd_data_a_wlen_word_inc = {rf_base_rd_data_a_i[DmemAddrWidth-1:5] + 1'b1, 5'b0};
334
335 // Choose increment to write back to base register file, only one increment can be written as
336 // there is only one write port. Note that where an instruction is incrementing the indirect
337 // reference to its destination register (insn_dec_bignum_i.d_inc) that reference is read on the
338 // B read port so the B increment is written back.
339 always_comb begin
340 unique case (1'b1)
341 insn_dec_bignum_i.a_inc: begin
342 increment_out = {27'b0, rf_base_rd_data_a_inc};
343 end
344 insn_dec_bignum_i.b_inc: begin
345 increment_out = {27'b0, rf_base_rd_data_b_inc};
346 end
347 insn_dec_bignum_i.d_inc: begin
348 increment_out = {27'b0, rf_base_rd_data_b_inc};
349 end
350 insn_dec_bignum_i.a_wlen_word_inc: begin
351 increment_out = {{32-DmemAddrWidth{1'b0}}, rf_base_rd_data_a_wlen_word_inc};
352 end
Pirmin Vogele97cac02020-11-02 12:28:50 +0100353 default: begin
354 // Whenever increment_out is written back to the register file, exactly one of the
355 // increment selector signals is high. To prevent the automatic inference of latches in
356 // case nothing is written back (rf_wdata_sel != RfWdSelIncr) and to save logic, we choose
357 // a valid output as default.
358 increment_out = {27'b0, rf_base_rd_data_a_inc};
359 end
Greg Chadwickae8e6452020-10-02 12:04:15 +0100360 endcase
361 end
362
363 always_comb begin
364 rf_base_rd_addr_a_o = insn_dec_base_i.a;
Greg Chadwickef411792020-12-01 17:44:34 +0000365 rf_base_rd_en_a_o = insn_dec_base_i.rf_ren_a & insn_valid_i;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100366 rf_base_rd_addr_b_o = insn_dec_base_i.b;
Greg Chadwickef411792020-12-01 17:44:34 +0000367 rf_base_rd_en_b_o = insn_dec_base_i.rf_ren_b & insn_valid_i;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100368 rf_base_wr_addr_o = insn_dec_base_i.d;
369
370 if (insn_dec_shared_i.subset == InsnSubsetBignum) begin
371 unique case (1'b1)
372 insn_dec_bignum_i.a_inc,
373 insn_dec_bignum_i.a_wlen_word_inc: begin
374 rf_base_wr_addr_o = insn_dec_base_i.a;
375 end
376
377 insn_dec_bignum_i.b_inc,
378 insn_dec_bignum_i.d_inc: begin
379 rf_base_wr_addr_o = insn_dec_base_i.b;
380 end
381 default: ;
382 endcase
383 end
384 end
Philipp Wagner31441082020-07-14 11:17:21 +0100385
386 // Base ALU Operand A MUX
387 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100388 unique case (insn_dec_base_i.op_a_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100389 OpASelRegister: alu_base_operation_o.operand_a = rf_base_rd_data_a_i;
390 OpASelZero: alu_base_operation_o.operand_a = '0;
391 OpASelCurrPc: alu_base_operation_o.operand_a = {{(32 - ImemAddrWidth){1'b0}}, insn_addr_i};
392 default: alu_base_operation_o.operand_a = rf_base_rd_data_a_i;
Philipp Wagner31441082020-07-14 11:17:21 +0100393 endcase
394 end
395
396 // Base ALU Operand B MUX
397 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100398 unique case (insn_dec_base_i.op_b_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100399 OpBSelRegister: alu_base_operation_o.operand_b = rf_base_rd_data_b_i;
400 OpBSelImmediate: alu_base_operation_o.operand_b = insn_dec_base_i.i;
401 default: alu_base_operation_o.operand_b = rf_base_rd_data_b_i;
Philipp Wagner31441082020-07-14 11:17:21 +0100402 endcase
403 end
404
Greg Chadwicke177f172020-09-09 14:46:03 +0100405 assign alu_base_operation_o.op = insn_dec_base_i.alu_op;
Philipp Wagner31441082020-07-14 11:17:21 +0100406
Greg Chadwick9791eed2020-07-22 18:08:28 +0100407 assign alu_base_comparison_o.operand_a = rf_base_rd_data_a_i;
408 assign alu_base_comparison_o.operand_b = rf_base_rd_data_b_i;
Greg Chadwicke177f172020-09-09 14:46:03 +0100409 assign alu_base_comparison_o.op = insn_dec_base_i.comparison_op;
Greg Chadwick9791eed2020-07-22 18:08:28 +0100410
Philipp Wagner31441082020-07-14 11:17:21 +0100411 // Register file write MUX
Greg Chadwick121847e2020-09-02 15:31:28 +0100412 // Suppress write for loads when controller isn't in stall state as load data for writeback is
413 // only available in the stall state.
Greg Chadwickf6f35962020-11-02 17:32:08 +0000414 assign rf_base_wr_en_o = insn_valid_i & insn_dec_base_i.rf_we &
Greg Chadwickcf048242020-10-02 15:28:42 +0100415 ~(insn_dec_shared_i.ld_insn & (state_q != OtbnStateStall));
Philipp Wagner31441082020-07-14 11:17:21 +0100416
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100417 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100418 unique case (insn_dec_base_i.rf_wdata_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100419 RfWdSelEx: rf_base_wr_data_o = alu_base_operation_result_i;
420 RfWdSelLsu: rf_base_wr_data_o = lsu_base_rdata_i;
421 RfWdSelNextPc: rf_base_wr_data_o = {{(32-ImemAddrWidth){1'b0}}, next_insn_addr};
422 RfWdSelIspr: rf_base_wr_data_o = csr_rdata;
423 RfWdSelIncr: rf_base_wr_data_o = increment_out;
424 default: rf_base_wr_data_o = alu_base_operation_result_i;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100425 endcase
426 end
427
Greg Chadwickae8e6452020-10-02 12:04:15 +0100428 assign rf_bignum_rd_addr_a_o = insn_dec_bignum_i.rf_a_indirect ? rf_base_rd_data_a_i[4:0] :
429 insn_dec_bignum_i.a;
430
431 assign rf_bignum_rd_addr_b_o = insn_dec_bignum_i.rf_b_indirect ? rf_base_rd_data_b_i[4:0] :
432 insn_dec_bignum_i.b;
Greg Chadwickf7863442020-09-14 18:11:33 +0100433
434 assign alu_bignum_operation_o.operand_a = rf_bignum_rd_data_a_i;
435
436 // Base ALU Operand B MUX
437 always_comb begin
Greg Chadwick94786452020-10-28 18:19:51 +0000438 unique case (insn_dec_bignum_i.alu_op_b_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100439 OpBSelRegister: alu_bignum_operation_o.operand_b = rf_bignum_rd_data_b_i;
440 OpBSelImmediate: alu_bignum_operation_o.operand_b = insn_dec_bignum_i.i;
441 default: alu_bignum_operation_o.operand_b = rf_bignum_rd_data_b_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100442 endcase
443 end
444
445 assign alu_bignum_operation_o.op = insn_dec_bignum_i.alu_op;
Greg Chadwick94786452020-10-28 18:19:51 +0000446 assign alu_bignum_operation_o.shift_right = insn_dec_bignum_i.alu_shift_right;
447 assign alu_bignum_operation_o.shift_amt = insn_dec_bignum_i.alu_shift_amt;
448 assign alu_bignum_operation_o.flag_group = insn_dec_bignum_i.alu_flag_group;
449 assign alu_bignum_operation_o.sel_flag = insn_dec_bignum_i.alu_sel_flag;
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000450 assign alu_bignum_operation_o.alu_flag_en = insn_dec_bignum_i.alu_flag_en;
451 assign alu_bignum_operation_o.mac_flag_en = insn_dec_bignum_i.mac_flag_en;
Greg Chadwickf7863442020-09-14 18:11:33 +0100452
Greg Chadwick94786452020-10-28 18:19:51 +0000453 assign mac_bignum_operation_o.operand_a = rf_bignum_rd_data_a_i;
454 assign mac_bignum_operation_o.operand_b = rf_bignum_rd_data_b_i;
455 assign mac_bignum_operation_o.operand_a_qw_sel = insn_dec_bignum_i.mac_op_a_qw_sel;
456 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 +0000457 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 +0000458 assign mac_bignum_operation_o.pre_acc_shift_imm = insn_dec_bignum_i.mac_pre_acc_shift;
459 assign mac_bignum_operation_o.zero_acc = insn_dec_bignum_i.mac_zero_acc;
460 assign mac_bignum_operation_o.shift_acc = insn_dec_bignum_i.mac_shift_out;
461
462 assign mac_bignum_en_o = insn_dec_bignum_i.mac_en & insn_valid_i;
463
464
465 // Bignum Register file write control
466
467 always_comb begin
468 // By default write nothing
469 rf_bignum_wr_en_o = 2'b00;
470
471 // Only write if enabled
Greg Chadwickf6f35962020-11-02 17:32:08 +0000472 if (insn_valid_i && insn_dec_bignum_i.rf_we) begin
Greg Chadwick94786452020-10-28 18:19:51 +0000473 if (insn_dec_bignum_i.mac_en && insn_dec_bignum_i.mac_shift_out) begin
474 // Special handling for BN.MULQACC.SO, only enable upper or lower half depending on
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000475 // mac_wr_hw_sel_upper.
476 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 +0000477 end else if (insn_dec_shared_i.ld_insn) begin
478 // Special handling for BN.LID. Load data is requested in the first cycle of the instruction
479 // (where state_q == OtbnStateRun) and is available in the second cycle following the
480 // request (where state_q == OtbnStateStall), so only enable writes for BN.LID when in
481 // OtbnStateStall.
482 if (state_q == OtbnStateStall) begin
483 rf_bignum_wr_en_o = 2'b11;
484 end
485 end else begin
486 // For everything else write both halves immediately.
487 rf_bignum_wr_en_o = 2'b11;
488 end
489 end
490 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100491
Greg Chadwickae8e6452020-10-02 12:04:15 +0100492 assign rf_bignum_wr_addr_o = insn_dec_bignum_i.rf_d_indirect ? rf_base_rd_data_b_i[4:0] :
493 insn_dec_bignum_i.d;
Greg Chadwickf7863442020-09-14 18:11:33 +0100494
Greg Chadwick94786452020-10-28 18:19:51 +0000495 // 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 +0000496 // half of a desintation register specified by the instruction (mac_wr_hw_sel_upper). The bottom
497 // half of the MAC result must be placed in the appropriate half of the write data (the RF only
498 // accepts write data for the top half in the top half of the write data input). Otherwise
499 // (shift-out to bottom half and all other BN.MULQACC instructions) simply pass the MAC result
500 // through unchanged as write data.
Greg Chadwick94786452020-10-28 18:19:51 +0000501 assign mac_bignum_rf_wr_data[WLEN-1:WLEN/2] =
Philipp Wagnerdc946522020-12-03 10:52:58 +0000502 insn_dec_bignum_i.mac_wr_hw_sel_upper &&
503 insn_dec_bignum_i.mac_shift_out ? mac_bignum_operation_result_i[WLEN/2-1:0] :
504 mac_bignum_operation_result_i[WLEN-1:WLEN/2];
Greg Chadwick94786452020-10-28 18:19:51 +0000505
506 assign mac_bignum_rf_wr_data[WLEN/2-1:0] = mac_bignum_operation_result_i[WLEN/2-1:0];
507
Greg Chadwickf7863442020-09-14 18:11:33 +0100508 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100509 unique case (insn_dec_bignum_i.rf_wdata_sel)
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100510 RfWdSelEx: rf_bignum_wr_data_o = alu_bignum_operation_result_i;
511 RfWdSelLsu: rf_bignum_wr_data_o = lsu_bignum_rdata_i;
512 RfWdSelIspr: rf_bignum_wr_data_o = ispr_rdata_i;
Greg Chadwick94786452020-10-28 18:19:51 +0000513 RfWdSelMac: rf_bignum_wr_data_o = mac_bignum_rf_wr_data;
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100514 default: rf_bignum_wr_data_o = alu_bignum_operation_result_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100515 endcase
516 end
517
518 // CSR/WSR/ISPR handling
519 // ISPRs (Internal Special Purpose Registers) are the internal registers. CSRs and WSRs are the
520 // ISA visible versions of those registers in the base and bignum ISAs respectively.
521
522 assign csr_addr = csr_e'(insn_dec_base_i.i[11:0]);
523
524 always_comb begin
525 ispr_addr_base = IsprMod;
526 ispr_word_addr_base = '0;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100527 csr_illegal_addr = 1'b0;
Greg Chadwickf7863442020-09-14 18:11:33 +0100528
529 unique case (csr_addr)
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000530 CsrFlags, CsrFg0, CsrFg1 : begin
Greg Chadwickf7863442020-09-14 18:11:33 +0100531 ispr_addr_base = IsprFlags;
532 ispr_word_addr_base = '0;
533 end
534 CsrMod0,CsrMod1,CsrMod2,CsrMod3,CsrMod4,CsrMod5,CsrMod6,CsrMod7: begin
535 ispr_addr_base = IsprMod;
536 ispr_word_addr_base = csr_addr[2:0];
537 end
538 CsrRnd: begin
539 ispr_addr_base = IsprRnd;
540 ispr_word_addr_base = '0;
541 end
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100542 default: csr_illegal_addr = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100543 endcase
544 end
545
546 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_ispr_word_sel_base
547 assign ispr_word_sel_base[i_word] = ispr_word_addr_base == i_word;
548 end
549
550 for (genvar i_bit = 0; i_bit < 32; i_bit++) begin : g_csr_rdata_mux
551 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_csr_rdata_mux_inner
Philipp Wagnerdc946522020-12-03 10:52:58 +0000552 assign csr_rdata_mux[i_bit][i_word] =
553 ispr_rdata_i[i_word*32 + i_bit] & ispr_word_sel_base[i_word];
Greg Chadwickf7863442020-09-14 18:11:33 +0100554 end
555
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000556 assign csr_rdata_raw[i_bit] = |csr_rdata_mux[i_bit];
Greg Chadwickf7863442020-09-14 18:11:33 +0100557 end
558
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000559 // Specialised read data handling for CSR reads where raw read data needs modification.
560 always_comb begin
561 csr_rdata = csr_rdata_raw;
562
563 unique case(csr_addr)
564 // For FG0/FG1 select out appropriate bits from FLAGS ISPR and pad the rest with zeros.
565 CsrFg0: csr_rdata = {28'b0, csr_rdata_raw[3:0]};
566 CsrFg1: csr_rdata = {28'b0, csr_rdata_raw[7:4]};
567 default: ;
568 endcase
569 end
570
Philipp Wagnerdc946522020-12-03 10:52:58 +0000571 assign csr_wdata_raw = insn_dec_shared_i.ispr_rs_insn ? csr_rdata | rf_base_rd_data_a_i :
572 rf_base_rd_data_a_i;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000573
574 // Specialised write data handling for CSR writes where raw write data needs modification.
575 always_comb begin
576 csr_wdata = csr_wdata_raw;
577
578 unique case(csr_addr)
579 // For FG0/FG1 only modify relevant part of FLAGS ISPR.
580 CsrFg0: csr_wdata = {24'b0, csr_rdata_raw[7:4], csr_wdata_raw[3:0]};
581 CsrFg1: csr_wdata = {24'b0, csr_wdata_raw[3:0], csr_rdata_raw[3:0]};
582 default: ;
583 endcase
584 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100585
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000586 // ISPR RS (read and set) must not be combined with ISPR RD or WR (read or write). ISPR RD and
587 // WR (read and write) is allowed.
588 `ASSERT(NoIsprRorWAndRs, insn_valid_i |-> ~(insn_dec_shared_i.ispr_rs_insn &
589 (insn_dec_shared_i.ispr_rd_insn |
590 insn_dec_shared_i.ispr_wr_insn)))
591
592
Greg Chadwickf7863442020-09-14 18:11:33 +0100593 assign wsr_addr = wsr_e'(insn_dec_bignum_i.i[WsrNumWidth-1:0]);
594
595 always_comb begin
596 ispr_addr_bignum = IsprMod;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100597 wsr_illegal_addr = 1'b0;
Greg Chadwickf7863442020-09-14 18:11:33 +0100598
599 unique case (wsr_addr)
600 WsrMod: ispr_addr_bignum = IsprMod;
601 WsrRnd: ispr_addr_bignum = IsprRnd;
602 WsrAcc: ispr_addr_bignum = IsprAcc;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100603 default: wsr_illegal_addr = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100604 endcase
605 end
606
Philipp Wagnerdc946522020-12-03 10:52:58 +0000607 assign wsr_wdata = insn_dec_shared_i.ispr_rs_insn ? ispr_rdata_i | rf_bignum_rd_data_a_i :
608 rf_bignum_rd_data_a_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100609
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100610 assign ispr_illegal_addr = insn_dec_shared_i.subset == InsnSubsetBase ? csr_illegal_addr : wsr_illegal_addr;
611
612 assign ispr_err = ispr_illegal_addr & insn_valid_i & (insn_dec_shared_i.ispr_rd_insn |
613 insn_dec_shared_i.ispr_wr_insn |
614 insn_dec_shared_i.ispr_rs_insn);
615
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000616 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 +0100617
Philipp Wagnerdc946522020-12-03 10:52:58 +0000618 assign ispr_addr_o = insn_dec_shared_i.subset == InsnSubsetBase ? ispr_addr_base :
619 ispr_addr_bignum;
Greg Chadwickf7863442020-09-14 18:11:33 +0100620 assign ispr_base_wdata_o = csr_wdata;
Greg Chadwickf6f35962020-11-02 17:32:08 +0000621 assign ispr_base_wr_en_o =
622 {BaseWordsPerWLEN{(insn_dec_shared_i.subset == InsnSubsetBase) & ispr_wr_insn & insn_valid_i}}
623 & ispr_word_sel_base;
624
Greg Chadwickf7863442020-09-14 18:11:33 +0100625 assign ispr_bignum_wdata_o = wsr_wdata;
Greg Chadwickf6f35962020-11-02 17:32:08 +0000626 assign ispr_bignum_wr_en_o = (insn_dec_shared_i.subset == InsnSubsetBignum) & ispr_wr_insn
627 & insn_valid_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100628
Greg Chadwickf7863442020-09-14 18:11:33 +0100629 assign lsu_load_req_o = insn_valid_i & insn_dec_shared_i.ld_insn & (state_q == OtbnStateRun);
630 assign lsu_store_req_o = insn_valid_i & insn_dec_shared_i.st_insn & (state_q == OtbnStateRun);
631 assign lsu_req_subset_o = insn_dec_shared_i.subset;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100632
Greg Chadwickae8e6452020-10-02 12:04:15 +0100633 assign lsu_addr_o = alu_base_operation_result_i[DmemAddrWidth-1:0];
634 assign lsu_base_wdata_o = rf_base_rd_data_b_i;
635 assign lsu_bignum_wdata_o = rf_bignum_rd_data_b_i;
Greg Chadwick6ab8d952020-10-30 12:13:34 +0000636
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100637 assign dmem_addr_unaligned_bignum = (lsu_req_subset_o == InsnSubsetBignum) & (|lsu_addr_o[$clog2(WLEN/8)-1:0]);
638 assign dmem_addr_unaligned_base = (lsu_req_subset_o == InsnSubsetBase) & (|lsu_addr_o[1:0]);
639 assign dmem_addr_overflow = |alu_base_operation_result_i[31:DmemAddrWidth];
640
641 assign dmem_addr_err = (lsu_load_req_o | lsu_store_req_o) & (dmem_addr_overflow |
642 dmem_addr_unaligned_bignum |
643 dmem_addr_unaligned_base);
644
Greg Chadwick6ab8d952020-10-30 12:13:34 +0000645 // RF Read enables for bignum RF are unused for now. Future security hardening work may make use
646 // of them.
647 logic unused_rf_ren_a_bignum;
648 logic unused_rf_ren_b_bignum;
649
650 assign unused_rf_ren_a_bignum = insn_dec_bignum_i.rf_ren_a;
651 assign unused_rf_ren_b_bignum = insn_dec_bignum_i.rf_ren_b;
Philipp Wagner31441082020-07-14 11:17:21 +0100652endmodule