-
Notifications
You must be signed in to change notification settings - Fork 22
/
cv32e40s_if_stage.sv
707 lines (582 loc) · 31.2 KB
/
cv32e40s_if_stage.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// Engineer: Renzo Andri - andrire@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// Andreas Traber - atraber@student.ethz.ch //
// Sven Stucki - svstucki@student.ethz.ch //
// Michael Platzer - michael.platzer@tuwien.ac.at //
// //
// Design Name: Instruction Fetch Stage //
// Project Name: RI5CY //
// Language: SystemVerilog //
// //
// Description: Instruction fetch unit: Selection of the next PC, and //
// buffering (sampling) of the read instruction //
// //
////////////////////////////////////////////////////////////////////////////////
module cv32e40s_if_stage import cv32e40s_pkg::*;
#(
parameter rv32_e RV32 = RV32I,
parameter b_ext_e B_EXT = B_NONE,
parameter int PMA_NUM_REGIONS = 0,
parameter pma_cfg_t PMA_CFG[PMA_NUM_REGIONS-1:0] = '{default:PMA_R_DEFAULT},
parameter int unsigned PMP_GRANULARITY = 0,
parameter int PMP_NUM_REGIONS = 0,
parameter bit DUMMY_INSTRUCTIONS = 0,
parameter int unsigned MTVT_ADDR_WIDTH = 26,
parameter bit CLIC = 1'b0,
parameter int unsigned CLIC_ID_WIDTH = 5,
parameter bit ZC_EXT = 0,
parameter m_ext_e M_EXT = M_NONE,
parameter bit DEBUG = 1,
parameter logic [31:0] DM_REGION_START = 32'hF0000000,
parameter logic [31:0] DM_REGION_END = 32'hF0003FFF
)
(
input logic clk,
input logic rst_n,
// Target addresses
input logic [31:0] boot_addr_i, // Boot address
input logic [31:0] branch_target_ex_i, // Branch target address
input logic [31:0] dm_exception_addr_i, // Debug mode exception address
input logic [31:0] dm_halt_addr_i, // Debug mode halt address
input logic [31:0] dpc_i, // Debug PC (restore upon return from debug)
input logic [31:0] jump_target_id_i, // Jump target address
input logic [31:0] mepc_i, // Exception PC (restore upon return from exception/interrupt)
input logic [24:0] mtvec_addr_i, // Exception/interrupt address (MSBs)
input logic [5:0] jvt_mode_i,
input logic branch_decision_ex_i, // Current branch decision from EX
input logic last_sec_op_id_i,
output logic pc_err_o, // Error signal for the pc checker module
input logic [MTVT_ADDR_WIDTH-1:0] mtvt_addr_i, // Base address for CLIC vectoring
input ctrl_fsm_t ctrl_fsm_i,
input logic trigger_match_i,
// Instruction bus interface
cv32e40s_if_c_obi.master m_c_obi_instr_if,
output if_id_pipe_t if_id_pipe_o, // IF/ID pipeline stage
output logic [31:0] pc_if_o, // Program counter
output logic csr_mtvec_init_o, // Tell CS regfile to init mtvec
output logic if_busy_o, // Is the IF stage busy fetching instructions?
output logic ptr_in_if_o, // The IF stage currently holds a pointer
output privlvl_t priv_lvl_if_o, // Privilege level of the instruction currently in IF
output logic first_op_nondummy_o,
output logic last_op_o,
output logic abort_op_o,
output logic prefetch_valid_o,
// Stage ready/valid
output logic if_valid_o,
input logic id_ready_i,
input logic id_valid_i,
input logic ex_ready_i,
input logic ex_valid_i,
input logic wb_ready_i,
input id_ex_pipe_t id_ex_pipe_i,
// PMP CSR's
input pmp_csr_t csr_pmp_i,
// mstateen CSR
input logic [31:0] mstateen0_i,
// Privilege mode
input privlvlctrl_t priv_lvl_ctrl_i,
// Dummy Instruction Control
input xsecure_ctrl_t xsecure_ctrl_i,
output logic lfsr_shift_o,
output logic integrity_err_o,
output logic protocol_err_o
);
// ALBUF_DEPTH set to 3 as the alignment_buffer will need 3 entries to function correctly
localparam int unsigned ALBUF_DEPTH = 3;
localparam int unsigned ALBUF_CNT_WIDTH = $clog2(ALBUF_DEPTH);
logic if_ready;
// prefetch buffer related signals
logic prefetch_busy;
logic [31:0] branch_addr_n;
logic prefetch_valid;
logic prefetch_ready;
inst_resp_t prefetch_instr;
privlvl_t prefetch_priv_lvl;
logic prefetch_is_clic_ptr;
logic prefetch_is_mret_ptr;
logic prefetch_is_tbljmp_ptr;
logic illegal_c_insn;
inst_resp_t instr_decompressed;
logic instr_compressed;
logic instr_hint;
// Transaction signals to/from obi interface
logic prefetch_resp_valid;
logic prefetch_trans_valid;
logic prefetch_trans_ready;
logic [31:0] prefetch_trans_addr;
logic prefetch_trans_ptr;
inst_resp_t prefetch_inst_resp;
logic prefetch_one_txn_pend_n;
logic [ALBUF_CNT_WIDTH-1:0] prefetch_outstnd_cnt_q;
logic bus_resp_valid;
obi_inst_resp_t bus_resp;
logic bus_trans_valid;
logic bus_trans_ready;
obi_inst_req_t bus_trans;
obi_inst_req_t core_trans;
logic dummy_insert;
inst_resp_t dummy_instr;
logic alcheck_resp_valid;
inst_resp_t alcheck_resp;
logic alcheck_trans_valid;
logic alcheck_trans_ready;
obi_inst_req_t alcheck_trans;
logic align_check_en;
logic address_misaligned;
// Local instr_valid
logic instr_valid;
// ready signal for predecoder, tied to id_ready_i
logic predec_ready;
// Zc* sequencer signals
logic seq_valid; // sequencer has valid output
logic seq_ready; // sequencer is ready for new inputs
logic seq_instr_valid; // Sequencer has valid inputs
logic seq_first; // sequencer is outputting the first operation
logic seq_last; // sequencer is outputting the last operation
inst_resp_t seq_instr; // Instruction for sequenced operation
logic seq_tbljmp; // Sequenced instruction is a table jump
logic seq_pushpop; // Sequenced instruction is a push or pop
logic id_ready_no_dummy; // Ready signal to acknowledge the sequencer
logic first_op; // Local first_op, including dummies
logic integrity_err_obi; // Integrity error from OBI interface
logic protocol_err_obi; // Protocol error from OBI interface
logic prefetch_protocol_err;
logic unused_signals;
// Fetch address selection
always_comb
begin
// Default assign PC_BOOT (should be overwritten in below case)
branch_addr_n = {boot_addr_i[31:2], 2'b0};
unique case (ctrl_fsm_i.pc_mux)
PC_BOOT: branch_addr_n = {boot_addr_i[31:2], 2'b0};
PC_JUMP: branch_addr_n = jump_target_id_i;
PC_BRANCH: branch_addr_n = branch_target_ex_i;
PC_MRET: branch_addr_n = mepc_i; // PC is restored when returning from IRQ/exception
PC_DRET: branch_addr_n = dpc_i;
PC_WB_PLUS4: branch_addr_n = ctrl_fsm_i.pipe_pc; // Jump to next instruction forces prefetch buffer reload
PC_TRAP_EXC: branch_addr_n = {mtvec_addr_i, 7'h0}; // All the exceptions go to base address
PC_TRAP_IRQ: branch_addr_n = {mtvec_addr_i, ctrl_fsm_i.mtvec_pc_mux, 2'b00}; // interrupts are vectored
PC_TRAP_DBD: branch_addr_n = {dm_halt_addr_i[31:2], 2'b0};
PC_TRAP_DBE: branch_addr_n = {dm_exception_addr_i[31:2], 2'b0};
PC_TRAP_NMI: branch_addr_n = {mtvec_addr_i, ctrl_fsm_i.nmi_mtvec_index, 2'b00};
PC_TRAP_CLICV: branch_addr_n = {mtvt_addr_i, ctrl_fsm_i.mtvt_pc_mux[CLIC_ID_WIDTH-1:0], 2'b00};
// CLIC and Zc* spec requires to clear bit 0. This clearing is done in the alignment buffer.
PC_POINTER : branch_addr_n = if_id_pipe_o.ptr;
// JVT + (index << 2)
PC_TBLJUMP : branch_addr_n = jump_target_id_i; // Tablejumps reuse jump target adder in the ID stage.
default:;
endcase
end
// tell CS register file to initialize mtvec on boot
assign csr_mtvec_init_o = (ctrl_fsm_i.pc_mux == PC_BOOT) & ctrl_fsm_i.pc_set;
// prefetch buffer, caches a fixed number of instructions
cv32e40s_prefetch_unit
#(
.CLIC (CLIC),
.ALBUF_DEPTH (ALBUF_DEPTH),
.ALBUF_CNT_WIDTH (ALBUF_CNT_WIDTH)
)
prefetch_unit_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.ctrl_fsm_i ( ctrl_fsm_i ),
.priv_lvl_ctrl_i ( priv_lvl_ctrl_i ),
.branch_addr_i ( {branch_addr_n[31:1], 1'b0} ),
.prefetch_ready_i ( prefetch_ready ),
.prefetch_valid_o ( prefetch_valid ),
.prefetch_instr_o ( prefetch_instr ),
.prefetch_addr_o ( pc_if_o ),
.prefetch_priv_lvl_o ( prefetch_priv_lvl ),
.prefetch_is_clic_ptr_o ( prefetch_is_clic_ptr ),
.prefetch_is_mret_ptr_o ( prefetch_is_mret_ptr ),
.prefetch_is_tbljmp_ptr_o ( prefetch_is_tbljmp_ptr ),
.trans_valid_o ( prefetch_trans_valid ),
.trans_ready_i ( prefetch_trans_ready ),
.trans_addr_o ( prefetch_trans_addr ),
.trans_ptr_o ( prefetch_trans_ptr ),
.resp_valid_i ( prefetch_resp_valid ),
.resp_i ( prefetch_inst_resp ),
.xsecure_ctrl_i ( xsecure_ctrl_i ),
// Prefetch Buffer Status
.prefetch_busy_o ( prefetch_busy ),
.one_txn_pend_n ( prefetch_one_txn_pend_n ),
.outstnd_cnt_q_o ( prefetch_outstnd_cnt_q ),
.protocol_err_o ( prefetch_protocol_err )
);
//////////////////////////////////////////////////////////////////////////////
// MPU
//////////////////////////////////////////////////////////////////////////////
// TODO: The prot bits are currently not checked for correctness anywhere
assign core_trans.addr = prefetch_trans_addr;
assign core_trans.dbg = ctrl_fsm_i.debug_mode_if;
assign core_trans.prot[0] = 1'b0; // Transfers from IF stage are instruction transfers
assign core_trans.prot[2:1] = prefetch_priv_lvl; // Privilege level
assign core_trans.memtype = 2'b00; // memtype is assigned in the MPU
assign core_trans.achk = 12'b0; // Integrity signals assigned in bus interface
assign core_trans.integrity = 1'b0; // PMA integrity attribute is assigned in the MPU
cv32e40s_mpu
#(
.IF_STAGE ( 1 ),
.CORE_REQ_TYPE ( obi_inst_req_t ),
.CORE_RESP_TYPE ( inst_resp_t ),
.BUS_RESP_TYPE ( inst_resp_t ),
.PMA_NUM_REGIONS ( PMA_NUM_REGIONS ),
.PMA_CFG ( PMA_CFG ),
.PMP_GRANULARITY ( PMP_GRANULARITY ),
.PMP_NUM_REGIONS ( PMP_NUM_REGIONS ),
.DEBUG ( DEBUG ),
.DM_REGION_START ( DM_REGION_START ),
.DM_REGION_END ( DM_REGION_END )
)
mpu_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.misaligned_access_i ( 1'b0 ), // MPU on instruction side will not issue misaligned access fault
// Misaligned access to main is allowed, and accesses outside main will
// result in instruction access fault (which will have priority over
// misaligned from I/O fault)
.csr_pmp_i ( csr_pmp_i ),
.core_one_txn_pend_n ( prefetch_one_txn_pend_n ),
.core_mpu_err_wait_i ( 1'b1 ),
.core_mpu_err_o ( ), // Unconnected on purpose
.core_trans_valid_i ( prefetch_trans_valid ),
.core_trans_pushpop_i ( 1'b0 ), // Prefetches are never part of a PUSH/POP sequence
.core_trans_ready_o ( prefetch_trans_ready ),
.core_trans_i ( core_trans ),
.core_resp_valid_o ( prefetch_resp_valid ),
.core_resp_o ( prefetch_inst_resp ),
.bus_trans_valid_o ( alcheck_trans_valid ),
.bus_trans_ready_i ( alcheck_trans_ready ),
.bus_trans_o ( alcheck_trans ),
.bus_resp_valid_i ( alcheck_resp_valid ),
.bus_resp_i ( alcheck_resp )
);
assign align_check_en = prefetch_trans_ptr;
assign address_misaligned = |prefetch_trans_addr[1:0];
cv32e40s_align_check
#(
.IF_STAGE ( 1 ),
.CORE_RESP_TYPE ( inst_resp_t ),
.BUS_RESP_TYPE ( obi_inst_resp_t ),
.CORE_REQ_TYPE ( obi_inst_req_t )
)
align_check_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.align_check_en_i ( align_check_en ),
.misaligned_access_i ( address_misaligned ),
.core_one_txn_pend_n ( prefetch_one_txn_pend_n ),
.core_align_err_wait_i( 1'b1 ),
.core_align_err_o ( ), // Unconnected on purpose
.core_trans_valid_i ( alcheck_trans_valid ),
.core_trans_ready_o ( alcheck_trans_ready ),
.core_trans_i ( alcheck_trans ),
.core_resp_valid_o ( alcheck_resp_valid ),
.core_resp_o ( alcheck_resp ),
.bus_trans_valid_o ( bus_trans_valid ),
.bus_trans_ready_i ( bus_trans_ready ),
.bus_trans_o ( bus_trans ),
.bus_resp_valid_i ( bus_resp_valid ),
.bus_resp_i ( bus_resp )
);
//////////////////////////////////////////////////////////////////////////////
// OBI interface
//////////////////////////////////////////////////////////////////////////////
cv32e40s_instr_obi_interface
#(
.MAX_OUTSTANDING (2) // todo: hook up to parameter
)
instruction_obi_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.trans_valid_i ( bus_trans_valid ),
.trans_ready_o ( bus_trans_ready ),
.trans_i ( bus_trans ),
.resp_valid_o ( bus_resp_valid ),
.resp_o ( bus_resp ),
.integrity_err_o ( integrity_err_obi), // immediate integrity error
.protocol_err_o ( protocol_err_obi ), // immediate protocol error
.xsecure_ctrl_i ( xsecure_ctrl_i ),
.m_c_obi_instr_if ( m_c_obi_instr_if )
);
///////////////
// PC checker
///////////////
cv32e40s_pc_check
pc_check_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.xsecure_ctrl_i ( xsecure_ctrl_i ),
.if_valid_i ( if_valid_o ),
.id_ready_i ( id_ready_i ),
.id_valid_i ( id_valid_i ),
.ex_ready_i ( ex_ready_i ),
.ex_valid_i ( ex_valid_i ),
.wb_ready_i ( wb_ready_i ),
.pc_if_i ( pc_if_o ),
.ctrl_fsm_i ( ctrl_fsm_i ),
.if_id_pipe_i ( if_id_pipe_o ),
.id_ex_pipe_i ( id_ex_pipe_i ),
.jump_target_id_i ( jump_target_id_i ),
.branch_target_ex_i ( branch_target_ex_i ),
.branch_decision_ex_i ( branch_decision_ex_i ),
.last_sec_op_id_i ( last_sec_op_id_i ),
.last_op_ex_i ( id_ex_pipe_i.last_op ),
.prefetch_is_ptr_i ( ptr_in_if_o ),
.mepc_i ( mepc_i ),
.mtvec_addr_i ( mtvec_addr_i ),
.dpc_i ( dpc_i ),
.boot_addr_i ( boot_addr_i ),
.dm_halt_addr_i ( dm_halt_addr_i ),
.dm_exception_addr_i ( dm_exception_addr_i ),
.pc_err_o ( pc_err_o )
);
// Local instr_valid when we have valid output from prefetcher or we are inserting a dummy instruction
// and IF is not halted or killed
assign instr_valid = (prefetch_valid || dummy_insert) && !ctrl_fsm_i.kill_if && !ctrl_fsm_i.halt_if;
// if_stage ready when killed, otherwise when not halted or if a dummy instruction is inserted.
assign if_ready = ctrl_fsm_i.kill_if || (seq_ready && predec_ready && !ctrl_fsm_i.halt_if);
// if stage valid when local instr_valid=1
// Ideally this should be the following:
//
// assign if_valid_o = (seq_en && seq_valid ) ||
// (predec_en && predec_valid ) && instr_valid;
//
// The predecoder is purely combinatorial module, and will produce a valid output for any valid input (instr_valid)
// The Sequencer will output valid=1 for any instruction it can decode while not halted or killed
// when its valid_i (prefetch_valid) is high.
assign if_valid_o = instr_valid;
assign if_busy_o = prefetch_busy;
// Ensures one shift of lfsr0 for each instruction (dummy or hint) inserted in IF
assign lfsr_shift_o = if_valid_o && id_ready_i && (dummy_insert || instr_hint);
assign ptr_in_if_o = prefetch_is_clic_ptr || prefetch_is_mret_ptr || prefetch_is_tbljmp_ptr;
// Acknowledge prefetcher when IF stage is ready. This factors in seq_ready to avoid ack'ing the
// prefetcher in the middle of a Zc sequence.
assign prefetch_ready = if_ready;
// Sequenced instructions set last_op from the sequencer.
// Any other instruction will be single operation, and gets last_op=1.
// Regular CLIC pointers are single operation with first_op == last_op == 1
// CLIC pointers that are a side effect of mret instructions will have first_op == 0 and last_op == 1
assign last_op_o = dummy_insert ? 1'b1 :
seq_valid ? seq_last : // Sequencer controls last_op for sequenced instructions
prefetch_is_mret_ptr ? 1'b1 : // clic pointer caused by mret, must be !first && last
1'b1; // Any other regular instructions are single operation.
// Flag first operation of a sequence (excluding dummy instructions)
// Any sequenced instructions use the seq_first from the sequencer.
// Any other instruction will be single operation, and gets first_op=1.
// Regular CLIC pointers are single operation with first_op == last_op == 1
// CLIC pointers that are a side effect of mret instructions will have first_op == 0 and last_op == 1
assign first_op_nondummy_o = seq_valid ? seq_first :
prefetch_is_mret_ptr ? 1'b0 :
1'b1; // Any other regular instructions are single operation.
// Local first_op, including dummy instructions
assign first_op = dummy_insert ? 1'b1 : first_op_nondummy_o;
// Set flag to indicate that instruction/sequence will be aborted due to known exceptions or trigger match
assign abort_op_o = dummy_insert ? 1'b0 :
(instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK) ||
(instr_decompressed.bus_resp.integrity_err) || (instr_decompressed.align_status != ALIGN_OK) || trigger_match_i);
assign prefetch_valid_o = prefetch_valid;
// Signal current privilege level of IF
assign priv_lvl_if_o = prefetch_priv_lvl;
// Populate instruction meta data
// Fields 'compressed' and 'tbljmp' keep their old value by default.
// - In case of a table jump we need the fields to stay as 'compressed=1' and 'tbljmp=1'
// even when the pointer is sent to ID (operation 2/2)
// - For all cases except table jump pointer we update the values to the current values from predecoding.
instr_meta_t instr_meta_n;
always_comb begin
instr_meta_n = '0;
instr_meta_n.dummy = dummy_insert;
instr_meta_n.hint = dummy_insert ? 1'b0 : instr_hint; // dummies may be inserted when a hint is in IF
instr_meta_n.compressed = if_id_pipe_o.instr_meta.compressed;
instr_meta_n.clic_ptr = prefetch_is_clic_ptr;
instr_meta_n.mret_ptr = prefetch_is_mret_ptr;
instr_meta_n.tbljmp = if_id_pipe_o.instr_meta.tbljmp;
instr_meta_n.pushpop = if_id_pipe_o.instr_meta.pushpop;
end
// IF-ID pipeline registers, frozen when the ID stage is stalled
// Todo: E40S: We will probably need to prevent dummy instructions between pointer fetcher and the pointer target fetch
always_ff @(posedge clk, negedge rst_n)
begin : IF_ID_PIPE_REGISTERS
if (rst_n == 1'b0) begin
if_id_pipe_o.instr_valid <= 1'b0;
if_id_pipe_o.instr <= INST_RESP_RESET_VAL;
if_id_pipe_o.instr_meta <= '0;
if_id_pipe_o.pc <= '0;
if_id_pipe_o.illegal_c_insn <= 1'b0;
if_id_pipe_o.compressed_instr <= '0;
if_id_pipe_o.priv_lvl <= PRIV_LVL_M;
if_id_pipe_o.trigger_match <= 1'b0;
if_id_pipe_o.ptr <= '0;
if_id_pipe_o.last_op <= 1'b0;
if_id_pipe_o.first_op <= 1'b0;
if_id_pipe_o.abort_op <= 1'b0;
end else begin
// Valid pipeline output if we are valid AND the
// alignment buffer has a valid instruction
if (if_valid_o && id_ready_i) begin
if_id_pipe_o.instr_valid <= 1'b1;
if_id_pipe_o.instr_meta <= instr_meta_n;
// seq_valid implies no illegal instruction, sequencer successfully decoded an instruction.
// compressed decoder will still raise illegal_c_insn as it doesn't (currently) recognize Zc push/pop/dmove
if_id_pipe_o.illegal_c_insn <= (seq_valid || dummy_insert) ? 1'b0 : illegal_c_insn;
if_id_pipe_o.priv_lvl <= prefetch_priv_lvl;
if_id_pipe_o.trigger_match <= dummy_insert ? 1'b0 : trigger_match_i;
if_id_pipe_o.last_op <= last_op_o;
if_id_pipe_o.first_op <= first_op;
if_id_pipe_o.abort_op <= abort_op_o;
// No PC update for tablejump pointer, PC of instruction itself is needed later.
// No update to the meta compressed, as this is used in calculating the link address.
// Any pointer could change instr_compressed and cause a wrong link address.
// No update to tbljmp flag, we want flag to be high for both operations.
if (!prefetch_is_tbljmp_ptr) begin
// For mret pointers, the pointer address is only needed downstream if the pointer fetch fails.
// If the pointer fetch is successful, the address of the mret (i.e. the previous PC) is needed.
if(prefetch_is_mret_ptr ?
(instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK) || (instr_decompressed.align_status != ALIGN_OK)) :
1'b1) begin
if_id_pipe_o.pc <= pc_if_o;
end
// Sequenced instructions are marked as illegal by the compressed decoder, however, the instr_compressed
// flag is still set and can be used when propagating to ID.
// Dummy instructions are never marked as compressed or tablejumps.
if_id_pipe_o.instr_meta.compressed <= dummy_insert ? 1'b0 : instr_compressed;
if_id_pipe_o.instr_meta.tbljmp <= dummy_insert ? 1'b0 : seq_tbljmp;
if_id_pipe_o.instr_meta.pushpop <= dummy_insert ? 1'b0 : seq_pushpop;
// Only update compressed_instr for compressed instructions
if (instr_compressed) begin
if_id_pipe_o.compressed_instr <= prefetch_instr.bus_resp.rdata[15:0];
end
end
// For pointers, we want to update the if_id_pipe.ptr field, but also any associated error conditions from bus or MPU.
if (ptr_in_if_o) begin
// Update pointer value
if_id_pipe_o.ptr <= instr_decompressed.bus_resp.rdata;
// Need to update bus error status and mpu status, but may omit the 32-bit instruction word
if_id_pipe_o.instr.bus_resp.err <= instr_decompressed.bus_resp.err;
if_id_pipe_o.instr.mpu_status <= instr_decompressed.mpu_status;
if_id_pipe_o.instr.bus_resp.integrity_err <= instr_decompressed.bus_resp.integrity_err;
if_id_pipe_o.instr.align_status <= instr_decompressed.align_status;
end else begin
// Regular instruction, update the whole instr field
// Dummy instructions replace instruction word with a random instruction word
// Hint instructions are replaced with random instructions within the compressed decoder
if_id_pipe_o.instr <= dummy_insert ? dummy_instr :
seq_valid ? seq_instr : instr_decompressed;
end
end else if (id_ready_i) begin
if_id_pipe_o.instr_valid <= 1'b0;
end
end
end
cv32e40s_compressed_decoder
#(
.ZC_EXT ( ZC_EXT ),
.B_EXT ( B_EXT ),
.M_EXT ( M_EXT )
)
compressed_decoder_i
(
.instr_i ( prefetch_instr ),
.instr_is_ptr_i ( ptr_in_if_o ),
.xsecure_ctrl_i ( xsecure_ctrl_i ),
.hint_replacement_i ( dummy_instr.bus_resp.rdata ), // instruction word for replaced hints
.instr_o ( instr_decompressed ),
.is_compressed_o ( instr_compressed ),
.illegal_instr_o ( illegal_c_insn ),
.hint_o ( instr_hint )
);
// Setting predec_ready to id_ready_i here instead of passing it through the predecoder.
// Predecoder is purely combinatorial and is always ready for new inputs
assign predec_ready = id_ready_i && !dummy_insert;
// Dummies are allowed when first_op_nondummy_o == 1
// If the first operation of a sequence is ready, we allow dummies
// but must not advance the sequencer.
assign id_ready_no_dummy = id_ready_i && !dummy_insert;
// Sequencer gets valid inputs regardless of known error conditions
// Error conditions will cause a 'deassert_we' in the ID stage and exceptions
// will be taken from WB with no side effects performed.
assign seq_instr_valid = prefetch_valid;
generate
if (ZC_EXT) begin : gen_seq
cv32e40s_sequencer
#(.RV32(RV32))
sequencer_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.jvt_mode_i ( jvt_mode_i ),
.instr_i ( prefetch_instr ),
.instr_is_clic_ptr_i ( prefetch_is_clic_ptr ),
.instr_is_mret_ptr_i ( prefetch_is_mret_ptr ),
.instr_is_tbljmp_ptr_i( prefetch_is_tbljmp_ptr ),
.valid_i ( seq_instr_valid ),
.ready_i ( id_ready_no_dummy ),
.halt_i ( ctrl_fsm_i.halt_if ),
.kill_i ( ctrl_fsm_i.kill_if ),
.mstateen0_i ( mstateen0_i ),
.priv_lvl_i ( prefetch_priv_lvl ),
.instr_o ( seq_instr ),
.valid_o ( seq_valid ),
.ready_o ( seq_ready ),
.seq_first_o ( seq_first ),
.seq_last_o ( seq_last ),
.seq_tbljmp_o ( seq_tbljmp ),
.seq_pushpop_o ( seq_pushpop )
);
end else begin : gen_no_seq
assign seq_valid = 1'b0;
assign seq_last = 1'b0;
assign seq_instr = '0;
assign seq_ready = 1'b1;
assign seq_first = 1'b0;
assign seq_tbljmp = 1'b0;
assign seq_pushpop = 1'b0;
end
endgenerate
//---------------------------------------------------------------------------
// Dummy Instruction Insertion
//---------------------------------------------------------------------------
generate
if (DUMMY_INSTRUCTIONS) begin : gen_dummy_instr
logic instr_issued; // Used to count issued instructions between dummy instructions
assign instr_issued = if_valid_o && id_ready_i;
cv32e40s_dummy_instr
dummy_instr_i
(.clk ( clk ),
.rst_n ( rst_n ),
.instr_issued_i ( instr_issued ),
.ctrl_fsm_i ( ctrl_fsm_i ),
.xsecure_ctrl_i ( xsecure_ctrl_i ),
.dummy_insert_o ( dummy_insert ),
.dummy_instr_o ( dummy_instr )
);
end : gen_dummy_instr
else begin : gen_no_dummy_instr
assign dummy_insert = 1'b0;
assign dummy_instr = '0;
end : gen_no_dummy_instr
endgenerate
// Set error outputs
assign integrity_err_o = integrity_err_obi;
assign protocol_err_o = protocol_err_obi || prefetch_protocol_err;
// Some signals are unused on purpose. Use them here for easier LINT waiving.
assign unused_signals = |prefetch_outstnd_cnt_q;
endmodule