blob: 157e7c6002bdc7ea1151f6056f808b3d020f5e3a [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
Greg Chadwick5ce1cb72021-01-13 14:20:48 +000027 output err_bits_t err_bits_o, // valid when done_o is asserted
Greg Chadwickd3154ec2020-09-24 12:03:23 +010028
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
Philipp Wagner56a64bd2021-05-08 14:31:24 +010042 // Decoded instruction data
Philipp Wagner31441082020-07-14 11:17:21 +010043 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
Greg Chadwickee060bd2021-05-15 17:33:22 +010048 output logic [4:0] rf_base_wr_addr_o,
49 output logic rf_base_wr_en_o,
50 output logic rf_base_wr_commit_o,
51 output logic [31:0] rf_base_wr_data_no_intg_o,
52 output logic [BaseIntgWidth-1:0] rf_base_wr_data_intg_o,
53 output logic rf_base_wr_data_intg_sel_o,
Philipp Wagner31441082020-07-14 11:17:21 +010054
Greg Chadwick009d9ee2021-04-26 16:25:51 +010055 output logic [4:0] rf_base_rd_addr_a_o,
56 output logic rf_base_rd_en_a_o,
57 input logic [BaseIntgWidth-1:0] rf_base_rd_data_a_intg_i,
58 output logic [4:0] rf_base_rd_addr_b_o,
59 output logic rf_base_rd_en_b_o,
60 input logic [BaseIntgWidth-1:0] rf_base_rd_data_b_intg_i,
61 output logic rf_base_rd_commit_o,
Philipp Wagner31441082020-07-14 11:17:21 +010062
Greg Chadwickd3154ec2020-09-24 12:03:23 +010063 input logic rf_base_call_stack_err_i,
Greg Chadwick009d9ee2021-04-26 16:25:51 +010064 input logic rf_base_rd_data_err_i,
Greg Chadwickd3154ec2020-09-24 12:03:23 +010065
Greg Chadwickf7863442020-09-14 18:11:33 +010066 // Bignum register file (WDRs)
Greg Chadwick009d9ee2021-04-26 16:25:51 +010067 output logic [4:0] rf_bignum_wr_addr_o,
68 output logic [1:0] rf_bignum_wr_en_o,
69 output logic [WLEN-1:0] rf_bignum_wr_data_no_intg_o,
70 output logic [ExtWLEN-1:0] rf_bignum_wr_data_intg_o,
71 output logic rf_bignum_wr_data_intg_sel_o,
Greg Chadwickf7863442020-09-14 18:11:33 +010072
Greg Chadwick009d9ee2021-04-26 16:25:51 +010073 output logic [4:0] rf_bignum_rd_addr_a_o,
74 output logic rf_bignum_rd_en_a_o,
75 input logic [ExtWLEN-1:0] rf_bignum_rd_data_a_intg_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010076
Greg Chadwick009d9ee2021-04-26 16:25:51 +010077 output logic [4:0] rf_bignum_rd_addr_b_o,
78 output logic rf_bignum_rd_en_b_o,
79 input logic [ExtWLEN-1:0] rf_bignum_rd_data_b_intg_i,
80
81 input logic rf_bignum_rd_data_err_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010082
Philipp Wagner31441082020-07-14 11:17:21 +010083 // Execution units
Greg Chadwickf7863442020-09-14 18:11:33 +010084
85 // Base ALU
Greg Chadwick9791eed2020-07-22 18:08:28 +010086 output alu_base_operation_t alu_base_operation_o,
87 output alu_base_comparison_t alu_base_comparison_o,
88 input logic [31:0] alu_base_operation_result_i,
Greg Chadwickc8cd4352020-08-14 16:45:23 +010089 input logic alu_base_comparison_result_i,
90
Greg Chadwickf7863442020-09-14 18:11:33 +010091 // Bignum ALU
92 output alu_bignum_operation_t alu_bignum_operation_o,
93 input logic [WLEN-1:0] alu_bignum_operation_result_i,
Greg Chadwick009d9ee2021-04-26 16:25:51 +010094 input logic alu_bignum_selection_flag_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010095
Greg Chadwick94786452020-10-28 18:19:51 +000096 // Bignum MAC
97 output mac_bignum_operation_t mac_bignum_operation_o,
98 input logic [WLEN-1:0] mac_bignum_operation_result_i,
99 output logic mac_bignum_en_o,
100
Greg Chadwickf7863442020-09-14 18:11:33 +0100101 // LSU
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100102 output logic lsu_load_req_o,
103 output logic lsu_store_req_o,
104 output insn_subset_e lsu_req_subset_o,
105 output logic [DmemAddrWidth-1:0] lsu_addr_o,
106
Greg Chadwickee060bd2021-05-15 17:33:22 +0100107 output logic [BaseIntgWidth-1:0] lsu_base_wdata_o,
108 output logic [ExtWLEN-1:0] lsu_bignum_wdata_o,
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100109
Greg Chadwickee060bd2021-05-15 17:33:22 +0100110 input logic [BaseIntgWidth-1:0] lsu_base_rdata_i,
111 input logic [ExtWLEN-1:0] lsu_bignum_rdata_i,
Rupert Swarbrick40cd9142020-12-02 11:02:17 +0000112 input logic lsu_rdata_err_i,
Greg Chadwickf7863442020-09-14 18:11:33 +0100113
114 // Internal Special-Purpose Registers (ISPRs)
115 output ispr_e ispr_addr_o,
116 output logic [31:0] ispr_base_wdata_o,
117 output logic [BaseWordsPerWLEN-1:0] ispr_base_wr_en_o,
118 output logic [WLEN-1:0] ispr_bignum_wdata_o,
119 output logic ispr_bignum_wr_en_o,
Greg Chadwickb168ae92021-04-14 16:04:03 +0100120 input logic [WLEN-1:0] ispr_rdata_i,
121
122 output logic rnd_req_o,
123 output logic rnd_prefetch_req_o,
Vladimir Rozicb8db07a2021-05-24 14:15:04 +0100124 input logic rnd_valid_i,
125
Rupert Swarbrick13d50082021-07-13 14:14:03 +0100126 input logic state_reset_i,
Vladimir Rozicb8db07a2021-05-24 14:15:04 +0100127 output logic [31:0] insn_cnt_o
Philipp Wagner31441082020-07-14 11:17:21 +0100128);
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100129 otbn_state_e state_q, state_d, state_raw;
130
131 logic err;
132 logic done_complete;
133
134 logic insn_fetch_req_valid_raw;
Greg Chadwick28836af2020-07-23 14:35:52 +0100135
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100136 logic stall;
Greg Chadwickb168ae92021-04-14 16:04:03 +0100137 logic ispr_stall;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100138 logic mem_stall;
Rupert Swarbrickb2b784d2021-08-03 14:21:51 +0100139 logic jump_or_branch;
Greg Chadwick51f36232020-09-02 15:37:23 +0100140 logic branch_taken;
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000141 logic insn_executing;
Greg Chadwick51f36232020-09-02 15:37:23 +0100142 logic [ImemAddrWidth-1:0] branch_target;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100143 logic branch_target_overflow;
Rupert Swarbricke9ff47f2021-01-04 13:20:36 +0000144 logic [ImemAddrWidth:0] next_insn_addr_wide;
Greg Chadwick51f36232020-09-02 15:37:23 +0100145 logic [ImemAddrWidth-1:0] next_insn_addr;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100146
Greg Chadwickf7863442020-09-14 18:11:33 +0100147 csr_e csr_addr;
Philipp Wagner711d2262021-01-21 18:17:42 +0000148 logic [$clog2(BaseWordsPerWLEN)-1:0] csr_sub_addr;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000149 logic [31:0] csr_rdata_raw;
Greg Chadwickf7863442020-09-14 18:11:33 +0100150 logic [31:0] csr_rdata;
151 logic [BaseWordsPerWLEN-1:0] csr_rdata_mux [32];
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000152 logic [31:0] csr_wdata_raw;
Greg Chadwickf7863442020-09-14 18:11:33 +0100153 logic [31:0] csr_wdata;
154
155 wsr_e wsr_addr;
156 logic [WLEN-1:0] wsr_wdata;
157
158 ispr_e ispr_addr_base;
159 logic [$clog2(BaseWordsPerWLEN)-1:0] ispr_word_addr_base;
160 logic [BaseWordsPerWLEN-1:0] ispr_word_sel_base;
161
162 ispr_e ispr_addr_bignum;
163
Greg Chadwickb168ae92021-04-14 16:04:03 +0100164 logic ispr_wr_insn, ispr_rd_insn;
Rupert Swarbrick514348e2021-02-03 09:04:59 +0000165 logic ispr_wr_base_insn;
166 logic ispr_wr_bignum_insn;
Greg Chadwickf7863442020-09-14 18:11:33 +0100167
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000168 logic lsu_load_req_raw;
169 logic lsu_store_req_raw;
170
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100171 // Register read data with integrity stripped off
172 logic [31:0] rf_base_rd_data_a_no_intg;
173 logic [31:0] rf_base_rd_data_b_no_intg;
174 logic [WLEN-1:0] rf_bignum_rd_data_a_no_intg;
175 logic [WLEN-1:0] rf_bignum_rd_data_b_no_intg;
176
177 logic [ExtWLEN-1:0] selection_result;
178
Greg Chadwickae8e6452020-10-02 12:04:15 +0100179 // Computed increments for indirect register index and memory address in BN.LID/BN.SID/BN.MOVR
180 // instructions.
Greg Chadwick496fd342021-03-05 18:08:39 +0000181 logic [5:0] rf_base_rd_data_a_inc;
182 logic [5:0] rf_base_rd_data_b_inc;
Rupert Swarbrick9a4f47b2021-01-04 15:48:24 +0000183 logic [26:0] rf_base_rd_data_a_wlen_word_inc;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100184
185 // Output of mux taking the above increments as inputs and choosing one to write back to base
186 // register file with appropriate zero extension and padding to give a 32-bit result.
187 logic [31:0] increment_out;
188
Greg Chadwick53c95862020-10-14 17:58:38 +0100189 // Loop control, used to start a new loop
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000190 logic loop_start_req;
191 logic loop_start_commit;
Greg Chadwick53c95862020-10-14 17:58:38 +0100192 logic [11:0] loop_bodysize;
193 logic [31:0] loop_iterations;
194
195 // Loop generated jumps. The loop controller asks to jump when execution reaches the end of a loop
196 // body that hasn't completed all of its iterations.
197 logic loop_jump;
198 logic [ImemAddrWidth-1:0] loop_jump_addr;
199
Greg Chadwick94786452020-10-28 18:19:51 +0000200 logic [WLEN-1:0] mac_bignum_rf_wr_data;
201
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100202 logic csr_illegal_addr, wsr_illegal_addr, ispr_illegal_addr;
203 logic imem_addr_err, loop_err, ispr_err;
204 logic dmem_addr_err, dmem_addr_unaligned_base, dmem_addr_unaligned_bignum, dmem_addr_overflow;
205
Greg Chadwick496fd342021-03-05 18:08:39 +0000206 logic rf_a_indirect_err, rf_b_indirect_err, rf_d_indirect_err, rf_indirect_err;
207
Vladimir Rozicb8db07a2021-05-24 14:15:04 +0100208 logic insn_cnt_en;
209 logic [31:0] insn_cnt_d, insn_cnt_q;
210
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100211 // Stall a cycle on loads to allow load data writeback to happen the following cycle. Stall not
212 // required on stores as there is no response to deal with.
213 // TODO: Possibility of error response on store? Probably still don't need to stall in that case
214 // just ensure incoming store error stops anything else happening.
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000215 assign mem_stall = lsu_load_req_raw;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100216
Greg Chadwickb168ae92021-04-14 16:04:03 +0100217 // Reads to RND must stall until data is available
218 assign ispr_stall = rnd_req_o & ~rnd_valid_i;
219
220 assign stall = mem_stall | ispr_stall;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100221
222 // OTBN is done (raising the 'done' interrupt) either when it executes an ecall or an error
223 // occurs. The ecall triggered done is factored out as `done_complete` to avoid logic loops in the
224 // error handling logic.
225 assign done_complete = (insn_valid_i && insn_dec_shared_i.ecall_insn);
226 assign done_o = done_complete | err;
Philipp Wagner31441082020-07-14 11:17:21 +0100227
Rupert Swarbrickb2b784d2021-08-03 14:21:51 +0100228 assign jump_or_branch = (insn_valid_i &
229 (insn_dec_shared_i.branch_insn | insn_dec_shared_i.jump_insn));
230
Greg Chadwick51f36232020-09-02 15:37:23 +0100231 // Branch taken when there is a valid branch instruction and comparison passes or a valid jump
232 // instruction (which is always taken)
Philipp Wagnerdc946522020-12-03 10:52:58 +0000233 assign branch_taken = insn_valid_i &
234 ((insn_dec_shared_i.branch_insn & alu_base_comparison_result_i) |
235 insn_dec_shared_i.jump_insn);
Greg Chadwick51f36232020-09-02 15:37:23 +0100236 // Branch target computed by base ALU (PC + imm)
Greg Chadwick51f36232020-09-02 15:37:23 +0100237 assign branch_target = alu_base_operation_result_i[ImemAddrWidth-1:0];
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100238 assign branch_target_overflow = |alu_base_operation_result_i[31:ImemAddrWidth];
Greg Chadwick51f36232020-09-02 15:37:23 +0100239
Rupert Swarbricke9ff47f2021-01-04 13:20:36 +0000240 assign next_insn_addr_wide = {1'b0, insn_addr_i} + 'd4;
241 assign next_insn_addr = next_insn_addr_wide[ImemAddrWidth-1:0];
Greg Chadwick51f36232020-09-02 15:37:23 +0100242
Philipp Wagner31441082020-07-14 11:17:21 +0100243 always_comb begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100244 // `state_raw` and `insn_fetch_req_valid_raw` are the values of `state_d` and
245 // `insn_fetch_req_valid_o` before any errors are considered.
246 state_raw = state_q;
247 insn_fetch_req_valid_raw = 1'b0;
248 insn_fetch_req_addr_o = start_addr_i;
Greg Chadwick28836af2020-07-23 14:35:52 +0100249
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100250 // TODO: Harden state machine
Philipp Wagner31441082020-07-14 11:17:21 +0100251 // TODO: Jumps/branches
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100252 unique case (state_q)
253 OtbnStateHalt: begin
254 if (start_i) begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100255 state_raw = OtbnStateRun;
Greg Chadwickb5b86862021-04-09 15:49:43 +0100256
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100257 insn_fetch_req_addr_o = start_addr_i;
258 insn_fetch_req_valid_raw = 1'b1;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100259 end
260 end
261 OtbnStateRun: begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100262 insn_fetch_req_valid_raw = 1'b1;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100263
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100264 if (done_complete) begin
265 state_raw = OtbnStateHalt;
266 insn_fetch_req_valid_raw = 1'b0;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100267 end else begin
268 // When stalling refetch the same instruction to keep decode inputs constant
269 if (stall) begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100270 state_raw = OtbnStateStall;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100271 insn_fetch_req_addr_o = insn_addr_i;
272 end else begin
Greg Chadwick51f36232020-09-02 15:37:23 +0100273 if (branch_taken) begin
274 insn_fetch_req_addr_o = branch_target;
Greg Chadwick53c95862020-10-14 17:58:38 +0100275 end else if (loop_jump) begin
276 insn_fetch_req_addr_o = loop_jump_addr;
Greg Chadwick51f36232020-09-02 15:37:23 +0100277 end else begin
278 insn_fetch_req_addr_o = next_insn_addr;
279 end
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100280 end
281 end
282 end
283 OtbnStateStall: begin
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100284 insn_fetch_req_valid_raw = 1'b1;
Greg Chadwick9aef1c92021-01-25 18:24:58 +0000285
Greg Chadwicke6e8f152021-03-05 13:35:36 +0000286 // When stalling refetch the same instruction to keep decode inputs constant
287 if (stall) begin
288 state_raw = OtbnStateStall;
289 insn_fetch_req_addr_o = insn_addr_i;
Greg Chadwick9aef1c92021-01-25 18:24:58 +0000290 end else begin
Greg Chadwicke6e8f152021-03-05 13:35:36 +0000291 if (loop_jump) begin
292 insn_fetch_req_addr_o = loop_jump_addr;
293 end else begin
294 insn_fetch_req_addr_o = next_insn_addr;
295 end
Greg Chadwick9aef1c92021-01-25 18:24:58 +0000296
Greg Chadwicke6e8f152021-03-05 13:35:36 +0000297 state_raw = OtbnStateRun;
298 end
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100299 end
300 default: ;
301 endcase
Philipp Wagner31441082020-07-14 11:17:21 +0100302 end
303
Greg Chadwick9aef1c92021-01-25 18:24:58 +0000304 // Anything that moves us or keeps us in the stall state should cause `stall` to be asserted
Philipp Wagnerefa09012021-01-27 14:42:16 +0000305 `ASSERT(StallIfNextStateStall, insn_valid_i & (state_d == OtbnStateStall) |-> stall)
Greg Chadwick9aef1c92021-01-25 18:24:58 +0000306
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100307 // On any error immediately halt and suppress any Imem request.
308 assign state_d = err ? OtbnStateHalt : state_raw;
309 assign insn_fetch_req_valid_o = err ? 1'b0 : insn_fetch_req_valid_raw;
310
311 // Determine if there are any errors related to the Imem fetch address.
312 always_comb begin
313 imem_addr_err = 1'b0;
314
315 if (insn_fetch_req_valid_raw) begin
316 if (|insn_fetch_req_addr_o[1:0]) begin
317 // Imem address is unaligned
318 imem_addr_err = 1'b1;
319 end else if (branch_taken) begin
320 imem_addr_err = branch_target_overflow;
321 end else begin
Rupert Swarbricke9ff47f2021-01-04 13:20:36 +0000322 imem_addr_err = next_insn_addr_wide[ImemAddrWidth];
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100323 end
324 end
325 end
326
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100327 assign err_bits_o.fatal_reg = rf_base_rd_data_err_i | rf_bignum_rd_data_err_i;
Greg Chadwick3bb4f0b2021-02-19 15:07:00 +0000328 assign err_bits_o.fatal_imem = insn_fetch_err_i;
329 assign err_bits_o.fatal_dmem = lsu_rdata_err_i;
Greg Chadwick496fd342021-03-05 18:08:39 +0000330 assign err_bits_o.illegal_insn = insn_illegal_i | ispr_err | rf_indirect_err;
Greg Chadwick3bb4f0b2021-02-19 15:07:00 +0000331 assign err_bits_o.bad_data_addr = dmem_addr_err;
332 assign err_bits_o.loop = loop_err;
333 assign err_bits_o.call_stack = rf_base_call_stack_err_i;
334 assign err_bits_o.bad_insn_addr = imem_addr_err;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100335
Greg Chadwick3bb4f0b2021-02-19 15:07:00 +0000336 assign err = |err_bits_o;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100337
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000338 // Instructions must not execute if there is an error
339 assign insn_executing = insn_valid_i & ~err;
340
Greg Chadwick5ce1cb72021-01-13 14:20:48 +0000341 `ASSERT(ErrBitSetOnErr, err |-> |err_bits_o)
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100342
Greg Chadwickb168ae92021-04-14 16:04:03 +0100343 `ASSERT(ControllerStateValid, state_q inside {OtbnStateHalt, OtbnStateRun,
344 OtbnStateStall})
Greg Chadwick51f36232020-09-02 15:37:23 +0100345 // Branch only takes effect in OtbnStateRun so must not go into stall state for branch
346 // instructions.
Philipp Wagnerdc946522020-12-03 10:52:58 +0000347 `ASSERT(NoStallOnBranch,
348 insn_valid_i & insn_dec_shared_i.branch_insn |-> state_q != OtbnStateStall)
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100349
Greg Chadwick28836af2020-07-23 14:35:52 +0100350 always_ff @(posedge clk_i or negedge rst_ni) begin
351 if (!rst_ni) begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100352 state_q <= OtbnStateHalt;
Greg Chadwick28836af2020-07-23 14:35:52 +0100353 end else begin
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100354 state_q <= state_d;
Greg Chadwick28836af2020-07-23 14:35:52 +0100355 end
356 end
357
Rupert Swarbrick13d50082021-07-13 14:14:03 +0100358 assign insn_cnt_d = state_reset_i ? 32'd0 : (insn_cnt_q + 32'd1);
359 assign insn_cnt_en = (insn_executing & ~stall & (insn_cnt_q != 32'hffffffff)) | state_reset_i;
Vladimir Rozicb8db07a2021-05-24 14:15:04 +0100360 assign insn_cnt_o = insn_cnt_q;
361
362 always_ff @(posedge clk_i or negedge rst_ni) begin
363 if (!rst_ni) begin
364 insn_cnt_q <= 32'd0;
365 end else if (insn_cnt_en) begin
366 insn_cnt_q <= insn_cnt_d;
367 end
368 end
369
Greg Chadwick53c95862020-10-14 17:58:38 +0100370 otbn_loop_controller #(
371 .ImemAddrWidth(ImemAddrWidth)
372 ) u_otbn_loop_controller (
373 .clk_i,
374 .rst_ni,
375
Rupert Swarbrick13d50082021-07-13 14:14:03 +0100376 .state_reset_i,
377
Greg Chadwickb5163fd2020-11-26 16:48:55 +0000378 .insn_valid_i,
Greg Chadwick53c95862020-10-14 17:58:38 +0100379 .insn_addr_i,
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000380 .next_insn_addr_i (next_insn_addr),
Greg Chadwick53c95862020-10-14 17:58:38 +0100381
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000382 .loop_start_req_i (loop_start_req),
383 .loop_start_commit_i (loop_start_commit),
384 .loop_bodysize_i (loop_bodysize),
385 .loop_iterations_i (loop_iterations),
Greg Chadwick53c95862020-10-14 17:58:38 +0100386
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000387 .loop_jump_o (loop_jump),
388 .loop_jump_addr_o (loop_jump_addr),
389 .loop_err_o (loop_err),
Greg Chadwickb5163fd2020-11-26 16:48:55 +0000390
Rupert Swarbrickb2b784d2021-08-03 14:21:51 +0100391 .jump_or_branch_i (jump_or_branch),
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000392 .otbn_stall_i (stall)
Greg Chadwick53c95862020-10-14 17:58:38 +0100393 );
394
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000395 // loop_start_req indicates the instruction wishes to start a loop, loop_start_commit confirms it
396 // should occur.
397 assign loop_start_req = insn_valid_i & insn_dec_shared_i.loop_insn;
398 assign loop_start_commit = insn_executing;
399 assign loop_bodysize = insn_dec_base_i.loop_bodysize;
Rupert Swarbrick514348e2021-02-03 09:04:59 +0000400 assign loop_iterations = insn_dec_base_i.loop_immediate ? insn_dec_base_i.i :
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100401 rf_base_rd_data_a_no_intg;
Greg Chadwick53c95862020-10-14 17:58:38 +0100402
Greg Chadwickae8e6452020-10-02 12:04:15 +0100403 // Compute increments which can be optionally applied to indirect register accesses and memory
404 // addresses in BN.LID/BN.SID/BN.MOVR instructions.
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100405 assign rf_base_rd_data_a_inc = rf_base_rd_data_a_no_intg[4:0] + 1'b1;
406 assign rf_base_rd_data_b_inc = rf_base_rd_data_b_no_intg[4:0] + 1'b1;
Rupert Swarbrick9a4f47b2021-01-04 15:48:24 +0000407 // We can avoid a full 32-bit adder here because the offset is 32-bit aligned, so we know the
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100408 // load/store address will only be valid if rf_base_rd_data_a_no_intg[4:0] is zero.
409 assign rf_base_rd_data_a_wlen_word_inc = rf_base_rd_data_a_no_intg[31:5] + 27'h1;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100410
411 // Choose increment to write back to base register file, only one increment can be written as
412 // there is only one write port. Note that where an instruction is incrementing the indirect
413 // reference to its destination register (insn_dec_bignum_i.d_inc) that reference is read on the
414 // B read port so the B increment is written back.
415 always_comb begin
416 unique case (1'b1)
417 insn_dec_bignum_i.a_inc: begin
Greg Chadwick496fd342021-03-05 18:08:39 +0000418 increment_out = {26'b0, rf_base_rd_data_a_inc};
Greg Chadwickae8e6452020-10-02 12:04:15 +0100419 end
420 insn_dec_bignum_i.b_inc: begin
Greg Chadwick496fd342021-03-05 18:08:39 +0000421 increment_out = {26'b0, rf_base_rd_data_b_inc};
Greg Chadwickae8e6452020-10-02 12:04:15 +0100422 end
423 insn_dec_bignum_i.d_inc: begin
Greg Chadwick496fd342021-03-05 18:08:39 +0000424 increment_out = {26'b0, rf_base_rd_data_b_inc};
Greg Chadwickae8e6452020-10-02 12:04:15 +0100425 end
426 insn_dec_bignum_i.a_wlen_word_inc: begin
Rupert Swarbrick9a4f47b2021-01-04 15:48:24 +0000427 increment_out = {rf_base_rd_data_a_wlen_word_inc, 5'b0};
Greg Chadwickae8e6452020-10-02 12:04:15 +0100428 end
Pirmin Vogele97cac02020-11-02 12:28:50 +0100429 default: begin
430 // Whenever increment_out is written back to the register file, exactly one of the
431 // increment selector signals is high. To prevent the automatic inference of latches in
432 // case nothing is written back (rf_wdata_sel != RfWdSelIncr) and to save logic, we choose
433 // a valid output as default.
Greg Chadwick496fd342021-03-05 18:08:39 +0000434 increment_out = {26'b0, rf_base_rd_data_a_inc};
Pirmin Vogele97cac02020-11-02 12:28:50 +0100435 end
Greg Chadwickae8e6452020-10-02 12:04:15 +0100436 endcase
437 end
438
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100439 // Base RF read/write address, enable and commit control
Greg Chadwickae8e6452020-10-02 12:04:15 +0100440 always_comb begin
441 rf_base_rd_addr_a_o = insn_dec_base_i.a;
442 rf_base_rd_addr_b_o = insn_dec_base_i.b;
443 rf_base_wr_addr_o = insn_dec_base_i.d;
Greg Chadwicke6e8f152021-03-05 13:35:36 +0000444
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100445 // Only commit read or write if the instruction is executing (in particular a read commit pops
446 // the call stack so must not occur where a valid instruction sees an error and doesn't
447 // execute).
448 rf_base_rd_commit_o = insn_executing;
449 rf_base_wr_commit_o = insn_executing;
Greg Chadwick9f5b6382021-05-10 17:53:46 +0100450
451 rf_base_rd_en_a_o = 1'b0;
452 rf_base_rd_en_b_o = 1'b0;
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100453 rf_base_wr_en_o = 1'b0;
Greg Chadwick9f5b6382021-05-10 17:53:46 +0100454
455 if (insn_valid_i) begin
Rupert Swarbrick46e11ba2021-07-13 12:11:43 +0100456 if (insn_dec_shared_i.st_insn) begin
457 // For stores, both base reads happen in the same cycle as the request because they give the
458 // address and data, which make up the request.
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100459 rf_base_rd_en_a_o = insn_dec_base_i.rf_ren_a & lsu_store_req_raw;
460 rf_base_rd_en_b_o = insn_dec_base_i.rf_ren_b & lsu_store_req_raw;
461
462 // Bignum stores can update the base register file where an increment is used.
463 rf_base_wr_en_o = (insn_dec_shared_i.subset == InsnSubsetBignum) &
464 insn_dec_base_i.rf_we &
465 lsu_store_req_raw;
Rupert Swarbrick46e11ba2021-07-13 12:11:43 +0100466 end else if (insn_dec_shared_i.ld_insn) begin
467 // For loads, the A read happens in the same cycle as the request, giving the address from
468 // which to load. The B read is only used for BN.LID and should take place when the
469 // instruction is unstalled, giving the index of the register to write the result to.
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100470 rf_base_rd_en_a_o = insn_dec_base_i.rf_ren_a & lsu_load_req_raw;
Rupert Swarbrick46e11ba2021-07-13 12:11:43 +0100471 rf_base_rd_en_b_o = insn_dec_base_i.rf_ren_b & ~stall;
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100472
473 if (insn_dec_shared_i.subset == InsnSubsetBignum) begin
474 // Bignum loads can update the base register file where an increment is used. When
475 // incrementing the base address this must happen in the same cycle as the request and the
476 // A read. When incrementing the indirect destination register this should happen when the
477 // instruction is unstalled and the B read occurs. This ensures correct call stack
478 // behaviour when x1 is being incremented.
479 rf_base_wr_en_o = insn_dec_bignum_i.d_inc ? insn_dec_base_i.rf_we & ~stall :
480 insn_dec_base_i.rf_we & lsu_load_req_raw;
481 end else begin
482 // For Base loads write the base register file when the instruction is unstalled (meaning
483 // the load data is available).
484 rf_base_wr_en_o = insn_dec_base_i.rf_we & ~stall;
485 end
Greg Chadwick9f5b6382021-05-10 17:53:46 +0100486 end else begin
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100487 // For all other instructions the read and write happen when the instruction is unstalled.
Greg Chadwick9f5b6382021-05-10 17:53:46 +0100488 rf_base_rd_en_a_o = insn_dec_base_i.rf_ren_a & ~stall;
489 rf_base_rd_en_b_o = insn_dec_base_i.rf_ren_b & ~stall;
Greg Chadwick5c8579c2021-08-04 14:38:33 +0100490 rf_base_wr_en_o = insn_dec_base_i.rf_we & ~stall;
Greg Chadwick9f5b6382021-05-10 17:53:46 +0100491 end
Greg Chadwicke6e8f152021-03-05 13:35:36 +0000492 end
Greg Chadwickae8e6452020-10-02 12:04:15 +0100493
494 if (insn_dec_shared_i.subset == InsnSubsetBignum) begin
495 unique case (1'b1)
496 insn_dec_bignum_i.a_inc,
497 insn_dec_bignum_i.a_wlen_word_inc: begin
498 rf_base_wr_addr_o = insn_dec_base_i.a;
499 end
500
501 insn_dec_bignum_i.b_inc,
502 insn_dec_bignum_i.d_inc: begin
503 rf_base_wr_addr_o = insn_dec_base_i.b;
504 end
505 default: ;
506 endcase
507 end
508 end
Philipp Wagner31441082020-07-14 11:17:21 +0100509
510 // Base ALU Operand A MUX
511 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100512 unique case (insn_dec_base_i.op_a_sel)
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100513 OpASelRegister: alu_base_operation_o.operand_a = rf_base_rd_data_a_no_intg;
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100514 OpASelZero: alu_base_operation_o.operand_a = '0;
515 OpASelCurrPc: alu_base_operation_o.operand_a = {{(32 - ImemAddrWidth){1'b0}}, insn_addr_i};
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100516 default: alu_base_operation_o.operand_a = rf_base_rd_data_a_no_intg;
Philipp Wagner31441082020-07-14 11:17:21 +0100517 endcase
518 end
519
520 // Base ALU Operand B MUX
521 always_comb begin
Greg Chadwickcf048242020-10-02 15:28:42 +0100522 unique case (insn_dec_base_i.op_b_sel)
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100523 OpBSelRegister: alu_base_operation_o.operand_b = rf_base_rd_data_b_no_intg;
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100524 OpBSelImmediate: alu_base_operation_o.operand_b = insn_dec_base_i.i;
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100525 default: alu_base_operation_o.operand_b = rf_base_rd_data_b_no_intg;
Philipp Wagner31441082020-07-14 11:17:21 +0100526 endcase
527 end
528
Greg Chadwicke177f172020-09-09 14:46:03 +0100529 assign alu_base_operation_o.op = insn_dec_base_i.alu_op;
Philipp Wagner31441082020-07-14 11:17:21 +0100530
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100531 assign alu_base_comparison_o.operand_a = rf_base_rd_data_a_no_intg;
532 assign alu_base_comparison_o.operand_b = rf_base_rd_data_b_no_intg;
Greg Chadwicke177f172020-09-09 14:46:03 +0100533 assign alu_base_comparison_o.op = insn_dec_base_i.comparison_op;
Greg Chadwick9791eed2020-07-22 18:08:28 +0100534
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100535 assign rf_base_rd_data_a_no_intg = rf_base_rd_data_a_intg_i[31:0];
536 assign rf_base_rd_data_b_no_intg = rf_base_rd_data_b_intg_i[31:0];
537
538 // TODO: For now integrity bits from RF base are ignored in the controller, remove this when end
539 // to end integrity features that use them are implemented
540 logic unused_rf_base_rd_a_intg_bits;
541 logic unused_rf_base_rd_b_intg_bits;
542
543 assign unused_rf_base_rd_a_intg_bits = |rf_base_rd_data_a_intg_i[38:32];
544 assign unused_rf_base_rd_b_intg_bits = |rf_base_rd_data_b_intg_i[38:32];
545
Philipp Wagner31441082020-07-14 11:17:21 +0100546 // Register file write MUX
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100547 always_comb begin
Greg Chadwickee060bd2021-05-15 17:33:22 +0100548 // Write data mux for anything that needs integrity computing during register write
Greg Chadwickcf048242020-10-02 15:28:42 +0100549 unique case (insn_dec_base_i.rf_wdata_sel)
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100550 RfWdSelEx: rf_base_wr_data_no_intg_o = alu_base_operation_result_i;
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100551 RfWdSelNextPc: rf_base_wr_data_no_intg_o = {{(32-(ImemAddrWidth+1)){1'b0}},
552 next_insn_addr_wide};
553 RfWdSelIspr: rf_base_wr_data_no_intg_o = csr_rdata;
554 RfWdSelIncr: rf_base_wr_data_no_intg_o = increment_out;
555 default: rf_base_wr_data_no_intg_o = alu_base_operation_result_i;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100556 endcase
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100557
Greg Chadwickee060bd2021-05-15 17:33:22 +0100558 // Write data mux for anything that provides its own integrity
559 unique case (insn_dec_base_i.rf_wdata_sel)
560 RfWdSelLsu: begin
561 rf_base_wr_data_intg_sel_o = 1'b1;
562 rf_base_wr_data_intg_o = lsu_base_rdata_i;
563 end
564 default: begin
565 rf_base_wr_data_intg_sel_o = 1'b0;
566 rf_base_wr_data_intg_o = '0;
567 end
568 endcase
569 end
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100570
571 for (genvar i = 0; i < BaseWordsPerWLEN; ++i) begin : g_rf_bignum_rd_data
572 assign rf_bignum_rd_data_a_no_intg[i * 32 +: 32] = rf_bignum_rd_data_a_intg_i[i * 39 +: 32];
573 assign rf_bignum_rd_data_b_no_intg[i * 32 +: 32] = rf_bignum_rd_data_b_intg_i[i * 39 +: 32];
574 end
575
576 assign rf_bignum_rd_addr_a_o = insn_dec_bignum_i.rf_a_indirect ? rf_base_rd_data_a_no_intg[4:0] :
Greg Chadwickae8e6452020-10-02 12:04:15 +0100577 insn_dec_bignum_i.a;
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100578 assign rf_bignum_rd_en_a_o = insn_dec_bignum_i.rf_ren_a & insn_valid_i;
Greg Chadwickae8e6452020-10-02 12:04:15 +0100579
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100580 assign rf_bignum_rd_addr_b_o = insn_dec_bignum_i.rf_b_indirect ? rf_base_rd_data_b_no_intg[4:0] :
Greg Chadwickae8e6452020-10-02 12:04:15 +0100581 insn_dec_bignum_i.b;
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100582 assign rf_bignum_rd_en_b_o = insn_dec_bignum_i.rf_ren_b & insn_valid_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100583
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100584 assign alu_bignum_operation_o.operand_a = rf_bignum_rd_data_a_no_intg;
Greg Chadwickf7863442020-09-14 18:11:33 +0100585
586 // Base ALU Operand B MUX
587 always_comb begin
Greg Chadwick94786452020-10-28 18:19:51 +0000588 unique case (insn_dec_bignum_i.alu_op_b_sel)
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100589 OpBSelRegister: alu_bignum_operation_o.operand_b = rf_bignum_rd_data_b_no_intg;
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100590 OpBSelImmediate: alu_bignum_operation_o.operand_b = insn_dec_bignum_i.i;
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100591 default: alu_bignum_operation_o.operand_b = rf_bignum_rd_data_b_no_intg;
Greg Chadwickf7863442020-09-14 18:11:33 +0100592 endcase
593 end
594
595 assign alu_bignum_operation_o.op = insn_dec_bignum_i.alu_op;
Greg Chadwick94786452020-10-28 18:19:51 +0000596 assign alu_bignum_operation_o.shift_right = insn_dec_bignum_i.alu_shift_right;
597 assign alu_bignum_operation_o.shift_amt = insn_dec_bignum_i.alu_shift_amt;
598 assign alu_bignum_operation_o.flag_group = insn_dec_bignum_i.alu_flag_group;
599 assign alu_bignum_operation_o.sel_flag = insn_dec_bignum_i.alu_sel_flag;
Greg Chadwick96fe7052021-03-18 15:15:05 +0000600 assign alu_bignum_operation_o.alu_flag_en = insn_dec_bignum_i.alu_flag_en & insn_executing;
601 assign alu_bignum_operation_o.mac_flag_en = insn_dec_bignum_i.mac_flag_en & insn_executing;
Greg Chadwickf7863442020-09-14 18:11:33 +0100602
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100603 assign mac_bignum_operation_o.operand_a = rf_bignum_rd_data_a_no_intg;
604 assign mac_bignum_operation_o.operand_b = rf_bignum_rd_data_b_no_intg;
Greg Chadwick94786452020-10-28 18:19:51 +0000605 assign mac_bignum_operation_o.operand_a_qw_sel = insn_dec_bignum_i.mac_op_a_qw_sel;
606 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 +0000607 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 +0000608 assign mac_bignum_operation_o.pre_acc_shift_imm = insn_dec_bignum_i.mac_pre_acc_shift;
609 assign mac_bignum_operation_o.zero_acc = insn_dec_bignum_i.mac_zero_acc;
610 assign mac_bignum_operation_o.shift_acc = insn_dec_bignum_i.mac_shift_out;
611
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000612 assign mac_bignum_en_o = insn_executing & insn_dec_bignum_i.mac_en;
Greg Chadwick94786452020-10-28 18:19:51 +0000613
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100614 // Move / Conditional Select. Only select B register data when a selection instruction is being
615 // executed and the selection flag isn't set.
616
617 `ASSERT(SelFlagValid, insn_valid_i & insn_dec_bignum_i.sel_insn |->
618 insn_dec_bignum_i.alu_sel_flag inside {FlagC, FlagL, FlagM, FlagZ})
619
620 assign selection_result =
621 ~insn_dec_bignum_i.sel_insn | alu_bignum_selection_flag_i ? rf_bignum_rd_data_a_intg_i :
622 rf_bignum_rd_data_b_intg_i;
Greg Chadwick94786452020-10-28 18:19:51 +0000623
624 // Bignum Register file write control
625
626 always_comb begin
627 // By default write nothing
628 rf_bignum_wr_en_o = 2'b00;
629
Greg Chadwicke6e8f152021-03-05 13:35:36 +0000630 // Only write if executing instruction wants a bignum rf write and it isn't stalled and there is
631 // no error
632 if (insn_executing && insn_dec_bignum_i.rf_we && !err && !stall) begin
Greg Chadwick94786452020-10-28 18:19:51 +0000633 if (insn_dec_bignum_i.mac_en && insn_dec_bignum_i.mac_shift_out) begin
634 // Special handling for BN.MULQACC.SO, only enable upper or lower half depending on
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000635 // mac_wr_hw_sel_upper.
636 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 +0000637 end else begin
638 // For everything else write both halves immediately.
639 rf_bignum_wr_en_o = 2'b11;
640 end
641 end
642 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100643
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100644 assign rf_bignum_wr_addr_o = insn_dec_bignum_i.rf_d_indirect ? rf_base_rd_data_b_no_intg[4:0] :
Greg Chadwickae8e6452020-10-02 12:04:15 +0100645 insn_dec_bignum_i.d;
Greg Chadwickf7863442020-09-14 18:11:33 +0100646
Greg Chadwick496fd342021-03-05 18:08:39 +0000647
Greg Chadwick94786452020-10-28 18:19:51 +0000648 // 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 +0000649 // half of a desintation register specified by the instruction (mac_wr_hw_sel_upper). The bottom
650 // half of the MAC result must be placed in the appropriate half of the write data (the RF only
651 // accepts write data for the top half in the top half of the write data input). Otherwise
652 // (shift-out to bottom half and all other BN.MULQACC instructions) simply pass the MAC result
653 // through unchanged as write data.
Greg Chadwick94786452020-10-28 18:19:51 +0000654 assign mac_bignum_rf_wr_data[WLEN-1:WLEN/2] =
Philipp Wagnerdc946522020-12-03 10:52:58 +0000655 insn_dec_bignum_i.mac_wr_hw_sel_upper &&
656 insn_dec_bignum_i.mac_shift_out ? mac_bignum_operation_result_i[WLEN/2-1:0] :
657 mac_bignum_operation_result_i[WLEN-1:WLEN/2];
Greg Chadwick94786452020-10-28 18:19:51 +0000658
659 assign mac_bignum_rf_wr_data[WLEN/2-1:0] = mac_bignum_operation_result_i[WLEN/2-1:0];
660
Greg Chadwickf7863442020-09-14 18:11:33 +0100661 always_comb begin
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100662 // Write data mux for anything that needs integrity computing during register write
Greg Chadwickee060bd2021-05-15 17:33:22 +0100663 // TODO: ISPR data will go via direct mux below once integrity has been implemented for
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100664 // them.
Greg Chadwickcf048242020-10-02 15:28:42 +0100665 unique case (insn_dec_bignum_i.rf_wdata_sel)
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100666 RfWdSelEx: rf_bignum_wr_data_no_intg_o = alu_bignum_operation_result_i;
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100667 RfWdSelIspr: rf_bignum_wr_data_no_intg_o = ispr_rdata_i;
668 RfWdSelMac: rf_bignum_wr_data_no_intg_o = mac_bignum_rf_wr_data;
669 default: rf_bignum_wr_data_no_intg_o = alu_bignum_operation_result_i;
670 endcase
671
672 // Write data mux for anything that provides its own integrity
673 unique case (insn_dec_bignum_i.rf_wdata_sel)
674 RfWdSelMovSel: begin
675 rf_bignum_wr_data_intg_sel_o = 1'b1;
676 rf_bignum_wr_data_intg_o = selection_result;
677 end
Greg Chadwickee060bd2021-05-15 17:33:22 +0100678 RfWdSelLsu: begin
679 rf_bignum_wr_data_intg_sel_o = 1'b1;
680 rf_bignum_wr_data_intg_o = lsu_bignum_rdata_i;
681 end
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100682 default: begin
683 rf_bignum_wr_data_intg_sel_o = 1'b0;
684 rf_bignum_wr_data_intg_o = '0;
685 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100686 endcase
687 end
688
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100689 assign rf_a_indirect_err = insn_dec_bignum_i.rf_a_indirect & (|rf_base_rd_data_a_no_intg[31:5]);
690 assign rf_b_indirect_err = insn_dec_bignum_i.rf_b_indirect & (|rf_base_rd_data_b_no_intg[31:5]);
691 assign rf_d_indirect_err = insn_dec_bignum_i.rf_d_indirect & (|rf_base_rd_data_b_no_intg[31:5]);
Greg Chadwick496fd342021-03-05 18:08:39 +0000692
693 assign rf_indirect_err =
694 insn_valid_i & (rf_a_indirect_err | rf_b_indirect_err | rf_d_indirect_err);
695
Greg Chadwickf7863442020-09-14 18:11:33 +0100696 // CSR/WSR/ISPR handling
697 // ISPRs (Internal Special Purpose Registers) are the internal registers. CSRs and WSRs are the
698 // ISA visible versions of those registers in the base and bignum ISAs respectively.
699
Philipp Wagner711d2262021-01-21 18:17:42 +0000700 assign csr_addr = csr_e'(insn_dec_base_i.i[11:0]);
701 assign csr_sub_addr = insn_dec_base_i.i[$clog2(BaseWordsPerWLEN)-1:0];
Greg Chadwickf7863442020-09-14 18:11:33 +0100702
703 always_comb begin
704 ispr_addr_base = IsprMod;
705 ispr_word_addr_base = '0;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100706 csr_illegal_addr = 1'b0;
Greg Chadwickf7863442020-09-14 18:11:33 +0100707
708 unique case (csr_addr)
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000709 CsrFlags, CsrFg0, CsrFg1 : begin
Greg Chadwickf7863442020-09-14 18:11:33 +0100710 ispr_addr_base = IsprFlags;
711 ispr_word_addr_base = '0;
712 end
Philipp Wagner711d2262021-01-21 18:17:42 +0000713 CsrMod0, CsrMod1, CsrMod2, CsrMod3, CsrMod4, CsrMod5, CsrMod6, CsrMod7: begin
Greg Chadwickf7863442020-09-14 18:11:33 +0100714 ispr_addr_base = IsprMod;
Philipp Wagner711d2262021-01-21 18:17:42 +0000715 ispr_word_addr_base = csr_sub_addr;
Greg Chadwickf7863442020-09-14 18:11:33 +0100716 end
Greg Chadwickb168ae92021-04-14 16:04:03 +0100717 CsrRndPrefetch: begin
718 // Reading from RND_PREFETCH results in 0, there is no ISPR to read so no address is set.
719 // The csr_rdata mux logic takes care of producing the 0.
720 end
Philipp Wagner93877522021-07-16 10:49:25 +0100721 CsrRnd: begin
722 ispr_addr_base = IsprRnd;
723 ispr_word_addr_base = '0;
724 end
Greg Chadwickb168ae92021-04-14 16:04:03 +0100725 CsrUrnd: begin
726 ispr_addr_base = IsprUrnd;
727 ispr_word_addr_base = '0;
728 end
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100729 default: csr_illegal_addr = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100730 endcase
731 end
732
733 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_ispr_word_sel_base
734 assign ispr_word_sel_base[i_word] = ispr_word_addr_base == i_word;
735 end
736
737 for (genvar i_bit = 0; i_bit < 32; i_bit++) begin : g_csr_rdata_mux
738 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_csr_rdata_mux_inner
Philipp Wagnerdc946522020-12-03 10:52:58 +0000739 assign csr_rdata_mux[i_bit][i_word] =
740 ispr_rdata_i[i_word*32 + i_bit] & ispr_word_sel_base[i_word];
Greg Chadwickf7863442020-09-14 18:11:33 +0100741 end
742
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000743 assign csr_rdata_raw[i_bit] = |csr_rdata_mux[i_bit];
Greg Chadwickf7863442020-09-14 18:11:33 +0100744 end
745
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000746 // Specialised read data handling for CSR reads where raw read data needs modification.
747 always_comb begin
748 csr_rdata = csr_rdata_raw;
749
Greg Chadwickb168ae92021-04-14 16:04:03 +0100750 unique case (csr_addr)
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000751 // For FG0/FG1 select out appropriate bits from FLAGS ISPR and pad the rest with zeros.
Greg Chadwickb168ae92021-04-14 16:04:03 +0100752 CsrFg0: csr_rdata = {28'b0, csr_rdata_raw[3:0]};
753 CsrFg1: csr_rdata = {28'b0, csr_rdata_raw[7:4]};
754 CsrRndPrefetch: csr_rdata = '0;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000755 default: ;
756 endcase
757 end
758
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100759 assign csr_wdata_raw = insn_dec_shared_i.ispr_rs_insn ? csr_rdata | rf_base_rd_data_a_no_intg :
760 rf_base_rd_data_a_no_intg;
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000761
762 // Specialised write data handling for CSR writes where raw write data needs modification.
763 always_comb begin
764 csr_wdata = csr_wdata_raw;
765
Greg Chadwickb168ae92021-04-14 16:04:03 +0100766 unique case (csr_addr)
Greg Chadwickdbd655a2020-11-24 16:42:06 +0000767 // For FG0/FG1 only modify relevant part of FLAGS ISPR.
768 CsrFg0: csr_wdata = {24'b0, csr_rdata_raw[7:4], csr_wdata_raw[3:0]};
769 CsrFg1: csr_wdata = {24'b0, csr_wdata_raw[3:0], csr_rdata_raw[3:0]};
770 default: ;
771 endcase
772 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100773
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000774 // ISPR RS (read and set) must not be combined with ISPR RD or WR (read or write). ISPR RD and
775 // WR (read and write) is allowed.
776 `ASSERT(NoIsprRorWAndRs, insn_valid_i |-> ~(insn_dec_shared_i.ispr_rs_insn &
777 (insn_dec_shared_i.ispr_rd_insn |
778 insn_dec_shared_i.ispr_wr_insn)))
779
780
Greg Chadwickf7863442020-09-14 18:11:33 +0100781 assign wsr_addr = wsr_e'(insn_dec_bignum_i.i[WsrNumWidth-1:0]);
782
783 always_comb begin
784 ispr_addr_bignum = IsprMod;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100785 wsr_illegal_addr = 1'b0;
Greg Chadwickf7863442020-09-14 18:11:33 +0100786
787 unique case (wsr_addr)
Greg Chadwickb168ae92021-04-14 16:04:03 +0100788 WsrMod: ispr_addr_bignum = IsprMod;
789 WsrRnd: ispr_addr_bignum = IsprRnd;
Greg Chadwickb168ae92021-04-14 16:04:03 +0100790 WsrUrnd: ispr_addr_bignum = IsprUrnd;
Philipp Wagner19afa992021-07-16 10:56:23 +0100791 WsrAcc: ispr_addr_bignum = IsprAcc;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100792 default: wsr_illegal_addr = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100793 endcase
794 end
795
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100796 assign wsr_wdata = insn_dec_shared_i.ispr_rs_insn ? ispr_rdata_i | rf_bignum_rd_data_a_no_intg :
797 rf_bignum_rd_data_a_no_intg;
Greg Chadwickf7863442020-09-14 18:11:33 +0100798
Philipp Wagner711d2262021-01-21 18:17:42 +0000799 assign ispr_illegal_addr = insn_dec_shared_i.subset == InsnSubsetBase ? csr_illegal_addr :
800 wsr_illegal_addr;
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100801
802 assign ispr_err = ispr_illegal_addr & insn_valid_i & (insn_dec_shared_i.ispr_rd_insn |
803 insn_dec_shared_i.ispr_wr_insn |
804 insn_dec_shared_i.ispr_rs_insn);
805
Rupert Swarbricka2c05e72020-11-20 08:46:25 +0000806 assign ispr_wr_insn = insn_dec_shared_i.ispr_wr_insn | insn_dec_shared_i.ispr_rs_insn;
Greg Chadwickb168ae92021-04-14 16:04:03 +0100807 assign ispr_rd_insn = insn_dec_shared_i.ispr_rd_insn | insn_dec_shared_i.ispr_rs_insn;
808
809 // Write to RND_PREFETCH must not produce ISR write
810 assign ispr_wr_base_insn =
811 ispr_wr_insn & (insn_dec_shared_i.subset == InsnSubsetBase) & (csr_addr != CsrRndPrefetch);
812
Rupert Swarbrick514348e2021-02-03 09:04:59 +0000813 assign ispr_wr_bignum_insn = ispr_wr_insn & (insn_dec_shared_i.subset == InsnSubsetBignum);
Greg Chadwickf7863442020-09-14 18:11:33 +0100814
Philipp Wagnerdc946522020-12-03 10:52:58 +0000815 assign ispr_addr_o = insn_dec_shared_i.subset == InsnSubsetBase ? ispr_addr_base :
816 ispr_addr_bignum;
Greg Chadwickf7863442020-09-14 18:11:33 +0100817 assign ispr_base_wdata_o = csr_wdata;
Rupert Swarbrick514348e2021-02-03 09:04:59 +0000818 assign ispr_base_wr_en_o = {BaseWordsPerWLEN{ispr_wr_base_insn & insn_executing}} &
819 ispr_word_sel_base;
Greg Chadwickf6f35962020-11-02 17:32:08 +0000820
Greg Chadwickf7863442020-09-14 18:11:33 +0100821 assign ispr_bignum_wdata_o = wsr_wdata;
Rupert Swarbrick514348e2021-02-03 09:04:59 +0000822 assign ispr_bignum_wr_en_o = ispr_wr_bignum_insn & insn_executing;
Greg Chadwickf7863442020-09-14 18:11:33 +0100823
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000824 // lsu_load_req_raw/lsu_store_req_raw indicate an instruction wishes to perform a store or a load.
Rupert Swarbrick514348e2021-02-03 09:04:59 +0000825 // lsu_load_req_o/lsu_store_req_o factor in whether an instruction is actually executing (it may
826 // be suppressed due an error) and command the load or store to happen when asserted.
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000827 assign lsu_load_req_raw = insn_valid_i & insn_dec_shared_i.ld_insn & (state_q == OtbnStateRun);
828 assign lsu_load_req_o = insn_executing & lsu_load_req_raw;
829
830 assign lsu_store_req_raw = insn_valid_i & insn_dec_shared_i.st_insn & (state_q == OtbnStateRun);
831 assign lsu_store_req_o = insn_executing & lsu_store_req_raw;
832
Greg Chadwickf7863442020-09-14 18:11:33 +0100833 assign lsu_req_subset_o = insn_dec_shared_i.subset;
Greg Chadwickc8cd4352020-08-14 16:45:23 +0100834
Greg Chadwickae8e6452020-10-02 12:04:15 +0100835 assign lsu_addr_o = alu_base_operation_result_i[DmemAddrWidth-1:0];
Greg Chadwickee060bd2021-05-15 17:33:22 +0100836 assign lsu_base_wdata_o = rf_base_rd_data_b_intg_i;
837 assign lsu_bignum_wdata_o = rf_bignum_rd_data_b_intg_i;
Greg Chadwick6ab8d952020-10-30 12:13:34 +0000838
Philipp Wagner711d2262021-01-21 18:17:42 +0000839 assign dmem_addr_unaligned_bignum =
840 (lsu_req_subset_o == InsnSubsetBignum) & (|lsu_addr_o[$clog2(WLEN/8)-1:0]);
841 assign dmem_addr_unaligned_base =
842 (lsu_req_subset_o == InsnSubsetBase) & (|lsu_addr_o[1:0]);
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100843 assign dmem_addr_overflow = |alu_base_operation_result_i[31:DmemAddrWidth];
844
Greg Chadwick42a9f3b2021-01-28 13:54:14 +0000845 assign dmem_addr_err =
846 insn_valid_i & (lsu_load_req_raw | lsu_store_req_raw) & (dmem_addr_overflow |
Greg Chadwickd3154ec2020-09-24 12:03:23 +0100847 dmem_addr_unaligned_bignum |
848 dmem_addr_unaligned_base);
849
Greg Chadwickb168ae92021-04-14 16:04:03 +0100850 assign rnd_req_o = insn_valid_i & ispr_rd_insn & (ispr_addr_o == IsprRnd);
851
852 assign rnd_prefetch_req_o = insn_valid_i & ispr_wr_insn &
853 (insn_dec_shared_i.subset == InsnSubsetBase) & (csr_addr == CsrRndPrefetch);
Philipp Wagner31441082020-07-14 11:17:21 +0100854endmodule