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

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc3/] [or1ksim/] [peripheral/] [16450.c] - Diff between revs 1486 and 1499

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

Rev 1486 Rev 1499
Line 50... Line 50...
 
 
DEFAULT_DEBUG_CHANNEL(uart);
DEFAULT_DEBUG_CHANNEL(uart);
 
 
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 
 
void uart_tx_send(void *dat);
 
 
/* 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)
{
{
  unsigned int bauds_per_char = 2;
  unsigned int bauds_per_char = 2;
Line 74... Line 76...
  bauds_per_char += 10 + ((lcr & 0x3) << 1);
  bauds_per_char += 10 + ((lcr & 0x3) << 1);
 
 
  return (char_clks * bauds_per_char) >> 1;
  return (char_clks * bauds_per_char) >> 1;
}
}
 
 
 
/*----------------------------------------------------[ Transmitter logic ]---*/
 
/* Sends the data in the shift register to the outside world */
 
static void send_char (struct dev_16450 *uart, int bits_send)
 
{
 
  PRINTF ("%c", (char)uart->iregs.txser);
 
  TRACE("TX \'%c\' via UART at %"PRIxADDR"\n", (char)uart->iregs.txser,
 
        uart->baseaddr);
 
  if (uart->regs.mcr & UART_MCR_LOOP)
 
    uart->iregs.loopback = uart->iregs.txser;
 
  else {
 
    /* Send to either VAPI or to file */
 
    if (uart->vapi_id) {
 
      int par, pe, fe, nbits;
 
      int j, data;
 
      unsigned long packet = 0;
 
 
 
      nbits = MIN (bits_send, (uart->regs.lcr & UART_LCR_WLEN8) + 5);
 
      /* Encode a packet */
 
      packet = uart->iregs.txser & ((1 << nbits) - 1);
 
 
 
      /* Calculate parity */
 
      for (j = 0, par = 0; j < nbits; j++)
 
        par ^= (packet >> j) & 1;
 
 
 
      if (uart->regs.lcr & UART_LCR_PARITY) {
 
        if (uart->regs.lcr & UART_LCR_SPAR) {
 
          packet |= 1 << nbits;
 
        } else {
 
          if (uart->regs.lcr & UART_LCR_EPAR)
 
            packet |= par << nbits;
 
          else
 
            packet |= (par ^ 1) << nbits;
 
        }
 
        nbits++;
 
      }
 
      packet |= 1 << (nbits++);
 
      if (uart->regs.lcr & UART_LCR_STOP)
 
        packet |= 1 << (nbits++);
 
 
 
      /* Decode a packet */
 
      nbits = (uart->vapi.lcr & UART_LCR_WLEN8) + 5;
 
      data = packet & ((1 << nbits) - 1);
 
 
 
      /* Calculate parity, including parity bit */
 
      for (j = 0, par = 0; j < nbits + 1; j++)
 
        par ^= (packet >> j) & 1;
 
 
 
      if (uart->vapi.lcr & UART_LCR_PARITY) {
 
        if (uart->vapi.lcr & UART_LCR_SPAR) {
 
          pe = !((packet >> nbits) & 1);
 
        } else {
 
          if (uart->vapi.lcr & UART_LCR_EPAR)
 
            pe = par != 0;
 
          else
 
            pe = par != 1;
 
        }
 
        nbits++;
 
      } else
 
        pe = 0;
 
 
 
      fe = ((packet >> (nbits++)) & 1) ^ 1;
 
      if (uart->vapi.lcr & UART_LCR_STOP)
 
        fe |= ((packet >> (nbits++)) & 1) ^ 1;
 
 
 
      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);
 
      TRACE ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
 
      vapi_send (uart->vapi_id, data);
 
    } else {
 
      char buffer[1] = { uart->iregs.txser & 0xFF };
 
      channel_write(uart->channel, buffer, 1);
 
    }
 
  }
 
}
 
 
 
/* Called when all the bits have been shifted out of the shift register */
 
void uart_char_clock(void *dat)
 
{
 
  struct dev_16450 *uart = dat;
 
 
 
  TRACE("Sending data in shift reg: 0x%02lx\n", uart->iregs.txser);
 
  /* We've sent all bits */
 
  send_char(uart, (uart->regs.lcr & UART_LCR_WLEN8) + 5);
 
 
 
  if(!uart->istat.txbuf_full)
 
    uart->regs.lsr |= UART_LSR_TXSERE;
 
  else
 
    uart_tx_send(uart);
 
}
 
 
 
/* Called when a break has been shifted out of the shift register */
 
void uart_send_break(void *dat)
 
