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:51:57 CEST 2005
    Subject: [openrisc] [or1ksim #98] UART: Move TX logic out of uart_clock16 [0/6]
    Top
    Hi,

    This is the first of 7 patches that have the ultimate effect of removeing the
    hughe uart_clock16 function. I have ensured that the acv_uart test passes after
    each patch so hopefully there shouldn't be any regresions.

    ChangeLog:
    * Move TX logic out of uart_clock16.

    nog.
    -------------- next part --------------
    --- /hd0/or1k/or1k/or1ksim/peripheral/16450.c 2005-05-29 11:54:30.000000000 +0200
    +++ peripheral/16450.c 2005-05-29 14:16:38.000000000 +0200
    @@ -52,6 +52,8 @@ DEFAULT_DEBUG_CHANNEL(uart);

    #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())
    before a single character is transmitted or received. */
    static unsigned long char_clks(int dll, int dlh, int lcr)
    @@ -76,6 +78,148 @@ static unsigned long char_clks(int dll,
    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. */ void uart_write_byte(oraddr_t addr, uint8_t value, void *dat) { @@ -99,14 +243,15 @@ void uart_write_byte(oraddr_t addr, uint switch (addr) { case UART_TXBUF: + uart->regs.lsr &= ~UART_LSR_TXBUFE; if (uart->istat.txbuf_full < uart->fifo_len) { - uart->istat.txbuf_full++; uart->regs.txbuf[uart->istat.txbuf_head] = value; 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 uart->regs.txbuf[uart->istat.txbuf_head] = value; - uart->regs.lsr &= ~(UART_LSR_TXSERE | UART_LSR_TXBUFE); if (uart->regs.iir & UART_IIR_THRI) uart->istat.thre_int = 0; break; @@ -123,6 +268,8 @@ void uart_write_byte(oraddr_t addr, uint // For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty uart->istat.thre_int = (uart->fifo_len == 16); + + SCHED_FIND_REMOVE(uart_tx_send, uart); } if (value & UART_FCR_RRXFI) { uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0; @@ -134,6 +281,19 @@ void uart_write_byte(oraddr_t addr, uint uart->regs.ier = value & UART_VALID_IER; break; 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->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr); break; @@ -239,82 +399,6 @@ void uart_vapi_read (unsigned long id, u } } -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 */ void uart_add_char (struct dev_16450 *uart, int ch) @@ -356,53 +440,6 @@ void uart_clock16 (void *dat) 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 *****************/ /* Is there a break? */ @@ -603,10 +640,10 @@ 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.txser_full = uart->istat.rxser_full = 0; + uart->istat.rxser_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.break_set = 0; @@ -632,13 +669,12 @@ void uart_reset(void *dat) uart->regs.fcr = 0; uart->regs.lcr = UART_LCR_RESET; uart->regs.mcr = 0; - uart->regs.lsr = 0; + uart->regs.lsr = UART_LSR_TXBUFE | UART_LSR_TXSERE; 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.break_sent = 0; uart->vapi.skew = 0; uart->vapi.lcr = 0; uart->vapi.dll = 0; @@ -676,9 +712,8 @@ void uart_status(void *dat) PRINTF("\nInternal status (sim debug):\n"); PRINTF("char_clks: %ld\n", uart->char_clks); - PRINTF("rxser_clks: %ld txser_clks: %ld\n", uart->istat.rxser_clks, - uart->istat.txser_clks); - PRINTF("rxser: %d txser: %d\n", uart->istat.rxser_full, uart->istat.txser_full); + 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) --- /hd0/or1k/or1k/or1ksim/peripheral/16450.h 2005-03-31 16:39:43.000000000 +0200 +++ peripheral/16450.h 2005-05-29 13:21:49.000000000 +0200 @@ -57,13 +57,11 @@ struct dev_16450 { int txbuf_tail; int rxbuf_head; int rxbuf_tail; - unsigned int txser_full; unsigned int rxser_full; unsigned int txbuf_full; unsigned int rxbuf_full; unsigned thre_int; unsigned break_set; - unsigned long txser_clks; unsigned long rxser_clks; unsigned timeout_count; } istat; /* Internal status */ @@ -81,7 +79,6 @@ struct dev_16450 { int next_break_cnt; int cur_break; int cur_break_cnt; - int break_sent; } vapi; /* Required by VAPI - circular buffer */

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