| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Description: interface between a req/ack interface and a fifo |
| // |
| |
| module edn_ack_sm ( |
| input logic clk_i, |
| input logic rst_ni, |
| |
| input logic enable_i, |
| input logic req_i, |
| output logic ack_o, |
| input logic local_escalate_i, |
| input logic fifo_not_empty_i, |
| output logic fifo_pop_o, |
| output logic fifo_clr_o, |
| output logic ack_sm_err_o |
| ); |
| |
| // Encoding generated with: |
| // $ ./util/design/sparse-fsm-encode.py -d 3 -m 4 -n 6 \ |
| // -s 2299232677 --language=sv |
| // |
| // Hamming distance histogram: |
| // |
| // 0: -- |
| // 1: -- |
| // 2: -- |
| // 3: |||||||||||||||||||| (50.00%) |
| // 4: ||||||||||||| (33.33%) |
| // 5: |||||| (16.67%) |
| // 6: -- |
| // |
| // Minimum Hamming distance: 3 |
| // Maximum Hamming distance: 5 |
| // Minimum Hamming weight: 1 |
| // Maximum Hamming weight: 4 |
| // |
| localparam int StateWidth = 9; |
| typedef enum logic [StateWidth-1:0] { |
| Disabled = 9'b100110010, // Disabled |
| EndPointClear = 9'b110001110, // Clear out end point before beginning |
| Idle = 9'b001011100, // idle (hamming distance = 3) |
| DataWait = 9'b011101011, // wait for data to return |
| AckPls = 9'b000100101, // signal ack to endpoint |
| Error = 9'b111010001 // illegal state reached and hang |
| } state_e; |
| state_e state_d, state_q; |
| |
| `PRIM_FLOP_SPARSE_FSM(u_state_regs, state_d, state_q, state_e, Disabled) |
| |
| always_comb begin |
| state_d = state_q; |
| ack_o = 1'b0; |
| fifo_clr_o = 1'b0; |
| fifo_pop_o = 1'b0; |
| ack_sm_err_o = 1'b0; |
| unique case (state_q) |
| Disabled: begin |
| if (enable_i) begin |
| state_d = EndPointClear; |
| fifo_clr_o = 1'b1; |
| end |
| end |
| EndPointClear: begin |
| state_d = Idle; |
| end |
| Idle: begin |
| if (req_i) begin |
| if (fifo_not_empty_i) begin |
| fifo_pop_o = 1'b1; |
| end |
| state_d = DataWait; |
| end |
| end |
| DataWait: begin |
| if (fifo_not_empty_i) begin |
| state_d = AckPls; |
| end |
| end |
| AckPls: begin |
| ack_o = 1'b1; |
| state_d = Idle; |
| end |
| Error: begin |
| ack_sm_err_o = 1'b1; |
| end |
| default: begin |
| ack_sm_err_o = 1'b1; |
| state_d = Error; |
| end |
| endcase // unique case (state_q) |
| |
| // If local escalation is seen, transition directly to |
| // error state. |
| if (local_escalate_i) begin |
| state_d = Error; |
| // Tie off outputs, except for ack_sm_err_o. |
| ack_o = 1'b0; |
| fifo_clr_o = 1'b0; |
| fifo_pop_o = 1'b0; |
| end else if (!enable_i && state_q inside {EndPointClear, Idle, DataWait, AckPls}) begin |
| // Only disable if state is legal and not Disabled or Error. |
| // Even when disabled, illegal states must result in a transition to Error. |
| state_d = Disabled; |
| // Tie off all outputs, except for ack_sm_err_o. |
| ack_o = 1'b0; |
| fifo_pop_o = 1'b0; |
| fifo_clr_o = 1'b0; |
| end |
| end |
| |
| // The `local_escalate_i` includes `ack_sm_err_o`. |
| // The following assertion ensures the Error state is stable until reset. |
| // With `FpvSecCm` prefix, this assertion will added to weekly FPV sec_cm regression. |
| `ASSERT(FpvSecCmErrorStEscalate_A, state_q == Error |-> local_escalate_i) |
| |
| // This assertion does not have `FpvSecCm` prefix because the sec_cm FPV environment will |
| // blackbox the `prim_sparse_fsm` `state_q` output. |
| `ASSERT(AckSmErrorStStable_A, state_q == Error |=> $stable(state_q)) |
| |
| endmodule |