Line 556... |
Line 556... |
{
|
{
|
if(!uart->vapi_id)
|
if(!uart->vapi_id)
|
SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
|
SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
|
}
|
}
|
|
|
|
/*----------------------------------------------------[ UART I/O handling ]---*/
|
/* Set a specific UART register with value. */
|
/* Set a specific UART register with value. */
|
void uart_write_byte(oraddr_t addr, uint8_t value, void *dat)
|
void uart_write_byte(oraddr_t addr, uint8_t value, void *dat)
|
{
|
{
|
struct dev_16450 *uart = dat;
|
struct dev_16450 *uart = dat;
|
|
|
TRACE("uart_write_byte(%"PRIxADDR",%02"PRIx8")\n", addr, value);
|
|
|
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
switch (addr) {
|
switch (addr) {
|
case UART_DLL:
|
case UART_DLL:
|
uart->regs.dll = value;
|
uart->regs.dll = value;
|
uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
TRACE("\tSetting char_clks to %li (%02x, %02x, %02x)\n", uart->char_clks,
|
TRACE("\tSetting char_clks to %li (%02x, %02x, %02x)\n", uart->char_clks,
|
uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
return;
|
return;
|
case UART_DLH:
|
case UART_DLH:
|
|
TRACE("Setting dlh with %"PRIx8"\n", value);
|
uart->regs.dlh = value;
|
uart->regs.dlh = value;
|
return;
|
return;
|
}
|
}
|
}
|
}
|
|
|
switch (addr) {
|
switch (addr) {
|
case UART_TXBUF:
|
case UART_TXBUF:
|
|
TRACE("Adding %"PRIx8" to TX FIFO\n", value);
|
uart->regs.lsr &= ~UART_LSR_TXBUFE;
|
uart->regs.lsr &= ~UART_LSR_TXBUFE;
|
if (uart->istat.txbuf_full < uart->fifo_len) {
|
if (uart->istat.txbuf_full < uart->fifo_len) {
|
uart->regs.txbuf[uart->istat.txbuf_head] = value;
|
uart->regs.txbuf[uart->istat.txbuf_head] = value;
|
uart->istat.txbuf_head = (uart->istat.txbuf_head + 1) % uart->fifo_len;
|
uart->istat.txbuf_head = (uart->istat.txbuf_head + 1) % uart->fifo_len;
|
if(!uart->istat.txbuf_full++ && (uart->regs.lsr & UART_LSR_TXSERE))
|
if(!uart->istat.txbuf_full++ && (uart->regs.lsr & UART_LSR_TXSERE))
|
Line 591... |
Line 592... |
uart->regs.txbuf[uart->istat.txbuf_head] = value;
|
uart->regs.txbuf[uart->istat.txbuf_head] = value;
|
|
|
uart_clear_int(uart, UART_IIR_THRI);
|
uart_clear_int(uart, UART_IIR_THRI);
|
break;
|
break;
|
case UART_FCR:
|
case UART_FCR:
|
|
TRACE("Setting FCR reg with %"PRIx8"\n", value);
|
uart->regs.fcr = value & UART_VALID_FCR;
|
uart->regs.fcr = value & UART_VALID_FCR;
|
if ((uart->fifo_len == 1 && (value & UART_FCR_FIE))
|
if ((uart->fifo_len == 1 && (value & UART_FCR_FIE))
|
|| (uart->fifo_len != 1 && !(value & UART_FCR_FIE)))
|
|| (uart->fifo_len != 1 && !(value & UART_FCR_FIE)))
|
value |= UART_FCR_RRXFI | UART_FCR_RTXFI;
|
value |= UART_FCR_RRXFI | UART_FCR_RTXFI;
|
uart->fifo_len = (value & UART_FCR_FIE) ? 16 : 1;
|
uart->fifo_len = (value & UART_FCR_FIE) ? 16 : 1;
|
Line 618... |
Line 620... |
uart_clear_int(uart, UART_IIR_CTI);
|
uart_clear_int(uart, UART_IIR_CTI);
|
}
|
}
|
break;
|
break;
|
case UART_IER:
|
case UART_IER:
|
uart->regs.ier = value & UART_VALID_IER;
|
uart->regs.ier = value & UART_VALID_IER;
|
|
TRACE("Enabling 0x%02x interrupts with 0x%x interrupts pending\n",
|
|
value, uart->istat.ints);
|
SCHED_ADD(uart_next_int, uart, 0);
|
SCHED_ADD(uart_next_int, uart, 0);
|
break;
|
break;
|
case UART_LCR:
|
case UART_LCR:
|
|
TRACE("Setting LCR reg with %"PRIx8"\n", value);
|
if((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) {
|
if((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) {
|
if((value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
|
if((value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
|
/* Schedule a job to send the break char */
|
/* Schedule a job to send the break char */
|
SCHED_FIND_REMOVE(uart_char_clock, uart);
|
SCHED_FIND_REMOVE(uart_char_clock, uart);
|
SCHED_ADD(uart_send_break, uart, 0);
|
SCHED_ADD(uart_send_break, uart, 0);
|
Line 638... |
Line 643... |
}
|
}
|
uart->regs.lcr = value & UART_VALID_LCR;
|
uart->regs.lcr = value & UART_VALID_LCR;
|
uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
break;
|
break;
|
case UART_MCR:
|
case UART_MCR:
|
|
TRACE("Setting MCR reg with %"PRIx8"\n", value);
|
uart->regs.mcr = value & UART_VALID_MCR;
|
uart->regs.mcr = value & UART_VALID_MCR;
|
uart_loopback(uart);
|
uart_loopback(uart);
|
break;
|
break;
|
case UART_SCR:
|
case UART_SCR:
|
|
TRACE("Setting SCR reg with %"PRIx8"\n", value);
|
uart->regs.scr = value;
|
uart->regs.scr = value;
|
break;
|
break;
|
default:
|
default:
|
TRACE("write out of range (addr %x)\n", addr);
|
TRACE("write out of range (addr %"PRIxADDR")\n", addr);
|
}
|
}
|
}
|
}
|
|
|
/* Read a specific UART register. */
|
/* Read a specific UART register. */
|
uint8_t uart_read_byte(oraddr_t addr, void *dat)
|
uint8_t uart_read_byte(oraddr_t addr, void *dat)
|
{
|
{
|
struct dev_16450 *uart = dat;
|
struct dev_16450 *uart = dat;
|
uint8_t value = 0;
|
uint8_t value = 0;
|
|
|
TRACE("uart_read_byte(%"PRIxADDR")", addr);
|
|
|
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
switch (addr) {
|
switch (addr) {
|
case UART_DLL:
|
case UART_DLL:
|
value = uart->regs.dll;
|
value = uart->regs.dll;
|
TRACE("= %"PRIx8"\n", value);
|
TRACE("reading DLL = %"PRIx8"\n", value);
|
return value;
|
return value;
|
case UART_DLH:
|
case UART_DLH:
|
value = uart->regs.dlh;
|
value = uart->regs.dlh;
|
TRACE("= %"PRIx8"\n", value);
|
TRACE("reading DLH = %"PRIx8"\n", value);
|
return value;
|
return value;
|
}
|
}
|
}
|
}
|
|
|
switch (addr) {
|
switch (addr) {
|
Line 677... |
Line 682... |
{ /* Print out FIFO for debugging */
|
{ /* Print out FIFO for debugging */
|
int i;
|
int i;
|
TRACE("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len,
|
TRACE("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len,
|
uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
|
uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
|
for (i = 0; i < uart->istat.rxbuf_full; i++)
|
for (i = 0; i < uart->istat.rxbuf_full; i++)
|
TRACE("%02x ", uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
|
TRACE("%02x ",
|
|
uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
|
TRACE(")");
|
TRACE(")");
|
}
|
}
|
if (uart->istat.rxbuf_full) {
|
if (uart->istat.rxbuf_full) {
|
value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
|
value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
|
uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
|
uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
|
Line 707... |
Line 713... |
uart->regs.lsr &= ~UART_LSR_RDRDY;
|
uart->regs.lsr &= ~UART_LSR_RDRDY;
|
}
|
}
|
break;
|
break;
|
case UART_IER:
|
case UART_IER:
|
value = uart->regs.ier & UART_VALID_IER;
|
value = uart->regs.ier & UART_VALID_IER;
|
|
TRACE("reading IER = %"PRIx8"\n", value);
|
break;
|
break;
|
case UART_IIR:
|
case UART_IIR:
|
value = (uart->regs.iir & UART_VALID_IIR) | 0xc0;
|
value = (uart->regs.iir & UART_VALID_IIR) | 0xc0;
|
/* Only clear the thri interrupt if it is the one we are repporting */
|
/* Only clear the thri interrupt if it is the one we are repporting */
|
if(uart->regs.iir == UART_IIR_THRI)
|
if(uart->regs.iir == UART_IIR_THRI)
|
uart_clear_int(uart, UART_IIR_THRI);
|
uart_clear_int(uart, UART_IIR_THRI);
|
|
TRACE("reading IIR = %"PRIx8"\n", value);
|
break;
|
break;
|
case UART_LCR:
|
case UART_LCR:
|
value = uart->regs.lcr & UART_VALID_LCR;
|
value = uart->regs.lcr & UART_VALID_LCR;
|
|
TRACE("reading LCR = %"PRIx8"\n", value);
|
break;
|
break;
|
case UART_MCR:
|
case UART_MCR:
|
value = 0;
|
value = 0;
|
|
TRACE("reading MCR = %"PRIx8"\n", value);
|
break;
|
break;
|
case UART_LSR:
|
case UART_LSR:
|
value = uart->regs.lsr & UART_VALID_LSR;
|
value = uart->regs.lsr & UART_VALID_LSR;
|
uart->regs.lsr &=
|
uart->regs.lsr &=
|
~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
|
~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
|
| UART_LSR_FRAME | UART_LSR_RXERR);
|
| UART_LSR_FRAME | UART_LSR_RXERR);
|
/* Clear potentially pending RLSI interrupt */
|
/* Clear potentially pending RLSI interrupt */
|
uart_clear_int(uart, UART_IIR_RLSI);
|
uart_clear_int(uart, UART_IIR_RLSI);
|
|
TRACE("reading LSR = %"PRIx8"\n", value);
|
break;
|
break;
|
case UART_MSR:
|
case UART_MSR:
|
value = uart->regs.msr & UART_VALID_MSR;
|
value = uart->regs.msr & UART_VALID_MSR;
|
uart->regs.msr = 0;
|
uart->regs.msr = 0;
|
uart_clear_int(uart, UART_IIR_MSI);
|
uart_clear_int(uart, UART_IIR_MSI);
|
uart_loopback(uart);
|
uart_loopback(uart);
|
|
TRACE("reading MSR = %"PRIx8"\n", value);
|
break;
|
break;
|
case UART_SCR:
|
case UART_SCR:
|
value = uart->regs.scr;
|
value = uart->regs.scr;
|
|
TRACE("reading SCR = %"PRIx8"\n", value);
|
break;
|
break;
|
default:
|
default:
|
TRACE("read out of range (addr %"PRIxADDR")\n", addr);
|
TRACE("read out of range (addr %"PRIxADDR")\n", addr);
|
}
|
}
|
TRACE(" = %"PRIx8"\n", value);
|
|
return value;
|
return value;
|
}
|
}
|
|
|
/*--------------------------------------------------------[ VAPI handling ]---*/
|
/*--------------------------------------------------------[ VAPI handling ]---*/
|
/* Decodes the read vapi command */
|
/* Decodes the read vapi command */
|
Line 844... |
Line 856... |
}
|
}
|
if(!uart->istat.receiveing)
|
if(!uart->istat.receiveing)
|
uart_vapi_cmd(uart);
|
uart_vapi_cmd(uart);
|
}
|
}
|
|
|
|
/*--------------------------------------------------------[ Sim callbacks ]---*/
|
/* Reset. It initializes all registers of all UART devices to zero values,
|
/* Reset. It initializes all registers of all UART devices to zero values,
|
(re)opens all RX/TX file streams and places devices in memory address
|
* (re)opens all RX/TX file streams and places devices in memory address
|
space. */
|
* space. */
|
void uart_reset(void *dat)
|
void uart_reset(void *dat)
|
{
|
{
|
struct dev_16450 *uart = dat;
|
struct dev_16450 *uart = dat;
|
|
|
if(uart->vapi_id) {
|
if(uart->vapi_id) {
|