OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1501 to Rev 1502
    Reverse comparison

Rev 1501 → Rev 1502

/trunk/or1ksim/peripheral/16450.c
58,6 → 58,7
void uart_check_char(void *dat);
static void uart_sched_recv_check(struct dev_16450 *uart);
static void uart_vapi_cmd(void *dat);
static void uart_clear_int(struct dev_16450 *uart, int intr);
void uart_tx_send(void *dat);
 
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
84,6 → 85,189
return (char_clks * bauds_per_char) >> 1;
}
 
/*---------------------------------------------------[ Interrupt handling ]---*/
/* Signals the specified interrupt. If a higher priority interrupt is already
* pending, do nothing */
static void uart_int_msi(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.ints |= 1 << UART_IIR_MSI;
 
if(!(uart->regs.ier & UART_IER_MSI))
return;
 
if((uart->regs.iir & UART_IIR_NO_INT) || (uart->regs.iir == UART_IIR_MSI)) {
TRACE("Raiseing modem status interrupt\n");
uart_clear_int(uart, uart->regs.iir);
 
uart->regs.iir = UART_IIR_MSI;
SCHED_ADD(uart_int_msi, dat, UART_CLOCK_DIVIDER);
report_interrupt(uart->irq);
}
}
 
static void uart_int_thri(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.ints |= 1 << UART_IIR_THRI;
 
if(!(uart->regs.ier & UART_IER_THRI))
return;
 
if((uart->regs.iir & UART_IIR_NO_INT) || (uart->regs.iir == UART_IIR_MSI) ||
(uart->regs.iir == UART_IIR_THRI)) {
TRACE("Raiseing transmitter holding register interrupt\n");
uart_clear_int(uart, uart->regs.iir);
 
uart->regs.iir = UART_IIR_THRI;
SCHED_ADD(uart_int_thri, dat, UART_CLOCK_DIVIDER);
report_interrupt(uart->irq);
}
}
 
static void uart_int_cti(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.ints |= 1 << UART_IIR_CTI;
 
if(!(uart->regs.ier & UART_IER_RDI))
return;
 
if((uart->regs.iir != UART_IIR_RLSI) && (uart->regs.iir != UART_IIR_RDI)) {
TRACE("Raiseing character timeout interrupt\n");
uart_clear_int(uart, uart->regs.iir);
 
uart->regs.iir = UART_IIR_CTI;
SCHED_ADD(uart_int_cti, dat, UART_CLOCK_DIVIDER);
report_interrupt(uart->irq);
}
}
 
static void uart_int_rdi(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.ints |= 1 << UART_IIR_RDI;
 
if(!(uart->regs.ier & UART_IER_RDI))
return;
 
if(uart->regs.iir != UART_IIR_RLSI) {
TRACE("Raiseing receiver data interrupt\n");
uart_clear_int(uart, uart->regs.iir);
 
uart->regs.iir = UART_IIR_RDI;
SCHED_ADD(uart_int_rdi, dat, UART_CLOCK_DIVIDER);
report_interrupt(uart->irq);
}
}
 
static void uart_int_rlsi(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.ints |= 1 << UART_IIR_RLSI;
 
if(!(uart->regs.ier & UART_IER_RLSI))
return;
 
uart_clear_int(uart, uart->regs.iir);
 
TRACE("Raiseing receiver line status interrupt\n");
 
/* Highest priority interrupt */
uart->regs.iir = UART_IIR_RLSI;
SCHED_ADD(uart_int_rlsi, dat, UART_CLOCK_DIVIDER);
report_interrupt(uart->irq);
}
 
/* Checks to see if an RLSI interrupt is due and schedules one if need be */
static void uart_check_rlsi(void *dat)
{
struct dev_16450 *uart = dat;
 
if(uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY | UART_LSR_FRAME |
UART_LSR_BREAK))
uart_int_rlsi(uart);
}
 
/* Checks to see if an RDI interrupt is due and schedules one if need be */
static void uart_check_rdi(void *dat)
{
struct dev_16450 *uart = dat;
 
if(uart->istat.rxbuf_full >= UART_FIFO_TRIGGER(uart->regs.fcr >> 6))
uart_int_rdi(uart);
}
 
/* Raises the next highest priority interrupt */
static void uart_next_int(void *dat)
{
struct dev_16450 *uart = dat;
 
/* Interrupt detection in proper priority order. */
if((uart->istat.ints & (1 << UART_IIR_RLSI)) &&
(uart->regs.ier & UART_IER_RLSI))
uart_int_rlsi(uart);
else if((uart->istat.ints & (1 << UART_IIR_RDI)) &&
(uart->regs.ier & UART_IER_RDI))
uart_int_rdi(uart);
else if((uart->istat.ints & (1 << UART_IIR_CTI)) &&
(uart->regs.ier & UART_IER_RDI))
uart_int_cti(uart);
else if((uart->istat.ints & (1 << UART_IIR_THRI)) &&
(uart->regs.ier & UART_IER_THRI))
uart_int_thri(uart);
else if((uart->istat.ints & (1 << UART_IIR_MSI)) &&
(uart->regs.ier & UART_IER_MSI))
uart_int_msi(uart);
else
uart->regs.iir = UART_IIR_NO_INT;
}
 
