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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [peripheral/] [16450.c] - Diff between revs 1390 and 1392

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 1390 Rev 1392
Line 46... Line 46...
#include "vapi.h"
#include "vapi.h"
#include "sched.h"
#include "sched.h"
#include "channel.h"
#include "channel.h"
#include "debug.h"
#include "debug.h"
 
 
 
DEFAULT_DEBUG_CHANNEL(uart);
 
 
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
   before a single character is transmitted or received. */
   before a single character is transmitted or received. */
static unsigned long char_clks(int dll, int dlh, int lcr)
static unsigned long char_clks(int dll, int dlh, int lcr)
Line 77... Line 79...
/* Set a specific UART register with value. */
/* Set a specific UART register with value. */
void uart_write_byte(oraddr_t addr, uint32_t value, void *dat)
void uart_write_byte(oraddr_t addr, uint32_t value, void *dat)
{
{
  struct dev_16450 *uart = dat;
  struct dev_16450 *uart = dat;
 
 
  debug(4, "uart_write_byte(%"PRIxADDR",%02"PRIx32")\n", addr, value);
  TRACE("uart_write_byte(%"PRIxADDR",%02"PRIx32")\n", addr, value);
 
 
  if (uart->regs.lcr & UART_LCR_DLAB) {
  if (uart->regs.lcr & UART_LCR_DLAB) {
    switch (addr % UART_ADDR_SPACE) {
    switch (addr % UART_ADDR_SPACE) {
      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,
 
              uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
        return;
        return;
      case UART_DLH:
      case UART_DLH:
        uart->regs.dlh = value;
        uart->regs.dlh = value;
        return;
        return;
    }
    }
Line 138... Line 142...
      break;
      break;
    case UART_SCR:
    case UART_SCR:
      uart->regs.scr = value;
      uart->regs.scr = value;
      break;
      break;
    default:
    default:
      debug(1, "write out of range (addr %x)\n", addr);
      TRACE("write out of range (addr %x)\n", addr);
  }
  }
}
}
 
 
/* Read a specific UART register. */
/* Read a specific UART register. */
uint32_t uart_read_byte(oraddr_t addr, void *dat)
uint32_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;
 
 
  debug(4, "uart_read_byte(%"PRIxADDR")", addr);
  TRACE("uart_read_byte(%"PRIxADDR")", addr);
 
 
  if (uart->regs.lcr & UART_LCR_DLAB) {
  if (uart->regs.lcr & UART_LCR_DLAB) {
    switch (addr % UART_ADDR_SPACE) {
    switch (addr % UART_ADDR_SPACE) {
      case UART_DLL:
      case UART_DLL:
        value = uart->regs.dll;
        value = uart->regs.dll;
        debug(4, "= %"PRIx8"\n", value);
        TRACE("= %"PRIx8"\n", value);
        return value;
        return value;
      case UART_DLH:
      case UART_DLH:
        value = uart->regs.dlh;
        value = uart->regs.dlh;
        debug(4, "= %"PRIx8"\n", value);
        TRACE("= %"PRIx8"\n", value);
        return value;
        return value;
    }
    }
  }
  }
 
 
  switch (addr % UART_ADDR_SPACE) {
  switch (addr % UART_ADDR_SPACE) {
    case UART_RXBUF:
    case UART_RXBUF:
      { /* Print out FIFO for debugging */
      { /* Print out FIFO for debugging */
        int i;
        int i;
        debug(4, "(%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++)
          debug(4, "%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]);
        debug(4, ")");
        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;
        uart->istat.rxbuf_full--;
        uart->istat.rxbuf_full--;
Line 214... Line 218...
      break;
      break;
    case UART_SCR:
    case UART_SCR:
      value = uart->regs.scr;
      value = uart->regs.scr;
      break;
      break;
    default:
    default:
      debug(1, "read out of range (addr %"PRIxADDR")\n", addr);
      TRACE("read out of range (addr %"PRIxADDR")\n", addr);
  }
  }
  debug(4, " = %"PRIx8"\n", value);
  TRACE(" = %"PRIx8"\n", value);
  return value;
  return value;
}
}
 
 
/* Function that handles incoming VAPI data.  */
/* Function that handles incoming VAPI data.  */
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
{
{
  struct dev_16450 *uart = dat;
  struct dev_16450 *uart = dat;
  debug(4, "UART: id %08lx, data %08lx\n", id, data);
  TRACE("UART: id %08lx, data %08lx\n", id, data);
  uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
  uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
  uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
  uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
  if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
  if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
    exit (1);
    exit (1);
Line 236... Line 240...
}
}
 
 
static void send_char (struct dev_16450 *uart, int bits_send)
static void send_char (struct dev_16450 *uart, int bits_send)
{
{
  PRINTF ("%c", (char)uart->iregs.txser);
  PRINTF ("%c", (char)uart->iregs.txser);
  debug(4, "TX \'%c\' via UART at %"PRIxADDR"...\n", (char)uart->iregs.txser,
  TRACE("TX \'%c\' via UART at %"PRIxADDR"...\n", (char)uart->iregs.txser,
        uart->baseaddr);
        uart->baseaddr);
  if (uart->regs.mcr & UART_MCR_LOOP)
  if (uart->regs.mcr & UART_MCR_LOOP)
    uart->iregs.loopback = uart->iregs.txser;
    uart->iregs.loopback = uart->iregs.txser;
  else {
  else {
    /* Send to either VAPI or to file */
    /* Send to either VAPI or to file */
Line 295... Line 299...
 
 
      fe = ((packet >> (nbits++)) & 1) ^ 1;
      fe = ((packet >> (nbits++)) & 1) ^ 1;
      if (uart->vapi.lcr & UART_LCR_STOP)
      if (uart->vapi.lcr & UART_LCR_STOP)
        fe |= ((packet >> (nbits++)) & 1) ^ 1;
        fe |= ((packet >> (nbits++)) & 1) ^ 1;
 
 
      debug (4, "lcr vapi %02x, uart %02x\n", uart->vapi.lcr, uart->regs.lcr);
      TRACE ("lcr vapi %02x, uart %02x\n", uart->vapi.lcr, uart->regs.lcr);
      data |= (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi.lcr << 8);
      data |= (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi.lcr << 8);
      PRINTF ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
      PRINTF ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
      debug (4, "vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
      TRACE ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
      vapi_send (uart->vapi_id, data);
      vapi_send (uart->vapi_id, data);
    } else {
    } else {
      char buffer[1] = { uart->iregs.txser & 0xFF };
      char buffer[1] = { uart->iregs.txser & 0xFF };
      channel_write(uart->channel, buffer, 1);
      channel_write(uart->channel, buffer, 1);
    }
    }
Line 316... Line 320...
void uart_add_char (struct dev_16450 *uart, int ch)
void uart_add_char (struct dev_16450 *uart, int ch)
{
{
  if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
  if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
    uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
    uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
  else {
  else {
    debug(4, "add %02x\n", ch);
    TRACE("add %02x\n", ch);
    uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
    uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
    uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
    uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
    uart->istat.rxbuf_full++;
    uart->istat.rxbuf_full++;
  }
  }
  uart->regs.lsr |= UART_LSR_RDRDY;
  uart->regs.lsr |= UART_LSR_RDRDY;
Line 335... Line 339...
  int retval;
  int retval;
 
 
  /* Schedule for later */
  /* Schedule for later */
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
 
 
 
  TRACE("Running uart clock:\n");
 
 
  /* If VAPI is not selected, UART communicates with two file streams;
  /* If VAPI is not selected, UART communicates with two file streams;
     if VAPI is selected, we use VAPI streams.  */
     if VAPI is selected, we use VAPI streams.  */
  /* if txfs is corrupted, skip this uart. */
  /* if txfs is corrupted, skip this uart. */
  if (!uart->vapi_id && !channel_ok(uart->channel)) return;
  if (!uart->vapi_id && !channel_ok(uart->channel)) return;
 
 
 
  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.next_break_cnt < 0) {
    if (--uart->vapi.next_break_cnt < 0) {
      if (!(uart->vapi.cur_break = uart->vapi.next_break))
      if (!(uart->vapi.cur_break = uart->vapi.next_break))
        uart->istat.break_set = 0;
        uart->istat.break_set = 0;
    }
    }
 
 
  /***************** Transmit *****************/
  /***************** Transmit *****************/
 
  TRACE("\tuart->istat.txser_full = %i\n", uart->istat.txser_full);
 
  TRACE("\tuart->istat.txbuf_full = %i\n", uart->istat.txser_full);
 
  TRACE("\tuart->char_clks = %li\n", uart->char_clks);
  if (!uart->istat.txser_full) {
  if (!uart->istat.txser_full) {
//      uart->regs.lsr |= UART_LSR_TXBUFE;
//      uart->regs.lsr |= UART_LSR_TXBUFE;
    if (uart->istat.txbuf_full) {
    if (uart->istat.txbuf_full) {
      uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
      uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
      uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
      uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
Line 416... Line 427...
  } else {
  } else {
    if (uart->istat.rxser_full) {
    if (uart->istat.rxser_full) {
      if (uart->char_clks <= uart->istat.rxser_clks++) {
      if (uart->char_clks <= uart->istat.rxser_clks++) {
        /* Set unused character bits to zero and allow lsr register in fifo */
        /* Set unused character bits to zero and allow lsr register in fifo */
        uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
        uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
        debug(4, "Receiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
        TRACE("\tReceiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
              uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
              uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
        PRINTF ("%c", (char)uart->iregs.rxser);
        PRINTF ("%c", (char)uart->iregs.rxser);
        uart->istat.rxser_full = 0;
        uart->istat.rxser_full = 0;
        uart->istat.rxser_clks = 0;
        uart->istat.rxser_clks = 0;
        uart_add_char (uart, uart->iregs.rxser);
        uart_add_char (uart, uart->iregs.rxser);
Line 454... Line 465...
      /* do not handle commands while receiving */
      /* do not handle commands while receiving */
      if (uart->istat.rxser_full) return;
      if (uart->istat.rxser_full) return;
      while (!received) {
      while (!received) {
        if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
        if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
          unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
          unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
          debug(4, "Handling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
          TRACE("\tHandling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
                uart->vapi_buf_tail_ptr);
                uart->vapi_buf_tail_ptr);
          uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
          uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
          switch (data >> 24) {
          switch (data >> 24) {
            case 0x00:
            case 0x00:
              uart->vapi.lcr = (data >> 8) & 0xff;
              uart->vapi.lcr = (data >> 8) & 0xff;
Line 466... Line 477...
              uart->iregs.rxser = data & 0xff;
              uart->iregs.rxser = data & 0xff;
              uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
              uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
              if ((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
              if ((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
               || uart->vapi.char_clks != uart->char_clks
               || uart->vapi.char_clks != uart->char_clks
               || uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
               || uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
                debug (3, "WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
                WARN("WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
                      uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
                      uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
                /* Set error bits */
                /* Set error bits */
                uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
                uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
                if (uart->regs.lcr & UART_LCR_PARITY) uart->iregs.rxser |= UART_LSR_PARITY << 8;
                if (uart->regs.lcr & UART_LCR_PARITY) uart->iregs.rxser |= UART_LSR_PARITY << 8;
              }
              }
Line 490... Line 501...
            case 0x04:
            case 0x04:
              uart->vapi.next_break_cnt = data & 0xffff;
              uart->vapi.next_break_cnt = data & 0xffff;
              uart->vapi.next_break = (data >> 16) & 1;
              uart->vapi.next_break = (data >> 16) & 1;
              break;
              break;
            default:
            default:
              debug (0, "WARNING: Invalid vapi command %02lx\n", data >> 24);
              WARN ("WARNING: Invalid vapi command %02lx\n", data >> 24);
              break;
              break;
          }
          }
        } else break;
        } else break;
      }
      }
    }
    }
  }
  }
 
 
  /***************** Loopback *****************/
  /***************** Loopback *****************/
  if (uart->regs.mcr & UART_MCR_LOOP) {
  if (uart->regs.mcr & UART_MCR_LOOP) {
    debug(5, "uart_clock: Loopback\n");
    TRACE("uart_clock: Loopback\n");
    if ((uart->regs.mcr & UART_MCR_AUX2) !=
    if ((uart->regs.mcr & UART_MCR_AUX2) !=
        ((uart->regs.msr & UART_MSR_DCD) >> 4))
        ((uart->regs.msr & UART_MSR_DCD) >> 4))
      uart->regs.msr |= UART_MSR_DDCD;
      uart->regs.msr |= UART_MSR_DDCD;
    if ((uart->regs.mcr & UART_MCR_AUX1) <
    if ((uart->regs.mcr & UART_MCR_AUX1) <
        ((uart->regs.msr & UART_MSR_RI) >> 4))
        ((uart->regs.msr & UART_MSR_RI) >> 4))
Line 554... Line 565...
      uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
      uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
        | UART_MSR_TERI | UART_MSR_DDCD)) {
        | UART_MSR_TERI | UART_MSR_DDCD)) {
    uart->regs.iir = UART_IIR_MSI;
    uart->regs.iir = UART_IIR_MSI;
  }
  }
  if (!(uart->regs.iir & UART_IIR_NO_INT)) {
  if (!(uart->regs.iir & UART_IIR_NO_INT)) {
    debug (4, "uart->regs.iir = %i\t", uart->regs.iir);
    TRACE("\tuart->regs.iir = %i\t", uart->regs.iir);
    report_interrupt(uart->irq);
    report_interrupt(uart->irq);
  }
  }
}
}
 
 
/* Reset.  It initializes all registers of all UART devices to zero values,
/* Reset.  It initializes all registers of all UART devices to zero values,
Line 572... Line 583...
    if(uart->channel)
    if(uart->channel)
      channel_close(uart->channel);
      channel_close(uart->channel);
    else
    else
      uart->channel = channel_init(uart->channel_str);
      uart->channel = channel_init(uart->channel_str);
    if(channel_open(uart->channel) < 0) {
    if(channel_open(uart->channel) < 0) {
      debug (0, "WARNING: UART has problems with channel \"%s\".\n", uart->channel_str);
      WARN ("WARNING: UART has problems with channel \"%s\".\n", uart->channel_str);
    } else if (config.sim.verbose)
    } else if (config.sim.verbose)
      PRINTF("UART at 0x%"PRIxADDR" uses ", uart->baseaddr);
      PRINTF("UART at 0x%"PRIxADDR" uses ", uart->baseaddr);
  } else {
  } else {
    debug (0, "WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n", uart->baseaddr);
    WARN ("WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n", uart->baseaddr);
  }
  }
 
 
  if (uart->uart16550)
  if (uart->uart16550)
    uart->fifo_len = 16;
    uart->fifo_len = 16;
  else
  else

powered by: WebSVN 2.1.0

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