{
 
  struct dev_16450 *uart = dat;
 
 
 
  TRACE("Sending break\n");
 
#if 0
 
  /* Send broken frame */
 
  int nbits_sent = ((uart->regs.lcr & UART_LCR_WLEN8) + 5) * (uart->istat.txser_clks - 1) / uart->char_clks;
 
  send_char(i, nbits_sent);
 
#endif
 
  /* Send one break signal */
 
  vapi_send (uart->vapi_id, UART_LCR_SBC << 8);
 
 
 
  /* Send the next char (if there is one) */
 
  if(!uart->istat.txbuf_full)
 
    uart->regs.lsr |= UART_LSR_TXSERE;
 
  else
 
    uart_tx_send(uart);
 
}
 
 
 
/* Scheduled whenever the TX buffer has characters in it and we aren't sending
 
 * a character. */
 
void uart_tx_send(void *dat)
 
{
 
  struct dev_16450 *uart = dat;
 
 
 
  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_full--;
 
  uart->regs.lsr &= ~UART_LSR_TXSERE;
 
 
 
  TRACE("Moveing head of TX fifo (fill: %i) to shift reg 0x%02lx\n",
 
        uart->istat.txbuf_full, uart->iregs.txser);
 
 
 
  /* Schedules a char_clock to run in the correct amount of time */
 
  if(!(uart->regs.lcr & UART_LCR_SBC)) {
 
    SCHED_ADD(uart_char_clock, uart, uart->char_clks * UART_CLOCK_DIVIDER);
 
  } else {
 
    TRACE("Sending break not char\n");
 
    SCHED_ADD(uart_send_break, uart, 0);
 
  }
 
 
 
  /* When UART is in either character mode, i.e. 16450 emulation mode, or FIFO
 
   * mode, the THRE interrupt is raised when THR transitions from full to empty.
 
   */
 
  if (!uart->istat.txbuf_full) {
 
    uart->regs.lsr |= UART_LSR_TXBUFE;
 
    uart->istat.thre_int = 1;
 
  }
 
}
 
 
/* 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;
 
 
Line 97... Line 241...
    }
    }
  }
  }
 
 
  switch (addr) {
  switch (addr) {
    case UART_TXBUF:
    case UART_TXBUF:
 
      uart->regs.lsr &= ~UART_LSR_TXBUFE;
      if (uart->istat.txbuf_full < uart->fifo_len) {
      if (uart->istat.txbuf_full < uart->fifo_len) {
        uart->istat.txbuf_full++;
 
        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))
 
          SCHED_ADD(uart_tx_send, uart, 0);
      } else
      } else
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
 
 
      uart->regs.lsr &= ~(UART_LSR_TXSERE | UART_LSR_TXBUFE);
 
      if (uart->regs.iir & UART_IIR_THRI)
      if (uart->regs.iir & UART_IIR_THRI)
        uart->istat.thre_int = 0;
        uart->istat.thre_int = 0;
      break;
      break;
    case UART_FCR:
    case UART_FCR:
      uart->regs.fcr = value & UART_VALID_FCR;
      uart->regs.fcr = value & UART_VALID_FCR;
Line 121... Line 266...
        uart->istat.txbuf_full = 0;
        uart->istat.txbuf_full = 0;
        uart->regs.lsr |= UART_LSR_TXBUFE;
        uart->regs.lsr |= UART_LSR_TXBUFE;
 
 
        // For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
        // For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
        uart->istat.thre_int = (uart->fifo_len == 16);
        uart->istat.thre_int = (uart->fifo_len == 16);
 
 
 
        SCHED_FIND_REMOVE(uart_tx_send, uart);
      }
      }
      if (value & UART_FCR_RRXFI) {
      if (value & UART_FCR_RRXFI) {
        uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
        uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
        uart->istat.rxbuf_full = 0;
        uart->istat.rxbuf_full = 0;
        uart->regs.lsr &= ~UART_LSR_RDRDY;
        uart->regs.lsr &= ~UART_LSR_RDRDY;
Line 132... Line 279...
      break;
      break;
    case UART_IER:
    case UART_IER:
      uart->regs.ier = value & UART_VALID_IER;
      uart->regs.ier = value & UART_VALID_IER;
      break;
      break;
    case UART_LCR:
    case UART_LCR:
 
      if((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) {
 
        if((value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
 
          /* Schedule a job to send the break char */
 
          SCHED_FIND_REMOVE(uart_char_clock, uart);
 
          SCHED_ADD(uart_send_break, uart, 0);
 
        }
 
        if(!(value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
 
          /* Schedule a job to start sending characters */
 
          SCHED_ADD(uart_tx_send, uart, 0);
 
          /* Remove the uart_send_break job just in case it has not run yet */
 
          SCHED_FIND_REMOVE(uart_char_clock, uart);
 
        }
 
      }
      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:
      uart->regs.mcr = value & UART_VALID_MCR;
      uart->regs.mcr = value & UART_VALID_MCR;