/* Clears potentially pending interrupts */
static void uart_clear_int(struct dev_16450 *uart, int intr)
{
uart->istat.ints &= ~(1 << intr);
 
/* Short-circuit most likely case */
if(uart->regs.iir == UART_IIR_NO_INT)
return;
 
if(intr != uart->regs.iir)
return;
 
TRACE("Clearing interrupt 0x%x\n", intr);
 
uart->regs.iir = UART_IIR_NO_INT;
 
switch(intr) {
case UART_IIR_RLSI:
SCHED_FIND_REMOVE(uart_int_rlsi, uart);
break;
case UART_IIR_RDI:
SCHED_FIND_REMOVE(uart_int_rdi, uart);
break;
case UART_IIR_CTI:
SCHED_FIND_REMOVE(uart_int_cti, uart);
break;
case UART_IIR_THRI:
SCHED_FIND_REMOVE(uart_int_thri, uart);
break;
case UART_IIR_MSI:
SCHED_FIND_REMOVE(uart_int_msi, uart);
break;
}
 
/* Schedule this job as there is no rush to send the next interrupt (the or.
* code is probably still running with interrupts disabled and this function
* is called from the uart_{read,write}_byte functions. */
SCHED_ADD(uart_next_int, uart, 0);
}
 
/*----------------------------------------------------[ Transmitter logic ]---*/
/* Sends the data in the shift register to the outside world */
static void send_char (struct dev_16450 *uart, int bits_send)
222,7 → 406,7
*/
if (!uart->istat.txbuf_full) {
uart->regs.lsr |= UART_LSR_TXBUFE;
uart->istat.thre_int = 1;
uart_int_thri(uart);
}
}
 
231,10 → 415,14
static void uart_add_char (struct dev_16450 *uart, int ch)
{
uart->regs.lsr |= UART_LSR_RDRDY;
uart->istat.timeout_count = 0;
uart_clear_int(uart, UART_IIR_CTI);
SCHED_FIND_REMOVE(uart_int_cti, uart);
SCHED_ADD(uart_int_cti, uart,
uart->char_clks * UART_CHAR_TIMEOUT * UART_CLOCK_DIVIDER);
 
if (uart->istat.rxbuf_full + 1 > uart->fifo_len) {
uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
uart_int_rlsi(uart);
} else {
TRACE("add %02x\n", ch);
uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
241,8 → 429,10
uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
if(!uart->istat.rxbuf_full++) {
uart->regs.lsr |= ch >> 8;
uart_check_rlsi(uart);
}
}
uart_check_rdi(uart);
}
 
/* Called when a break sequence is about to start. It stops receiveing
371,8 → 561,7
} else
uart->regs.txbuf[uart->istat.txbuf_head] = value;
 
if (uart->regs.iir & UART_IIR_THRI)
uart->istat.thre_int = 0;
uart_clear_int(uart, UART_IIR_THRI);
break;
case UART_FCR:
uart->regs.fcr = value & UART_VALID_FCR;
385,8 → 574,10
uart->istat.txbuf_full = 0;
uart->regs.lsr |= UART_LSR_TXBUFE;
 
// For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
uart->istat.thre_int = (uart->fifo_len == 16);
/* For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
*/
if(uart->fifo_len == 16)
SCHED_ADD(uart_int_thri, uart, 0);
 
