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 1500 and 1501

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

Rev 1500 Rev 1501
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_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);
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)
Line 218... Line 224...
    uart->regs.lsr |= UART_LSR_TXBUFE;
    uart->regs.lsr |= UART_LSR_TXBUFE;
    uart->istat.thre_int = 1;
    uart->istat.thre_int = 1;
  }
  }
}
}
 
 
 
/*-------------------------------------------------------[ 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. */
/* 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 341... Line 460...
      }
      }
      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--;
      }
        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)
      if (uart->istat.rxbuf_full)
        uart->regs.lsr |= UART_LSR_RDRDY;
        uart->regs.lsr |= UART_LSR_RDRDY | uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
      else
      else
        uart->regs.lsr &= ~UART_LSR_RDRDY;
        uart->regs.lsr &= ~UART_LSR_RDRDY;
 
 
      uart->istat.timeout_count = 0;
      uart->istat.timeout_count = 0;
      break;
      break;
Line 386... Line 507...
  return value;
  return value;
}
}
 
 
/*--------------------------------------------------------[ VAPI handling ]---*/
/*--------------------------------------------------------[ VAPI handling ]---*/
/* Decodes the read vapi command */
/* 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;
  int received = 0;
 
 
  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];
Line 423... Line 545...
          /* 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)
          if(uart->regs.lcr & UART_LCR_PARITY)
            uart->iregs.rxser |= UART_LSR_PARITY << 8;
            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;
        received = 1;
        break;
        break;
      case 0x01:
      case 0x01:
        uart->vapi.dll = (data >> 0) & 0xff;
        uart->vapi.dll = (data >> 0) & 0xff;
        uart->vapi.dlh = (data >> 8) & 0xff;
        uart->vapi.dlh = (data >> 8) & 0xff;
Line 437... Line 562...
        break;
        break;
      case 0x03:
      case 0x03:
        uart->vapi.skew = (signed short)(data & 0xffff);
        uart->vapi.skew = (signed short)(data & 0xffff);
        break;
        break;
      case 0x04:
      case 0x04:
        uart->vapi.next_break_cnt = data & 0xffff;
        if((data >> 16) & 1) {
        uart->vapi.next_break = (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;
        break;
      default:
      default:
        WARN("WARNING: Invalid vapi command %02lx\n", data >> 24);
        WARN("WARNING: Invalid vapi command %02lx\n", data >> 24);
        break;
        break;
      }
      }
Line 459... Line 601...
  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);
  }
  }
}
  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
/* Simulation hook. Must be called every clock cycle to simulate all UART
   devices. It does internal functional UART simulation. */
   devices. It does internal functional UART simulation. */
void uart_clock16 (void *dat)
void uart_clock16 (void *dat)
{
{
  struct dev_16450 *uart = dat;
  struct dev_16450 *uart = dat;
  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");
  TRACE("Running uart clock:\n");
Line 496... Line 623...
  /* 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");
  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 *****************/
  /***************** Loopback *****************/
  if (uart->regs.mcr & UART_MCR_LOOP) {
  if (uart->regs.mcr & UART_MCR_LOOP) {
    TRACE("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))
Line 592... Line 649...
  }
  }
 
 
  if (uart->regs.lsr & UART_LSR_RDRDY)
  if (uart->regs.lsr & UART_LSR_RDRDY)
    uart->istat.timeout_count++;
    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. */
  /* Interrupt detection in proper priority order. */
  uart->regs.iir = UART_IIR_NO_INT;
  uart->regs.iir = UART_IIR_NO_INT;
  if (uart->regs.ier & UART_IER_RLSI &&                    /* Receiver LS */
  if (uart->regs.ier & UART_IER_RLSI &&                    /* Receiver LS */
      uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
      uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
        | UART_LSR_FRAME | UART_LSR_BREAK)) {
        | UART_LSR_FRAME | UART_LSR_BREAK)) {
Line 658... Line 708...
    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.rxser_full = 0;
 
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
 
 
  uart->istat.rxser_clks = 0;
 
 
 
  uart->istat.thre_int = 0;
  uart->istat.thre_int = 0;
  uart->istat.break_set = 0;
 
  uart->istat.timeout_count = 0;
  uart->istat.timeout_count = 0;
 
 
  // For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
  // For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
  uart->istat.thre_int = (uart->fifo_len == 16);
  uart->istat.thre_int = (uart->fifo_len == 16);
 
 
  uart->char_clks = 0;
  uart->char_clks = 0;
  uart->slowdown = UART_FGETC_SLOWDOWN;
 
 
 
  uart->iregs.txser = 0;
  uart->iregs.txser = 0;
  uart->iregs.rxser = 0;
  uart->iregs.rxser = 0;
  uart->iregs.loopback = 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.txbuf, 0, sizeof(uart->regs.txbuf));
  memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
  memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
 
 
  uart->regs.dll = 0;
  uart->regs.dll = 0;
Line 691... Line 738...
  uart->regs.mcr = 0;
  uart->regs.mcr = 0;
  uart->regs.lsr = UART_LSR_TXBUFE | UART_LSR_TXSERE;
  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.next_break_cnt = -1;
 
  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;
 
 
  uart->vapi_buf_head_ptr = 0;
  uart->vapi_buf_head_ptr = 0;
  uart->vapi_buf_tail_ptr = 0;
  uart->vapi_buf_tail_ptr = 0;
  memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
  memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
 
 
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
 
  uart_sched_recv_check(uart);
}
}
 
 
/* Print register values on stdout. */
/* Print register values on stdout. */
void uart_status(void *dat)
void uart_status(void *dat)
{
{
Line 730... Line 776...
  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\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("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.