Line 237... Line 397...
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
    exit (1);
    exit (1);
  }
  }
}
}
 
 
static void send_char (struct dev_16450 *uart, int bits_send)
 
{
 
  PRINTF ("%c", (char)uart->iregs.txser);
 
  TRACE("TX \'%c\' via UART at %"PRIxADDR"...\n", (char)uart->iregs.txser,
 
        uart->baseaddr);
 
  if (uart->regs.mcr & UART_MCR_LOOP)
 
    uart->iregs.loopback = uart->iregs.txser;
 
  else {
 
    /* Send to either VAPI or to file */
 
    if (uart->vapi_id) {
 
      int par, pe, fe, nbits;
 
      int j, data;
 
      unsigned long packet = 0;
 
 
 
      nbits = MIN (bits_send, (uart->regs.lcr & UART_LCR_WLEN8) + 5);
 
      /* Encode a packet */
 
      packet = uart->iregs.txser & ((1 << nbits) - 1);
 
 
 
      /* Calculate parity */
 
      for (j = 0, par = 0; j < nbits; j++)
 
        par ^= (packet >> j) & 1;
 
 
 
      if (uart->regs.lcr & UART_LCR_PARITY) {
 
        if (uart->regs.lcr & UART_LCR_SPAR) {
 
          packet |= 1 << nbits;
 
        } else {
 
          if (uart->regs.lcr & UART_LCR_EPAR)
 
            packet |= par << nbits;
 
          else
 
            packet |= (par ^ 1) << nbits;
 
        }
 
        nbits++;
 
      }
 
      packet |= 1 << (nbits++);
 
      if (uart->regs.lcr & UART_LCR_STOP)
 
        packet |= 1 << (nbits++);
 
 
 
      /* Decode a packet */
 
      nbits = (uart->vapi.lcr & UART_LCR_WLEN8) + 5;
 
      data = packet & ((1 << nbits) - 1);
 
 
 
      /* Calculate parity, including parity bit */
 
      for (j = 0, par = 0; j < nbits + 1; j++)
 
        par ^= (packet >> j) & 1;
 
 
 
      if (uart->vapi.lcr & UART_LCR_PARITY) {
 
        if (uart->vapi.lcr & UART_LCR_SPAR) {
 
          pe = !((packet >> nbits) & 1);
 
        } else {
 
          if (uart->vapi.lcr & UART_LCR_EPAR)
 
            pe = par != 0;
 
          else
 
            pe = par != 1;
 
        }
 
        nbits++;
 
      } else
 
        pe = 0;
 
 
 
      fe = ((packet >> (nbits++)) & 1) ^ 1;
 
      if (uart->vapi.lcr & UART_LCR_STOP)
 
        fe |= ((packet >> (nbits++)) & 1) ^ 1;
 
 
 
      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);
 
      PRINTF ("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);
 
    } else {
 
      char buffer[1] = { uart->iregs.txser & 0xFF };
 
      channel_write(uart->channel, buffer, 1);
 
    }
 
  }
 
  uart->istat.txser_full = 0;
 
  uart->istat.txser_clks = 0;
 
}
 
 
 