SCHED_FIND_REMOVE(uart_tx_send, uart);
}
394,10 → 585,13
uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
uart->istat.rxbuf_full = 0;
uart->regs.lsr &= ~UART_LSR_RDRDY;
uart_clear_int(uart, UART_IIR_RDI);
uart_clear_int(uart, UART_IIR_CTI);
}
break;
case UART_IER:
uart->regs.ier = value & UART_VALID_IER;
SCHED_ADD(uart_next_int, uart, 0);
break;
case UART_LCR:
if((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) {
465,13 → 659,23
TRACE("Reading %"PRIx8" out of RX FIFO\n", value);
} else
TRACE("Trying to read out of RX FIFO but it's empty!\n");
if(uart->istat.rxbuf_full)
 
uart_clear_int(uart, UART_IIR_RDI);
uart_clear_int(uart, UART_IIR_CTI);
SCHED_FIND_REMOVE(uart_int_cti, uart);
 
if(uart->istat.rxbuf_full) {
uart->regs.lsr |= UART_LSR_RDRDY | uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
else
SCHED_ADD(uart_int_cti, uart,
uart->char_clks * UART_CHAR_TIMEOUT * UART_CLOCK_DIVIDER);
/* Since we're not allowed to raise interrupts from read/write functions
* schedule them to run just after we have executed this read
* instruction. */
SCHED_ADD(uart_check_rlsi, uart, 0);
SCHED_ADD(uart_check_rdi, uart, 0);
} else {
uart->regs.lsr &= ~UART_LSR_RDRDY;
uart->istat.timeout_count = 0;
}
break;
case UART_IER:
value = uart->regs.ier & UART_VALID_IER;
478,8 → 682,9
break;
case UART_IIR:
value = (uart->regs.iir & UART_VALID_IIR) | 0xc0;
if (uart->regs.iir & UART_IIR_THRI)
uart->istat.thre_int = 0;
/* Only clear the thri interrupt if it is the one we are repporting */
if(uart->regs.iir == UART_IIR_THRI)
uart_clear_int(uart, UART_IIR_THRI);
break;
case UART_LCR:
value = uart->regs.lcr & UART_VALID_LCR;
492,10 → 697,13
uart->regs.lsr &=
~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
| UART_LSR_FRAME | UART_LSR_RXERR);
/* Clear potentially pending RLSI interrupt */
uart_clear_int(uart, UART_IIR_RLSI);
break;
case UART_MSR:
value = uart->regs.msr & UART_VALID_MSR;
uart->regs.msr = 0;
uart_clear_int(uart, UART_IIR_MSI);
break;
case UART_SCR:
value = uart->regs.scr;
647,36 → 855,6
uart->regs.msr |= ((uart->regs.mcr & UART_MCR_RTS) << 3);
uart->regs.msr |= ((uart->regs.mcr & UART_MCR_DTR) << 5);
}
if (uart->regs.lsr & UART_LSR_RDRDY)
uart->istat.timeout_count++;
/* Interrupt detection in proper priority order. */
uart->regs.iir = UART_IIR_NO_INT;
if (uart->regs.ier & UART_IER_RLSI && /* Receiver LS */
uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
| UART_LSR_FRAME | UART_LSR_BREAK)) {
uart->regs.iir = UART_IIR_RLSI;
} else if ((uart->regs.ier & UART_IER_RDI) /* RD available */
&& (uart->istat.rxbuf_full >= UART_FIFO_TRIGGER(uart->regs.fcr >> 6))
&& (uart->regs.lsr & UART_LSR_RDRDY)) {
uart->regs.iir = UART_IIR_RDI;
} else if ((uart->regs.ier & UART_IER_RDI) /* timeout */
&& (uart->istat.timeout_count >= UART_CHAR_TIMEOUT * uart->char_clks)
&& (uart->istat.rxbuf_head != uart->istat.rxbuf_tail)) {
uart->regs.iir = UART_IIR_CTI;
} else if (uart->regs.ier & UART_IER_THRI && /* Transm. empty */
uart->istat.thre_int == 1) {
uart->regs.iir = UART_IIR_THRI;
} else if (uart->regs.ier & UART_IER_MSI && /* Modem status */
uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
| UART_MSR_TERI | UART_MSR_DDCD)) {
uart->regs.iir = UART_IIR_MSI;
}
if (!(uart->regs.iir & UART_IIR_NO_INT)) {
TRACE("\tuart->regs.iir = %i\t", uart->regs.iir);
report_interrupt(uart->irq);
}
}
 
/* Reset. It initializes all registers of all UART devices to zero values,
712,12 → 890,6
uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
 
uart->istat.thre_int = 0;
uart->istat.timeout_count = 0;
 
// For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
uart->istat.thre_int = (uart->fifo_len == 16);
 
uart->char_clks = 0;
 
uart->iregs.txser = 0;
725,6 → 897,7
uart->iregs.loopback = 0;
uart->istat.receiveing = 0;
uart->istat.recv_break = 0;
uart->istat.ints = 0;
 
memset(uart->regs.txbuf, 0, sizeof(uart->regs.txbuf));
memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
732,7 → 905,7
uart->regs.dll = 0;
uart->regs.dlh = 0;
uart->regs.ier = 0;
uart->regs.iir = 0;
uart->regs.iir = UART_IIR_NO_INT;
uart->regs.fcr = 0;
uart->regs.lcr = UART_LCR_RESET;
uart->regs.mcr = 0;
/trunk/or1ksim/peripheral/16450.h
59,10 → 59,9
int rxbuf_tail;
unsigned int txbuf_full;
unsigned int rxbuf_full;
unsigned thre_int;
unsigned timeout_count;
int receiveing; /* Receiveing a char */
int recv_break; /* Receiveing a break */
int ints; /* Which interrupts are pending */
} istat; /* Internal status */
 
/* Clocks per char */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.