In 9.0.1 version of fifoed_avalon_uart, IRQ threshold logic is broke - can cause an interrupt to go away without user handling, which in turn can cause a lockup in the altera_irq_handler (which expects an IRQ, once asserted, to never to go away without a SW action).
Problem is that USED outputs on the internal FIFOs wrap around when FIFO is full. E.g. lets say you use FIFO depths of 128 and TX IRQ threshold of 1 and keep on sending data to the FIFO, the TXREADY interrupt will be de-asserted when FIFO has at least 1 entry but will be re-asserted when FIFO is full (because USED on TX FIFO will transition from 0x7F to 0); at that point IRQ handler will be called. While in the handler, the FIFO will get drained at least one character, USED will transition 0->0x7F and IRQ will be deasserted.
Proper fix is to either use wider USED field on the FIFO (WIDTHU=log2(DEPTH)+1) or to consider FULL flag while looking at USED to determine TXREADY/RXREADY status for generating the interrupt.
Here is the fix to mk_em_uart.pm:
1869c1869,1870
< ([e_signal->new ({name => "tx_almost_empty", never_export => 1}), "tx_used <=$Options->{tx_IRQ_Threshold}" ] )if $Options->{use_tx_fifo};
---
> ([e_signal->new ({name => "tx_almost_empty", never_export => 1}), "(tx_used <=$Options->{tx_IRQ_Threshold}) && tx_not_full" ] )if $Options->{use_tx_fifo};
>
1995c1996
< ([e_signal->new ({name => "rx_at_threshold", never_export => 1}), "(rx_used >=$Options->{rx_IRQ_Threshold}) || timer_timout" ] )if $Options->{use_rx_fifo};
---
> ([e_signal->new ({name => "rx_at_threshold", never_export => 1}), "(rx_used >=$Options->{rx_IRQ_Threshold}) || rx_full || timer_timout" ] )if $Options->{use_rx_fifo};