/* Adds a character to the FIFO */
/* Adds a character to the FIFO */
 
 
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)
Line 354... Line 438...
    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 *****************/
 
  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) {
 
//      uart->regs.lsr |= UART_LSR_TXBUFE;
 
    if (uart->istat.txbuf_full) {
 
      uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
 
      uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
 
      uart->istat.txser_full = 1;
 
      uart->istat.txbuf_full--;
 
      uart->regs.lsr &= ~UART_LSR_TXSERE;
 
 
 
      // When UART is in either character mode, i.e. 16450 emulation mode, or FIFO mode,
 
      // the THRE interrupt is raised when THR transitions from full to empty.
 
      if (!uart->istat.txbuf_full) {
 
        uart->istat.thre_int = 1;
 
        uart->regs.lsr |= UART_LSR_TXBUFE;
 
      }
 
    } else {
 
      uart->regs.lsr |= UART_LSR_TXSERE;
 
    }
 
  } else if (uart->char_clks <= uart->istat.txser_clks++) {
 
    send_char(uart, (uart->regs.lcr & UART_LCR_WLEN8) + 5); /* We've sent all bits */
 
  } else {
 
    /* We are still sending char here*/
 
 
 
    /* Check if we set the break bit */
 
    if (uart->regs.lcr & UART_LCR_SBC) {
 
      if (!uart->vapi.break_sent) {
 
#if 0
 
        /* Send broken frame */
 
        int nbits_sent = ((uart->regs.lcr & UART_LCR_WLEN8) + 5) * (uart->istat.txser_clks - 1) / uart->char_clks;
 
        send_char(i, nbits_sent);
 
#endif
 
        /* Send one break signal */
 
        vapi_send (uart->vapi_id, UART_LCR_SBC << 8);
 
        uart->vapi.break_sent = 1;
 
      }
 
      /* mark as character was sent */
 
      uart->istat.txser_full = 0;
 
      uart->istat.txser_clks = 0;
 
    } else
 
      uart->vapi.break_sent = 0;
 
 
 
  }
 
 
 
  /***************** Receive *****************/
  /***************** Receive *****************/
 
 
  /* Is there a break? */
  /* Is there a break? */
  if (uart->vapi.cur_break) {
  if (uart->vapi.cur_break) {
    uart->vapi.cur_break_cnt++;
    uart->vapi.cur_break_cnt++;
Line 601... Line 638...
    uart->fifo_len = 1;
    uart->fifo_len = 1;
 
 
  uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
  uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
  uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
  uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
 
 
  uart->istat.txser_full = uart->istat.rxser_full = 0;
  uart->istat.rxser_full = 0;
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
 
 
  uart->istat.txser_clks = uart->istat.rxser_clks = 0;
  uart->istat.rxser_clks = 0;
 
 
  uart->istat.thre_int = 0;
  uart->istat.thre_int = 0;
  uart->istat.break_set = 0;
  uart->istat.break_set = 0;
  uart->istat.timeout_count = 0;
  uart->istat.timeout_count = 0;
 
 
Line 630... Line 667...
  uart->regs.ier = 0;
  uart->regs.ier = 0;
  uart->regs.iir = 0;
  uart->regs.iir = 0;
  uart->regs.fcr = 0;
  uart->regs.fcr = 0;
  uart->regs.lcr = UART_LCR_RESET;
  uart->regs.lcr = UART_LCR_RESET;
  uart->regs.mcr = 0;
  uart->regs.mcr = 0;
  uart->regs.lsr = 0;
  uart->regs.lsr = UART_LSR_TXBUFE | UART_LSR_TXSERE;
  uart->regs.msr = 0;
  uart->regs.msr = 0;
  uart->regs.scr = 0;
  uart->regs.scr = 0;
 
 
  uart->vapi.cur_break = uart->vapi.cur_break_cnt = uart->vapi.next_break = 0;
  uart->vapi.cur_break = uart->vapi.cur_break_cnt = uart->vapi.next_break = 0;
  uart->vapi.next_break_cnt = -1;
  uart->vapi.next_break_cnt = -1;
  uart->vapi.break_sent = 0;
 
  uart->vapi.skew = 0;
  uart->vapi.skew = 0;
  uart->vapi.lcr = 0;
  uart->vapi.lcr = 0;
  uart->vapi.dll = 0;
  uart->vapi.dll = 0;
  uart->vapi.char_clks = 0;
  uart->vapi.char_clks = 0;
 
 
Line 674... Line 710...
  PRINTF("\nInternal registers (sim debug):\n");
  PRINTF("\nInternal registers (sim debug):\n");
  PRINTF("RXSER: %.2lx  TXSER: %.2lx\n", uart->iregs.rxser, uart->iregs.txser);
  PRINTF("RXSER: %.2lx  TXSER: %.2lx\n", uart->iregs.rxser, uart->iregs.txser);
 
 
  PRINTF("\nInternal status (sim debug):\n");
  PRINTF("\nInternal status (sim debug):\n");
  PRINTF("char_clks: %ld\n", uart->char_clks);
  PRINTF("char_clks: %ld\n", uart->char_clks);
  PRINTF("rxser_clks: %ld  txser_clks: %ld\n", uart->istat.rxser_clks,
  PRINTF("rxser_clks: %ld\n", uart->istat.rxser_clks);
         uart->istat.txser_clks);
  PRINTF("rxser: %d\n", uart->istat.rxser_full);
  PRINTF("rxser: %d  txser: %d\n", uart->istat.rxser_full, uart->istat.txser_full);
 
  PRINTF("rxbuf_full: %d  txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
  PRINTF("rxbuf_full: %d  txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
  PRINTF("Using IRQ%i\n", uart->irq);
  PRINTF("Using IRQ%i\n", uart->irq);
  if (uart->vapi_id)
  if (uart->vapi_id)
    PRINTF ("Connected to vapi ID=%lx\n\n", uart->vapi_id);
    PRINTF ("Connected to vapi ID=%lx\n\n", uart->vapi_id);
  /* TODO: replace by a channel_status
  /* TODO: replace by a channel_status

powered by: WebSVN 2.1.0

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