// Copyright 2017 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. module uart_interrupt #( parameter TX_FIFO_DEPTH = 32, parameter RX_FIFO_DEPTH = 32 ) ( input logic clk_i, input logic rstn_i, // registers input logic [7:0] IER_i, // interrupt enable register input logic RDA_i, // receiver data available input logic overrun_i, // character timeout indication // control logic input logic error_i, input logic [$clog2(RX_FIFO_DEPTH):0] rx_elements_i, input logic [$clog2(TX_FIFO_DEPTH):0] tx_elements_i, input logic [1:0] trigger_level_i, input logic [3:0] clr_int_i, // one hot output logic interrupt_o, output logic [3:0] IIR_o ); logic [3:0] iir_n, iir_q; logic trigger_level_reached; always_comb begin trigger_level_reached = 1'b0; case (trigger_level_i) 2'b00: if ($unsigned(rx_elements_i) == 1) trigger_level_reached = 1'b1; 2'b01: if ($unsigned(rx_elements_i) == 4) trigger_level_reached = 1'b1; 2'b10: if ($unsigned(rx_elements_i) == 8) trigger_level_reached = 1'b1; 2'b11: if ($unsigned(rx_elements_i) == 14) trigger_level_reached = 1'b1; default : /* default */; endcase end always_comb begin iir_n = iir_q; if (clr_int_i == iir_q) iir_n = 4'b0001; if (iir_q == 4'b0100 && (!trigger_level_reached && !RDA_i)) iir_n = 4'b0001; // Parity error if (IER_i[2] & error_i) iir_n = 4'b0110; // Received data available or trigger level reached in FIFO mode else if (IER_i[0] & (trigger_level_reached | RDA_i)) iir_n = 4'b0100; // Overrun error else if (IER_i[4] & overrun_i) iir_n = 4'b1100; // Transmitter holding register empty else if (IER_i[1] & tx_elements_i == 0) iir_n = 4'b0010; end always_ff @(posedge clk_i, negedge rstn_i) begin if (~rstn_i) begin iir_q <= 4'b0001; end else begin iir_q <= iir_n; end end assign IIR_o = iir_q; assign interrupt_o = ~iir_q[0]; endmodule