../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_controller.sv Cov: 95%
1: // Copyright lowRISC contributors.
2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
4: // SPDX-License-Identifier: Apache-2.0
5:
6: /**
7: * Main controller of the processor
8: */
9:
10: `include "prim_assert.sv"
11:
12: module ibex_controller #(
13: parameter bit WritebackStage = 0
14: ) (
15: input logic clk_i,
16: input logic rst_ni,
17:
18: input logic fetch_enable_i, // start decoding
19: output logic ctrl_busy_o, // core is busy processing instrs
20:
21: // decoder related signals
22: input logic illegal_insn_i, // decoder has an invalid instr
23: input logic ecall_insn_i, // decoder has ECALL instr
24: input logic mret_insn_i, // decoder has MRET instr
25: input logic dret_insn_i, // decoder has DRET instr
26: input logic wfi_insn_i, // decoder has WFI instr
27: input logic ebrk_insn_i, // decoder has EBREAK instr
28: input logic csr_pipe_flush_i, // do CSR-related pipeline flush
29:
30: // from IF-ID pipeline stage
31: input logic instr_valid_i, // instr from IF-ID reg is valid
32: input logic [31:0] instr_i, // instr from IF-ID reg, for mtval
33: input logic [15:0] instr_compressed_i, // instr from IF-ID reg, for mtval
34: input logic instr_is_compressed_i, // instr from IF-ID reg is compressed
35: input logic instr_fetch_err_i, // instr from IF-ID reg has error
36: input logic instr_fetch_err_plus2_i, // instr from IF-ID reg error is x32
37: input logic [31:0] pc_id_i, // instr from IF-ID reg address
38:
39: // to IF-ID pipeline stage
40: output logic instr_valid_clear_o, // kill instr in IF-ID reg
41: output logic id_in_ready_o, // ID stage is ready for new instr
42: output logic controller_run_o, // Controller is in standard instruction
43: // run mode
44:
45: // to prefetcher
46: output logic instr_req_o, // start fetching instructions
47: output logic pc_set_o, // jump to address set by pc_mux
48: output logic pc_set_spec_o, // speculative branch
49: output ibex_pkg::pc_sel_e pc_mux_o, // IF stage fetch address selector
50: // (boot, normal, exception...)
51: output ibex_pkg::exc_pc_sel_e exc_pc_mux_o, // IF stage selector for exception PC
52: output ibex_pkg::exc_cause_e exc_cause_o, // for IF stage, CSRs
53:
54: // LSU
55: input logic [31:0] lsu_addr_last_i, // for mtval
56: input logic load_err_i,
57: input logic store_err_i,
58: output logic wb_exception_o, // Instruction in WB taking an exception
59:
60: // jump/branch signals
61: input logic branch_set_i, // branch taken set signal
62: input logic branch_set_spec_i, // speculative branch signal
63: input logic jump_set_i, // jump taken set signal
64:
65: // interrupt signals
66: input logic csr_mstatus_mie_i, // M-mode interrupt enable bit
67: input logic irq_pending_i, // interrupt request pending
68: input ibex_pkg::irqs_t irqs_i, // interrupt requests qualified with
69: // mie CSR
70: input logic irq_nm_i, // non-maskeable interrupt
71: output logic nmi_mode_o, // core executing NMI handler
72:
73: // debug signals
74: input logic debug_req_i,
75: output ibex_pkg::dbg_cause_e debug_cause_o,
76: output logic debug_csr_save_o,
77: output logic debug_mode_o,
78: input logic debug_single_step_i,
79: input logic debug_ebreakm_i,
80: input logic debug_ebreaku_i,
81: input logic trigger_match_i,
82:
83: output logic csr_save_if_o,
84: output logic csr_save_id_o,
85: output logic csr_save_wb_o,
86: output logic csr_restore_mret_id_o,
87: output logic csr_restore_dret_id_o,
88: output logic csr_save_cause_o,
89: output logic [31:0] csr_mtval_o,
90: input ibex_pkg::priv_lvl_e priv_mode_i,
91: input logic csr_mstatus_tw_i,
92:
93: // stall & flush signals
94: input logic lsu_req_in_id_i,
95: input logic stall_id_i,
96: input logic stall_wb_i,
97: output logic flush_id_o,
98: input logic ready_wb_i,
99:
100: // performance monitors
101: output logic perf_jump_o, // we are executing a jump
102: // instruction (j, jr, jal, jalr)
103: output logic perf_tbranch_o // we are executing a taken branch
104: // instruction
105: );
106: import ibex_pkg::*;
107:
108: // FSM state encoding
109: typedef enum logic [3:0] {
110: RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
111: IRQ_TAKEN, DBG_TAKEN_IF, DBG_TAKEN_ID
112: } ctrl_fsm_e;
113:
114: ctrl_fsm_e ctrl_fsm_cs, ctrl_fsm_ns;
115:
116: logic nmi_mode_q, nmi_mode_d;
117: logic debug_mode_q, debug_mode_d;
118: logic load_err_q, load_err_d;
119: logic store_err_q, store_err_d;
120: logic exc_req_q, exc_req_d;
121: logic illegal_insn_q, illegal_insn_d;
122:
123: // Of the various exception/fault signals, which one takes priority in FLUSH and hence controls
124: // what happens next (setting exc_cause, csr_mtval etc)
125: logic instr_fetch_err_prio;
126: logic illegal_insn_prio;
127: logic ecall_insn_prio;
128: logic ebrk_insn_prio;
129: logic store_err_prio;
130: logic load_err_prio;
131:
132: logic stall;
133: logic halt_if;
134: logic retain_id;
135: logic flush_id;
136: logic illegal_dret;
137: logic illegal_umode;
138: logic exc_req_lsu;
139: logic special_req_all;
140: logic special_req_branch;
141: logic enter_debug_mode;
142: logic ebreak_into_debug;
143: logic handle_irq;
144:
145: logic [3:0] mfip_id;
146: logic unused_irq_timer;
147:
148: logic ecall_insn;
149: logic mret_insn;
150: logic dret_insn;
151: logic wfi_insn;
152: logic ebrk_insn;
153: logic csr_pipe_flush;
154: logic instr_fetch_err;
155:
156: `ifndef SYNTHESIS
157: // synopsys translate_off
158: // make sure we are called later so that we do not generate messages for
159: // glitches
160: always_ff @(negedge clk_i) begin
161: // print warning in case of decoding errors
162: if ((ctrl_fsm_cs == DECODE) && instr_valid_i && !instr_fetch_err_i && illegal_insn_d) begin
163: $display("%t: Illegal instruction (hart %0x) at PC 0x%h: 0x%h", $time, ibex_core.hart_id_i,
164: ibex_id_stage.pc_id_i, ibex_id_stage.instr_rdata_i);
165: end
166: end
167: // synopsys translate_on
168: `endif
169:
170: ////////////////
171: // Exceptions //
172: ////////////////
173:
174: assign load_err_d = load_err_i;
175: assign store_err_d = store_err_i;
176:
177: // Decoder doesn't take instr_valid into account, factor it in here.
178: assign ecall_insn = ecall_insn_i & instr_valid_i;
179: assign mret_insn = mret_insn_i & instr_valid_i;
180: assign dret_insn = dret_insn_i & instr_valid_i;
181: assign wfi_insn = wfi_insn_i & instr_valid_i;
182: assign ebrk_insn = ebrk_insn_i & instr_valid_i;
183: assign csr_pipe_flush = csr_pipe_flush_i & instr_valid_i;
184: assign instr_fetch_err = instr_fetch_err_i & instr_valid_i;
185:
186: // "Executing DRET outside of Debug Mode causes an illegal instruction exception."
187: // [Debug Spec v0.13.2, p.41]
188: assign illegal_dret = dret_insn & ~debug_mode_q;
189:
190: // Some instructions can only be executed in M-Mode
191: assign illegal_umode = (priv_mode_i != PRIV_LVL_M) &
192: // MRET must be in M-Mode. TW means trap WFI to M-Mode.
193: (mret_insn | (csr_mstatus_tw_i & wfi_insn));
194:
195: // This is recorded in the illegal_insn_q flop to help timing. Specifically
196: // it is needed to break the path from ibex_cs_registers/illegal_csr_insn_o
197: // to pc_set_o. Clear when controller is in FLUSH so it won't remain set
198: // once illegal instruction is handled.
199: // All terms in this expression are qualified by instr_valid_i
200: assign illegal_insn_d = (illegal_insn_i | illegal_dret | illegal_umode) & (ctrl_fsm_cs != FLUSH);
201:
202: // exception requests
203: // requests are flopped in exc_req_q. This is cleared when controller is in
204: // the FLUSH state so the cycle following exc_req_q won't remain set for an
205: // exception request that has just been handled.
206: // All terms in this expression are qualified by instr_valid_i
207: assign exc_req_d = (ecall_insn | ebrk_insn | illegal_insn_d | instr_fetch_err) &
208: (ctrl_fsm_cs != FLUSH);
209:
210: // LSU exception requests
211: assign exc_req_lsu = store_err_i | load_err_i;
212:
213:
214: // special requests: special instructions, pipeline flushes, exceptions...
215:
216: // To avoid creating a path from data_err_i -> instr_req_o and to help timing the below
217: // special_req_all has a version that only applies to branches. For a branch the controller needs
218: // to set pc_set_o but only if there is no special request. If the generic special_req_all signal
219: // is used then a variety of signals that will never cause a special request during a branch
220: // instruction end up factored into pc_set_o. The special_req_branch only considers the special
221: // request reasons that are relevant to a branch.
222:
223: // generic special request signal, applies to all instructions
224: // All terms in this expression are qualified by instr_valid_i except exc_req_lsu which can come
225: // from the Writeback stage with no instr_valid_i from the ID stage
226: assign special_req_all = mret_insn | dret_insn | wfi_insn | csr_pipe_flush |
227: exc_req_d | exc_req_lsu;
228:
229: // special request that can specifically occur during branch instructions
230: // All terms in this expression are qualified by instr_valid_i
231: assign special_req_branch = instr_fetch_err & (ctrl_fsm_cs != FLUSH);
232:
233: `ASSERT(SpecialReqBranchGivesSpecialReqAll,
234: special_req_branch |-> special_req_all)
235:
236: `ASSERT(SpecialReqAllGivesSpecialReqBranchIfBranchInst,
237: special_req_all && (branch_set_i || jump_set_i) |-> special_req_branch)
238:
239: // Exception/fault prioritisation is taken from Table 3.7 of Priviledged Spec v1.11
240: if (WritebackStage) begin : g_wb_exceptions
241: always_comb begin
242: instr_fetch_err_prio = 0;
243: illegal_insn_prio = 0;
244: ecall_insn_prio = 0;
245: ebrk_insn_prio = 0;
246: store_err_prio = 0;
247: load_err_prio = 0;
248:
249: // Note that with the writeback stage store/load errors occur on the instruction in writeback,
250: // all other exception/faults occur on the instruction in ID/EX. The faults from writeback
251: // must take priority as that instruction is architecurally ordered before the one in ID/EX.
252: if (store_err_q) begin
253: store_err_prio = 1'b1;
254: end else if (load_err_q) begin
255: load_err_prio = 1'b1;
256: end else if (instr_fetch_err) begin
257: instr_fetch_err_prio = 1'b1;
258: end else if (illegal_insn_q) begin
259: illegal_insn_prio = 1'b1;
260: end else if (ecall_insn) begin
261: ecall_insn_prio = 1'b1;
262: end else if (ebrk_insn) begin
263: ebrk_insn_prio = 1'b1;
264: end
265: end
266:
267: // Instruction in writeback is generating an exception so instruction in ID must not execute
268: assign wb_exception_o = load_err_q | store_err_q | load_err_i | store_err_i;
269: end else begin : g_no_wb_exceptions
270: always_comb begin
271: instr_fetch_err_prio = 0;
272: illegal_insn_prio = 0;
273: ecall_insn_prio = 0;
274: ebrk_insn_prio = 0;
275: store_err_prio = 0;
276: load_err_prio = 0;
277:
278: if (instr_fetch_err) begin
279: instr_fetch_err_prio = 1'b1;
280: end else if (illegal_insn_q) begin
281: illegal_insn_prio = 1'b1;
282: end else if (ecall_insn) begin
283: ecall_insn_prio = 1'b1;
284: end else if (ebrk_insn) begin
285: ebrk_insn_prio = 1'b1;
286: end else if (store_err_q) begin
287: store_err_prio = 1'b1;
288: end else if (load_err_q) begin
289: load_err_prio = 1'b1;
290: end
291: end
292: assign wb_exception_o = 1'b0;
293: end
294:
295: `ASSERT_IF(IbexExceptionPrioOnehot,
296: $onehot({instr_fetch_err_prio,
297: illegal_insn_prio,
298: ecall_insn_prio,
299: ebrk_insn_prio,
300: store_err_prio,
301: load_err_prio}),
302: (ctrl_fsm_cs == FLUSH) & exc_req_q);
303:
304: ////////////////
305: // Interrupts //
306: ////////////////
307:
308: // Enter debug mode due to an external debug_req_i or because the core is in
309: // single step mode (dcsr.step == 1). Single step must be qualified with
310: // instruction valid otherwise the core will immediately enter debug mode
311: // due to a recently flushed IF (or a delay in an instruction returning from
312: // memory) before it has had anything to single step.
313: // Also enter debug mode on a trigger match (hardware breakpoint)
314: assign enter_debug_mode = (debug_req_i | (debug_single_step_i & instr_valid_i) |
315: trigger_match_i) & ~debug_mode_q;
316:
317: // Set when an ebreak should enter debug mode rather than jump to exception
318: // handler
319: assign ebreak_into_debug = priv_mode_i == PRIV_LVL_M ? debug_ebreakm_i :
320: priv_mode_i == PRIV_LVL_U ? debug_ebreaku_i :
321: 1'b0;
322:
323: // Interrupts including NMI are ignored,
324: // - while in debug mode [Debug Spec v0.13.2, p.39],
325: // - while in NMI mode (nested NMIs are not supported, NMI has highest priority and
326: // cannot be interrupted by regular interrupts).
327: assign handle_irq = ~debug_mode_q & ~nmi_mode_q &
328: (irq_nm_i | (irq_pending_i & csr_mstatus_mie_i));
329:
330: // generate ID of fast interrupts, highest priority to highest ID
331: always_comb begin : gen_mfip_id
332: if (irqs_i.irq_fast[14]) mfip_id = 4'd14;
333: else if (irqs_i.irq_fast[13]) mfip_id = 4'd13;
334: else if (irqs_i.irq_fast[12]) mfip_id = 4'd12;
335: else if (irqs_i.irq_fast[11]) mfip_id = 4'd11;
336: else if (irqs_i.irq_fast[10]) mfip_id = 4'd10;
337: else if (irqs_i.irq_fast[ 9]) mfip_id = 4'd9;
338: else if (irqs_i.irq_fast[ 8]) mfip_id = 4'd8;
339: else if (irqs_i.irq_fast[ 7]) mfip_id = 4'd7;
340: else if (irqs_i.irq_fast[ 6]) mfip_id = 4'd6;
341: else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
342: else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
343: else if (irqs_i.irq_fast[ 4]) mfip_id = 4'd4;
344: else if (irqs_i.irq_fast[ 3]) mfip_id = 4'd3;
345: else if (irqs_i.irq_fast[ 2]) mfip_id = 4'd2;
346: else if (irqs_i.irq_fast[ 1]) mfip_id = 4'd1;
347: else mfip_id = 4'd0;
348: end
349:
350: assign unused_irq_timer = irqs_i.irq_timer;
351:
352: /////////////////////
353: // Core controller //
354: /////////////////////
355:
356: always_comb begin
357: // Default values
358: instr_req_o = 1'b1;
359:
360: csr_save_if_o = 1'b0;
361: csr_save_id_o = 1'b0;
362: csr_save_wb_o = 1'b0;
363: csr_restore_mret_id_o = 1'b0;
364: csr_restore_dret_id_o = 1'b0;
365: csr_save_cause_o = 1'b0;
366: csr_mtval_o = '0;
367:
368: // The values of pc_mux and exc_pc_mux are only relevant if pc_set is set. Some of the states
369: // below always set pc_mux and exc_pc_mux but only set pc_set if certain conditions are met.
370: // This avoid having to factor those conditions into the pc_mux and exc_pc_mux select signals
371: // helping timing.
372: pc_mux_o = PC_BOOT;
373: pc_set_o = 1'b0;
374: pc_set_spec_o = 1'b0;
375:
376: exc_pc_mux_o = EXC_PC_IRQ;
377: exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00
378:
379: ctrl_fsm_ns = ctrl_fsm_cs;
380:
381: ctrl_busy_o = 1'b1;
382:
383: halt_if = 1'b0;
384: retain_id = 1'b0;
385: flush_id = 1'b0;
386:
387: debug_csr_save_o = 1'b0;
388: debug_cause_o = DBG_CAUSE_EBREAK;
389: debug_mode_d = debug_mode_q;
390: nmi_mode_d = nmi_mode_q;
391:
392: perf_tbranch_o = 1'b0;
393: perf_jump_o = 1'b0;
394:
395: controller_run_o = 1'b0;
396:
397: unique case (ctrl_fsm_cs)
398: RESET: begin
399: // just wait for fetch_enable
400: instr_req_o = 1'b0;
401: pc_mux_o = PC_BOOT;
402: pc_set_o = 1'b1;
403: pc_set_spec_o = 1'b1;
404: if (fetch_enable_i) begin
405: ctrl_fsm_ns = BOOT_SET;
406: end
407: end
408:
409: BOOT_SET: begin
410: // copy boot address to instr fetch address
411: instr_req_o = 1'b1;
412: pc_mux_o = PC_BOOT;
413: pc_set_o = 1'b1;
414: pc_set_spec_o = 1'b1;
415:
416: ctrl_fsm_ns = FIRST_FETCH;
417: end
418:
419: WAIT_SLEEP: begin
420: ctrl_busy_o = 1'b0;
421: instr_req_o = 1'b0;
422: halt_if = 1'b1;
423: flush_id = 1'b1;
424: ctrl_fsm_ns = SLEEP;
425: end
426:
427: SLEEP: begin
428: // instruction in IF stage is already valid
429: // we begin execution when an interrupt has arrived
430: instr_req_o = 1'b0;
431: halt_if = 1'b1;
432: flush_id = 1'b1;
433:
434: // normal execution flow
435: // in debug mode or single step mode we leave immediately (wfi=nop)
436: if (irq_nm_i || irq_pending_i || debug_req_i || debug_mode_q || debug_single_step_i) begin
437: ctrl_fsm_ns = FIRST_FETCH;
438: end else begin
439: // Make sure clock remains disabled.
440: ctrl_busy_o = 1'b0;
441: end
442: end
443:
444: FIRST_FETCH: begin
445: // Stall because of IF miss
446: if (id_in_ready_o) begin
447: ctrl_fsm_ns = DECODE;
448: end
449:
450: // handle interrupts
451: if (handle_irq) begin
452: // We are handling an interrupt. Set halt_if to tell IF not to give
453: // us any more instructions before it redirects to the handler, but
454: // don't set flush_id: we must allow this instruction to complete
455: // (since it might have outstanding loads or stores).
456: ctrl_fsm_ns = IRQ_TAKEN;
457: halt_if = 1'b1;
458: end
459:
460: // enter debug mode
461: if (enter_debug_mode) begin
462: ctrl_fsm_ns = DBG_TAKEN_IF;
463: // Halt IF only for now, ID will be flushed in DBG_TAKEN_IF as the
464: // ID state is needed for correct debug mode entry
465: halt_if = 1'b1;
466: end
467: end
468:
469: DECODE: begin
470: // normal operating mode of the ID stage, in case of debug and interrupt requests,
471: // priorities are as follows (lower number == higher priority)
472: // 1. currently running (multicycle) instructions and exceptions caused by these
473: // 2. debug requests
474: // 3. interrupt requests
475:
476: controller_run_o = 1'b1;
477:
478: // Set PC mux for branch and jump here to ease timing. Value is only relevant if pc_set_o is
479: // also set. Setting the mux value here avoids factoring in special_req and instr_valid_i
480: // which helps timing.
481: pc_mux_o = PC_JUMP;
482:
483:
484: // Get ready for special instructions, exceptions, pipeline flushes
485: if (special_req_all) begin
486: // Halt IF but don't flush ID. This leaves a valid instruction in
487: // ID so controller can determine appropriate action in the
488: // FLUSH state.
489: retain_id = 1'b1;
490:
491: // Wait for the writeback stage to either be ready for a new instruction or raise its own
492: // exception before going to FLUSH. If the instruction in writeback raises an exception it
493: // must take priority over any exception from an instruction in ID/EX. Only once the
494: // writeback stage is ready can we be certain that won't happen. Without a writeback
495: // stage ready_wb_i == 1 so the FSM will always go directly to FLUSH.
496:
497: if (ready_wb_i | wb_exception_o) begin
498: ctrl_fsm_ns = FLUSH;
499: end
500: end
501:
502: if ((branch_set_i || jump_set_i) && !special_req_branch) begin
503: pc_set_o = 1'b1;
504:
505: perf_tbranch_o = branch_set_i;
506: perf_jump_o = jump_set_i;
507: end
508:
509: // pc_set signal excluding branch taken condition
510: if ((branch_set_spec_i || jump_set_i) && !special_req_branch) begin
511: pc_set_spec_o = 1'b1;
512: end
513:
514: // If entering debug mode or handling an IRQ the core needs to wait
515: // until the current instruction has finished executing. Stall IF
516: // during that time.
517: if ((enter_debug_mode || handle_irq) && (stall || lsu_req_in_id_i)) begin
518: halt_if = 1'b1;
519: end
520:
521: if (!stall && !lsu_req_in_id_i && !special_req_all) begin
522: if (enter_debug_mode) begin
523: // enter debug mode
524: ctrl_fsm_ns = DBG_TAKEN_IF;
525: // Halt IF only for now, ID will be flushed in DBG_TAKEN_IF as the
526: // ID state is needed for correct debug mode entry
527: halt_if = 1'b1;
528: end else if (handle_irq) begin
529: // handle interrupt (not in debug mode)
530: ctrl_fsm_ns = IRQ_TAKEN;
531: // We are handling an interrupt (not in debug mode). Set halt_if to
532: // tell IF not to give us any more instructions before it redirects
533: // to the handler, but don't set flush_id: we must allow this
534: // instruction to complete (since it might have outstanding loads
535: // or stores).
536: halt_if = 1'b1;
537: end
538: end
539:
540: end // DECODE
541:
542: IRQ_TAKEN: begin
543: pc_mux_o = PC_EXC;
544: exc_pc_mux_o = EXC_PC_IRQ;
545:
546: if (handle_irq) begin
547: pc_set_o = 1'b1;
548: pc_set_spec_o = 1'b1;
549:
550: csr_save_if_o = 1'b1;
551: csr_save_cause_o = 1'b1;
552:
553: // interrupt priorities according to Privileged Spec v1.11 p.31
554: if (irq_nm_i && !nmi_mode_q) begin
555: exc_cause_o = EXC_CAUSE_IRQ_NM;
556: nmi_mode_d = 1'b1; // enter NMI mode
557: end else if (irqs_i.irq_fast != 15'b0) begin
558: // generate exception cause ID from fast interrupt ID:
559: // - first bit distinguishes interrupts from exceptions,
560: // - second bit adds 16 to fast interrupt ID
561: // for example EXC_CAUSE_IRQ_FAST_0 = {1'b1, 5'd16}
562: exc_cause_o = exc_cause_e'({2'b11, mfip_id});
563: end else if (irqs_i.irq_external) begin
564: exc_cause_o = EXC_CAUSE_IRQ_EXTERNAL_M;
565: end else if (irqs_i.irq_software) begin
566: exc_cause_o = EXC_CAUSE_IRQ_SOFTWARE_M;
567: end else begin // irqs_i.irq_timer
568: exc_cause_o = EXC_CAUSE_IRQ_TIMER_M;
569: end
570: end
571:
572: ctrl_fsm_ns = DECODE;
573: end
574:
575: DBG_TAKEN_IF: begin
576: pc_mux_o = PC_EXC;
577: exc_pc_mux_o = EXC_PC_DBD;
578:
579: // enter debug mode and save PC in IF to dpc
580: // jump to debug exception handler in debug memory
581: if (debug_single_step_i || debug_req_i || trigger_match_i) begin
582: flush_id = 1'b1;
583: pc_set_o = 1'b1;
584: pc_set_spec_o = 1'b1;
585:
586: csr_save_if_o = 1'b1;
587: debug_csr_save_o = 1'b1;
588:
589: csr_save_cause_o = 1'b1;
590: if (trigger_match_i) begin
591: debug_cause_o = DBG_CAUSE_TRIGGER;
592: end else if (debug_single_step_i) begin
593: debug_cause_o = DBG_CAUSE_STEP;
594: end else begin
595: debug_cause_o = DBG_CAUSE_HALTREQ;
596: end
597:
598: // enter debug mode
599: debug_mode_d = 1'b1;
600: end
601:
602: ctrl_fsm_ns = DECODE;
603: end
604:
605: DBG_TAKEN_ID: begin
606: // enter debug mode and save PC in ID to dpc, used when encountering
607: // 1. EBREAK during debug mode
608: // 2. EBREAK with forced entry into debug mode (ebreakm or ebreaku set).
609: // regular ebreak's go through FLUSH.
610: //
611: // for 1. do not update dcsr and dpc, for 2. do so [Debug Spec v0.13.2, p.39]
612: // jump to debug exception handler in debug memory
613: flush_id = 1'b1;
614: pc_mux_o = PC_EXC;
615: pc_set_o = 1'b1;
616: pc_set_spec_o = 1'b1;
617: exc_pc_mux_o = EXC_PC_DBD;
618:
619: // update dcsr and dpc
620: if (ebreak_into_debug && !debug_mode_q) begin // ebreak with forced entry
621:
622: // dpc (set to the address of the EBREAK, i.e. set to PC in ID stage)
623: csr_save_cause_o = 1'b1;
624: csr_save_id_o = 1'b1;
625:
626: // dcsr
627: debug_csr_save_o = 1'b1;
628: debug_cause_o = DBG_CAUSE_EBREAK;
629: end
630:
631: // enter debug mode
632: debug_mode_d = 1'b1;
633:
634: ctrl_fsm_ns = DECODE;
635: end
636:
637: FLUSH: begin
638: // flush the pipeline
639: halt_if = 1'b1;
640: flush_id = 1'b1;
641: ctrl_fsm_ns = DECODE;
642:
643: // As pc_mux and exc_pc_mux can take various values in this state they aren't set early
644: // here.
645:
646: // exceptions: set exception PC, save PC and exception cause
647: // exc_req_lsu is high for one clock cycle only (in DECODE)
648: if (exc_req_q || store_err_q || load_err_q) begin
649: pc_set_o = 1'b1;
650: pc_set_spec_o = 1'b1;
651: pc_mux_o = PC_EXC;
652: exc_pc_mux_o = debug_mode_q ? EXC_PC_DBG_EXC : EXC_PC_EXC;
653:
654: if (WritebackStage) begin : g_writeback_mepc_save
655: // With the writeback stage present whether an instruction accessing memory will cause
656: // an exception is only known when it is in writeback. So when taking such an exception
657: // epc must come from writeback.
658: csr_save_id_o = ~(store_err_q | load_err_q);
659: csr_save_wb_o = store_err_q | load_err_q;
660: end else begin : g_no_writeback_mepc_save
661: csr_save_id_o = 1'b0;
662: end
663:
664: csr_save_cause_o = 1'b1;
665:
666: // Exception/fault prioritisation logic will have set exactly 1 X_prio signal
667: unique case (1'b1)
668: instr_fetch_err_prio: begin
669: exc_cause_o = EXC_CAUSE_INSTR_ACCESS_FAULT;
670: csr_mtval_o = instr_fetch_err_plus2_i ? (pc_id_i + 32'd2) : pc_id_i;
671: end
672: illegal_insn_prio: begin
673: exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
674: csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i;
675: end
676: ecall_insn_prio: begin
677: exc_cause_o = (priv_mode_i == PRIV_LVL_M) ? EXC_CAUSE_ECALL_MMODE :
678: EXC_CAUSE_ECALL_UMODE;
679: end
680: ebrk_insn_prio: begin
681: if (debug_mode_q | ebreak_into_debug) begin
682: /*
683: * EBREAK in debug mode re-enters debug mode
684: *
685: * "The only exception is EBREAK. When that is executed in Debug
686: * Mode, it halts the hart again but without updating dpc or
687: * dcsr." [Debug Spec v0.13.2, p.39]
688: */
689:
690: /*
691: * dcsr.ebreakm == 1:
692: * "EBREAK instructions in M-mode enter Debug Mode."
693: * [Debug Spec v0.13.2, p.42]
694: */
695: pc_set_o = 1'b0;
696: pc_set_spec_o = 1'b0;
697: csr_save_id_o = 1'b0;
698: csr_save_cause_o = 1'b0;
699: ctrl_fsm_ns = DBG_TAKEN_ID;
700: flush_id = 1'b0;
701: end else begin
702: /*
703: * "The EBREAK instruction is used by debuggers to cause control
704: * to be transferred back to a debugging environment. It
705: * generates a breakpoint exception and performs no other
706: * operation. [...] ECALL and EBREAK cause the receiving
707: * privilege mode's epc register to be set to the address of the
708: * ECALL or EBREAK instruction itself, not the address of the
709: * following instruction." [Privileged Spec v1.11, p.40]
710: */
711: exc_cause_o = EXC_CAUSE_BREAKPOINT;
712: end
713: end
714: store_err_prio: begin
715: exc_cause_o = EXC_CAUSE_STORE_ACCESS_FAULT;
716: csr_mtval_o = lsu_addr_last_i;
717: end
718: load_err_prio: begin
719: exc_cause_o = EXC_CAUSE_LOAD_ACCESS_FAULT;
720: csr_mtval_o = lsu_addr_last_i;
721: end
722: endcase
723: end else begin
724: // special instructions and pipeline flushes
725: if (mret_insn) begin
726: pc_mux_o = PC_ERET;
727: pc_set_o = 1'b1;
728: pc_set_spec_o = 1'b1;
729: csr_restore_mret_id_o = 1'b1;
730: if (nmi_mode_q) begin
731: nmi_mode_d = 1'b0; // exit NMI mode
732: end
733: end else if (dret_insn) begin
734: pc_mux_o = PC_DRET;
735: pc_set_o = 1'b1;
736: pc_set_spec_o = 1'b1;
737: debug_mode_d = 1'b0;
738: csr_restore_dret_id_o = 1'b1;
739: end else if (wfi_insn) begin
740: ctrl_fsm_ns = WAIT_SLEEP;
741: end else if (csr_pipe_flush && handle_irq) begin
742: // start handling IRQs when doing CSR-related pipeline flushes
743: ctrl_fsm_ns = IRQ_TAKEN;
744: end
745: end // exc_req_q
746:
747: // Entering debug mode due to either single step or debug_req. Ensure
748: // registers are set for exception but then enter debug handler rather
749: // than exception handler [Debug Spec v0.13.2, p.44]
750: // Leave all other signals as is to ensure CSRs and PC get set as if
751: // core was entering exception handler, entry to debug mode will then
752: // see the appropriate state and setup dpc correctly.
753: if (enter_debug_mode) begin
754: ctrl_fsm_ns = DBG_TAKEN_IF;
755: end
756: end // FLUSH
757:
758: default: begin
759: instr_req_o = 1'b0;
760: ctrl_fsm_ns = RESET;
761: end
762: endcase
763: end
764:
765: assign flush_id_o = flush_id;
766:
767: // signal to CSR when in debug mode
768: assign debug_mode_o = debug_mode_q;
769:
770: // signal to CSR when in an NMI handler (for nested exception handling)
771: assign nmi_mode_o = nmi_mode_q;
772:
773: ///////////////////
774: // Stall control //
775: ///////////////////
776:
777: // If high current instruction cannot complete this cycle. Either because it needs more cycles to
778: // finish (stall_id_i) or because the writeback stage cannot accept it yet (stall_wb_i). If there
779: // is no writeback stage stall_wb_i is a constant 0.
780: assign stall = stall_id_i | stall_wb_i;
781:
782: // signal to IF stage that ID stage is ready for next instr
783: assign id_in_ready_o = ~stall & ~halt_if & ~retain_id;
784:
785: // kill instr in IF-ID pipeline reg that are done, or if a
786: // multicycle instr causes an exception for example
787: // retain_id is another kind of stall, where the instr_valid bit must remain
788: // set (unless flush_id is set also). It cannot be factored directly into
789: // stall as this causes a combinational loop.
790: assign instr_valid_clear_o = ~(stall | retain_id) | flush_id;
791:
792: // update registers
793: always_ff @(posedge clk_i or negedge rst_ni) begin : update_regs
794: if (!rst_ni) begin
795: ctrl_fsm_cs <= RESET;
796: nmi_mode_q <= 1'b0;
797: debug_mode_q <= 1'b0;
798: load_err_q <= 1'b0;
799: store_err_q <= 1'b0;
800: exc_req_q <= 1'b0;
801: illegal_insn_q <= 1'b0;
802: end else begin
803: ctrl_fsm_cs <= ctrl_fsm_ns;
804: nmi_mode_q <= nmi_mode_d;
805: debug_mode_q <= debug_mode_d;
806: load_err_q <= load_err_d;
807: store_err_q <= store_err_d;
808: exc_req_q <= exc_req_d;
809: illegal_insn_q <= illegal_insn_d;
810: end
811: end
812:
813: ////////////////
814: // Assertions //
815: ////////////////
816:
817: // Selectors must be known/valid.
818: `ASSERT(IbexCtrlStateValid, ctrl_fsm_cs inside {
819: RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
820: IRQ_TAKEN, DBG_TAKEN_IF, DBG_TAKEN_ID})
821:
822: // The speculative branch signal should be set whenever the actual branch signal is set
823: `ASSERT(IbexSpecImpliesSetPC, pc_set_o |-> pc_set_spec_o)
824:
825: endmodule
826: