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 1500 to Rev 1501
    Reverse comparison

Rev 1500 → Rev 1501

/trunk/or1ksim/peripheral/16450.c
52,6 → 52,12
 
#define MIN(a,b) ((a) < (b) ? (a) : (b))
 
void uart_recv_break(void *dat);
void uart_recv_char(void *dat);
void uart_check_vapi(void *dat);
void uart_check_char(void *dat);
static void uart_sched_recv_check(struct dev_16450 *uart);
static void uart_vapi_cmd(void *dat);
void uart_tx_send(void *dat);
 
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
220,6 → 226,119
}
}
 
/*-------------------------------------------------------[ Receiver logic ]---*/
/* Adds a character to the RX FIFO */
static void uart_add_char (struct dev_16450 *uart, int ch)
{
uart->regs.lsr |= UART_LSR_RDRDY;
uart->istat.timeout_count = 0;
 
if (uart->istat.rxbuf_full + 1 > uart->fifo_len) {
uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
} else {
TRACE("add %02x\n", ch);
uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
if(!uart->istat.rxbuf_full++) {
uart->regs.lsr |= ch >> 8;
}
}
}
 
/* Called when a break sequence is about to start. It stops receiveing
* characters and schedules the uart_recv_break to send the break */
void uart_recv_break_start(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.receiveing = 0;
uart->istat.recv_break = 1;
 
SCHED_FIND_REMOVE(uart_recv_char, uart);
 
if(uart->vapi_id && (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr))
uart_vapi_cmd(uart);
 
SCHED_ADD(uart_recv_break, uart,
UART_BREAK_COUNT * uart->vapi.char_clks * UART_CLOCK_DIVIDER);
}
 
/* Stops sending breaks and starts receiveing characters */
void uart_recv_break_stop(void *dat)
{
struct dev_16450 *uart = dat;
 
uart->istat.recv_break = 0;
SCHED_FIND_REMOVE(uart_recv_break, dat);
}
 
/* Receives a break */
void uart_recv_break(void *dat)
{
struct dev_16450 *uart = dat;
unsigned lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY;
 
uart_add_char(uart, lsr << 8);
}
 
/* Moves a character from the serial register to the RX FIFO */
void uart_recv_char(void *dat)
{
struct dev_16450 *uart = dat;
uint16_t char_to_add;
 
/* Set unused character bits to zero and allow lsr register in fifo */
char_to_add = uart->iregs.rxser & (((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00);
 
TRACE("Receiving 0x%02"PRIx16"'%c' via UART at %"PRIxADDR"\n",
char_to_add, (char)char_to_add, uart->baseaddr);
PRINTF ("%c", (char)char_to_add);
 
if (uart->regs.mcr & UART_MCR_LOOP) {
uart->iregs.rxser = uart->iregs.loopback;
uart->istat.receiveing = 1;
SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
} else {
uart->istat.receiveing = 0;
uart_sched_recv_check(uart);
if(uart->vapi_id && (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr))
SCHED_ADD(uart_vapi_cmd, uart, 0);
}
 
uart_add_char(uart, char_to_add);
}
 
/* Checks if there is a character waiting to be received */
void uart_check_char(void *dat)
{
struct dev_16450 *uart = dat;
char buffer[1];
int retval;
 
/* Check if there is something waiting, and put it into rxser */
retval = channel_read(uart->channel, buffer, 1);
if(retval > 0) {
uart->iregs.rxser = (unsigned char)buffer[0];
uart->istat.receiveing = 1;
SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
return;
}
 
if(!retval) {
SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
return;
}
 
if(retval < 0)
perror(uart->channel_str);
}
 
static void uart_sched_recv_check(struct dev_16450 *uart)
{
if(!uart->vapi_id)
SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
}
 
/* Set a specific UART register with value. */
void uart_write_byte(oraddr_t addr, uint8_t value, void *dat)
{
343,10 → 462,12
value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
uart->istat.rxbuf_full--;
}
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->regs.lsr |= UART_LSR_RDRDY;
if(uart->istat.rxbuf_full)
uart->regs.lsr |= UART_LSR_RDRDY | uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
else
uart->regs.lsr &= ~UART_LSR_RDRDY;
388,8 → 509,9
 
/*--------------------------------------------------------[ VAPI handling ]---*/
/* Decodes the read vapi command */
static void uart_vapi_cmd(struct dev_16450 *uart)
static void uart_vapi_cmd(void *dat)
{
struct dev_16450 *uart = dat;
int received = 0;
 
while (!received) {
425,7 → 547,10
if(uart->regs.lcr & UART_LCR_PARITY)
uart->iregs.rxser |= UART_LSR_PARITY << 8;
}
uart->istat.rxser_full = 1;
if(!uart->istat.recv_break) {
uart->istat.receiveing = 1;
SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
}
received = 1;
break;
case 0x01:
439,8 → 564,25
uart->vapi.skew = (signed short)(data & 0xffff);
break;
case 0x04:
uart->vapi.next_break_cnt = data & 0xffff;
uart->vapi.next_break = (data >> 16) & 1;
if((data >> 16) & 1) {
/* If data & 0xffff is 0 then set the break imediatly and handle the
* following commands as appropriate */
if(!(data & 0xffff))
uart_recv_break_start(uart);
else
/* Schedule a job to start sending breaks */
SCHED_ADD(uart_recv_break_start, uart,
(data & 0xffff) * UART_CLOCK_DIVIDER);
} else {
/* If data & 0xffff is 0 then release the break imediatly and handle
* the following commands as appropriate */
if(!(data & 0xffff))
uart_recv_break_stop(uart);
else
/* Schedule a job to stop sending breaks */
SCHED_ADD(uart_recv_break_stop, uart,
(data & 0xffff) * UART_CLOCK_DIVIDER);
}
break;
default:
WARN("WARNING: Invalid vapi command %02lx\n", data >> 24);
461,30 → 603,15
fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
exit (1);
}
if(!uart->istat.receiveing)
uart_vapi_cmd(uart);
}
 
/* Adds a character to the FIFO */
 
void uart_add_char (struct dev_16450 *uart, int ch)
{
if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
else {
TRACE("add %02x\n", ch);
uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
uart->istat.rxbuf_full++;
}
uart->regs.lsr |= UART_LSR_RDRDY;
uart->istat.timeout_count = 0;
}
 
/* Simulation hook. Must be called every clock cycle to simulate all UART
devices. It does internal functional UART simulation. */
void uart_clock16 (void *dat)
{
struct dev_16450 *uart = dat;
int retval;
 
/* Schedule for later */
SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
498,76 → 625,6
 
TRACE("\tChannel stream or VAPI checks out ok\n");
if (uart->vapi.next_break_cnt >= 0)
if (--uart->vapi.next_break_cnt < 0) {
if (!(uart->vapi.cur_break = uart->vapi.next_break))
uart->istat.break_set = 0;
}
 
/***************** Receive *****************/
/* Is there a break? */
if (uart->vapi.cur_break) {
uart->vapi.cur_break_cnt++;
if (uart->vapi.cur_break_cnt > UART_BREAK_COUNT * uart->vapi.char_clks) {
if (!uart->istat.break_set) {
unsigned lsr;
uart->istat.break_set = 1;
lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY;
PRINTF ("[%x]\n", uart->regs.lsr);
uart->istat.rxser_full = 0;
uart->istat.rxser_clks = 0;
uart_add_char (uart, lsr << 8);
} else
uart->vapi.cur_break_cnt = 0;
}
if (uart->istat.rxser_full) {
uart->istat.rxser_full = 0;
uart->istat.rxser_clks = 0;
}
} else {
if (uart->istat.rxser_full) {
if (uart->char_clks <= uart->istat.rxser_clks++) {
/* Set unused character bits to zero and allow lsr register in fifo */
uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
TRACE("\tReceiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
PRINTF ("%c", (char)uart->iregs.rxser);
uart->istat.rxser_full = 0;
uart->istat.rxser_clks = 0;
uart_add_char (uart, uart->iregs.rxser);
}
}
}
 
/* Check if there is something waiting, and put it into rxser */
if (uart->regs.mcr & UART_MCR_LOOP) {
uart->iregs.rxser = uart->iregs.loopback;
uart->istat.rxser_full = 1;
} else {
if (!uart->vapi_id) {
if(uart->istat.rxser_full == 0) {
if (uart->slowdown)
uart->slowdown--;
else {
char buffer[1];
retval = channel_read(uart->channel, buffer, 1);
if(retval < 0)
perror(uart->channel_str);
else if(retval > 0) {
uart->iregs.rxser = (unsigned char)buffer[0];
uart->istat.rxser_full = 1;
} else
uart->slowdown = UART_FGETC_SLOWDOWN;
}
}
} else { /* VAPI */
/* do not handle commands while receiving */
if (uart->istat.rxser_full) return;
uart_vapi_cmd(uart);
}
}
/***************** Loopback *****************/
if (uart->regs.mcr & UART_MCR_LOOP) {
TRACE("uart_clock: Loopback\n");
594,13 → 651,6
if (uart->regs.lsr & UART_LSR_RDRDY)
uart->istat.timeout_count++;
/* Update LSR error bits from the ones from rx FIFO */
if (uart->istat.rxbuf_full) {
uart->regs.lsr |= uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
/* we must delete the lsr status, so that we can clear it from lsr */
uart->regs.rxbuf[uart->istat.rxbuf_tail] &= 0xff;
}
/* Interrupt detection in proper priority order. */
uart->regs.iir = UART_IIR_NO_INT;
if (uart->regs.ier & UART_IER_RLSI && /* Receiver LS */
660,13 → 710,9
uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
uart->istat.rxser_full = 0;
uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
 
uart->istat.rxser_clks = 0;
 
uart->istat.thre_int = 0;
uart->istat.break_set = 0;
uart->istat.timeout_count = 0;
 
// For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
673,11 → 719,12
uart->istat.thre_int = (uart->fifo_len == 16);
 
uart->char_clks = 0;
uart->slowdown = UART_FGETC_SLOWDOWN;
 
uart->iregs.txser = 0;
uart->iregs.rxser = 0;
uart->iregs.loopback = 0;
uart->istat.receiveing = 0;
uart->istat.recv_break = 0;
 
memset(uart->regs.txbuf, 0, sizeof(uart->regs.txbuf));
memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
693,8 → 740,6
uart->regs.msr = 0;
uart->regs.scr = 0;
 
uart->vapi.cur_break = uart->vapi.cur_break_cnt = uart->vapi.next_break = 0;
uart->vapi.next_break_cnt = -1;
uart->vapi.skew = 0;
uart->vapi.lcr = 0;
uart->vapi.dll = 0;
705,6 → 750,7
memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
 
SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
uart_sched_recv_check(uart);
}
 
/* Print register values on stdout. */
732,8 → 778,6
 
PRINTF("\nInternal status (sim debug):\n");
PRINTF("char_clks: %ld\n", uart->char_clks);
PRINTF("rxser_clks: %ld\n", uart->istat.rxser_clks);
PRINTF("rxser: %d\n", uart->istat.rxser_full);
PRINTF("rxbuf_full: %d txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
PRINTF("Using IRQ%i\n", uart->irq);
if (uart->vapi_id)
/trunk/or1ksim/peripheral/16450.h
57,13 → 57,12
int txbuf_tail;
int rxbuf_head;
int rxbuf_tail;
unsigned int rxser_full;
unsigned int txbuf_full;
unsigned int rxbuf_full;
unsigned thre_int;
unsigned break_set;
unsigned long rxser_clks;
unsigned timeout_count;
int receiveing; /* Receiveing a char */
int recv_break; /* Receiveing a break */
} istat; /* Internal status */
 
/* Clocks per char */
75,10 → 74,6
int dll, dlh;
int lcr;
int skew;
int next_break;
int next_break_cnt;
int cur_break;
int cur_break_cnt;
} vapi;
/* Required by VAPI - circular buffer */
91,9 → 86,6
/* Length of FIFO, 16 for 16550, 1 for 16450 */
int fifo_len;
 
/* fgetc slowdown */
int slowdown;
 
struct channel *channel;
 
/* Configuration */

powered by: WebSVN 2.1.0

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