LOGIN   :::   RECOVER PASS   :::   GET ACCOUNT    
Browse
  • Projects
  • Code (CVS)
  • Forums
  • News
  • Articles
  • Polls
  •  
    OpenCores
  • FAQ
  • CVS HowTo
  • Mission
  • Media
  • Tools
  • Advertise
  • Mirrors
  • Logos
  • Contact us
  • Find Resources
  • Job Opportunity
  •  
    Tools
  • Search
      
  • Download Cores (CVSGet)
  •  
    More
  • Wishbone
  • Perlilog
  • EDA tools
  • OpenTech CD
  •  
    Navigation: All forums > Openrisc > Message List > Message Post

    Message

    Reply | Reply all
    Date Prev | Date Next | Thread Prev | Thread Next Date Index | Thread Index

    From: György 'nog' Jeney<nog@s...>
    Date: Sun May 29 17:52:56 CEST 2005
    Subject: [openrisc] [or1ksim #100] UART: Move RX logic out of uart_clock16 [2/6]
    Top
    Hi,

    Changelog says it all.

    ChangeLog:
    * Move RX logic out of uart_clock16.

    nog.
    -------------- next part --------------
    --- ../or1ksim-patch/peripheral/16450.c 2005-05-29 15:50:19.000000000 +0200
    +++ peripheral/16450.c 2005-05-29 15:49:27.000000000 +0200
    @@ -52,6 +52,12 @@ DEFAULT_DEBUG_CHANNEL(uart);

    #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 @@ void uart_tx_send(void *dat)
    }
    }

    +/*-------------------------------------------------------[ 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 @@ uint8_t uart_read_byte(oraddr_t addr, vo 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 @@ uint8_t uart_read_byte(oraddr_t addr, vo /*--------------------------------------------------------[ 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 @@ static void uart_vapi_cmd(struct dev_164 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 @@ static void uart_vapi_cmd(struct dev_164 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,22 +603,8 @@ void uart_vapi_read (unsigned long id, u fprintf (stderr, "FATAL: uart VAPI buffer to small.\n"); exit (1); } -} - -/* 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; + if(!uart->istat.receiveing) + uart_vapi_cmd(uart); } /* Simulation hook. Must be called every clock cycle to simulate all UART @@ -484,7 +612,6 @@ void uart_add_char (struct dev_16450 *ua 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 @@ void uart_clock16 (void *dat) 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 @@ void uart_clock16 (void *dat) 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,24 +710,21 @@ void uart_reset(void *dat) 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 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 @@ void uart_reset(void *dat) 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 @@ void uart_reset(void *dat) 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 @@ void uart_status(void *dat) 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) --- ../or1ksim-patch/peripheral/16450.h 2005-05-29 15:50:16.000000000 +0200 +++ peripheral/16450.h 2005-05-29 15:49:00.000000000 +0200 @@ -57,13 +57,12 @@ struct dev_16450 { 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 @@ struct dev_16450 { 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 @@ struct dev_16450 { /* Length of FIFO, 16 for 16550, 1 for 16450 */ int fifo_len; - /* fgetc slowdown */ - int slowdown; - struct channel *channel; /* Configuration */

     
    Copyright (c) 1999 OPENCORES.ORG. All rights reserved.