Files
FPGA_DESIGN_IP/apb_uart/uart_interrupt.sv
2026-03-06 16:22:17 +08:00

101 lines
3.1 KiB
Systemverilog

// 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