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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 1396

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 31 lampret
/* 16450.c -- Simulation of 8250/16450 serial UART
2
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
3
 
4
This file is part of OpenRISC 1000 Architectural Simulator.
5
 
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
/* This is functional simulation of 8250/16450 UARTs. Since we RX/TX data
21
   via file streams, we can't simulate modem control lines coming from the
22
   DCE and similar details of communication with the DCE.
23
 
24
   This simulated UART device is intended for basic UART device driver
25
   verification. From device driver perspective this device looks like a
26
   regular UART but never reports and modem control lines changes (the
27
   only DCE responses are incoming characters from the file stream).
28
*/
29
 
30
#include <stdlib.h>
31
#include <stdio.h>
32
#include <string.h>
33
 
34 1350 nogj
#include "config.h"
35
 
36
#ifdef HAVE_INTTYPES_H
37
#include <inttypes.h>
38
#endif
39
 
40
#include "port.h"
41
#include "arch.h"
42 235 erez
#include "abstract.h"
43 31 lampret
#include "16450.h"
44
#include "sim-config.h"
45 102 lampret
#include "pic.h"
46 336 markom
#include "vapi.h"
47 805 markom
#include "sched.h"
48 1073 rprescott
#include "channel.h"
49 1308 phoenix
#include "debug.h"
50 31 lampret
 
51 1392 nogj
DEFAULT_DEBUG_CHANNEL(uart);
52
 
53 409 markom
#define MIN(a,b) ((a) < (b) ? (a) : (b))
54
 
55 31 lampret
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
56
   before a single character is transmitted or received. */
57 355 markom
static unsigned long char_clks(int dll, int dlh, int lcr)
58 31 lampret
{
59 1396 nogj
  unsigned int bauds_per_char = 2;
60 806 markom
  unsigned long char_clks = ((dlh << 8) + dll);
61 355 markom
 
62
  if (lcr & UART_LCR_PARITY)
63 1396 nogj
    bauds_per_char += 2;
64 31 lampret
 
65 355 markom
  /* stop bits 1 or two */
66
  if (lcr & UART_LCR_STOP)
67 1396 nogj
    bauds_per_char += 4;
68 355 markom
  else
69
    if ((lcr & 0x3) != 0)
70 1396 nogj
      bauds_per_char += 2;
71 355 markom
    else
72 1396 nogj
      bauds_per_char += 3;
73 355 markom
 
74 1396 nogj
  bauds_per_char += 10 + ((lcr & 0x3) << 1);
75 355 markom
 
76 1396 nogj
  return (char_clks * bauds_per_char) >> 1;
77 31 lampret
}
78
 
79
/* Set a specific UART register with value. */
80 1359 nogj
void uart_write_byte(oraddr_t addr, uint32_t value, void *dat)
81 31 lampret
{
82 1367 nogj
  struct dev_16450 *uart = dat;
83 355 markom
 
84 1392 nogj
  TRACE("uart_write_byte(%"PRIxADDR",%02"PRIx32")\n", addr, value);
85 341 markom
 
86 1367 nogj
  if (uart->regs.lcr & UART_LCR_DLAB) {
87 355 markom
    switch (addr % UART_ADDR_SPACE) {
88
      case UART_DLL:
89 1367 nogj
        uart->regs.dll = value;
90
        uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
91 1392 nogj
        TRACE("\tSetting char_clks to %li (%02x, %02x, %02x)\n", uart->char_clks,
92
              uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
93 355 markom
        return;
94
      case UART_DLH:
95 1367 nogj
        uart->regs.dlh = value;
96 355 markom
        return;
97
    }
98
  }
99
 
100
  switch (addr % UART_ADDR_SPACE) {
101
    case UART_TXBUF:
102 1367 nogj
      if (uart->istat.txbuf_full < uart->fifo_len) {
103
        uart->istat.txbuf_full++;
104
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
105
        uart->istat.txbuf_head = (uart->istat.txbuf_head + 1) % uart->fifo_len;
106 355 markom
      } else
107 1367 nogj
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
108 341 markom
 
109 1367 nogj
      uart->regs.lsr &= ~(UART_LSR_TXSERE | UART_LSR_TXBUFE);
110
      if (uart->regs.iir & UART_IIR_THRI)
111
        uart->istat.thre_int = 0;
112 355 markom
      break;
113 409 markom
    case UART_FCR:
114 1367 nogj
      uart->regs.fcr = value & UART_VALID_FCR;
115
      if ((uart->fifo_len == 1 && (value & UART_FCR_FIE))
116
       || (uart->fifo_len != 1 && !(value & UART_FCR_FIE)))
117 409 markom
        value |= UART_FCR_RRXFI | UART_FCR_RTXFI;
118 1367 nogj
      uart->fifo_len = (value & UART_FCR_FIE) ? 16 : 1;
119 409 markom
      if (value & UART_FCR_RTXFI) {
120 1367 nogj
        uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
121
        uart->istat.txbuf_full = 0;
122
        uart->regs.lsr |= UART_LSR_TXBUFE;
123 1145 sfurman
 
124
        // For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
125 1367 nogj
        uart->istat.thre_int = (uart->fifo_len == 16);
126 409 markom
      }
127
      if (value & UART_FCR_RRXFI) {
128 1367 nogj
        uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
129
        uart->istat.rxbuf_full = 0;
130
        uart->regs.lsr &= ~UART_LSR_RDRDY;
131 409 markom
      }
132
      break;
133 355 markom
    case UART_IER:
134 1367 nogj
      uart->regs.ier = value & UART_VALID_IER;
135 355 markom
      break;
136
    case UART_LCR:
137 1367 nogj
      uart->regs.lcr = value & UART_VALID_LCR;
138
      uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
139 355 markom
      break;
140
    case UART_MCR:
141 1367 nogj
      uart->regs.mcr = value & UART_VALID_MCR;
142 355 markom
      break;
143
    case UART_SCR:
144 1367 nogj
      uart->regs.scr = value;
145 355 markom
      break;
146
    default:
147 1392 nogj
      TRACE("write out of range (addr %x)\n", addr);
148 355 markom
  }
149 31 lampret
}
150
 
151
/* Read a specific UART register. */
152 1359 nogj
uint32_t uart_read_byte(oraddr_t addr, void *dat)
153 31 lampret
{
154 1367 nogj
  struct dev_16450 *uart = dat;
155 1350 nogj
  uint8_t value = 0;
156 355 markom
 
157 1392 nogj
  TRACE("uart_read_byte(%"PRIxADDR")", addr);
158 355 markom
 
159 1367 nogj
  if (uart->regs.lcr & UART_LCR_DLAB) {
160 355 markom
    switch (addr % UART_ADDR_SPACE) {
161
      case UART_DLL:
162 1367 nogj
        value = uart->regs.dll;
163 1392 nogj
        TRACE("= %"PRIx8"\n", value);
164 355 markom
        return value;
165
      case UART_DLH:
166 1367 nogj
        value = uart->regs.dlh;
167 1392 nogj
        TRACE("= %"PRIx8"\n", value);
168 355 markom
        return value;
169
    }
170
  }
171
 
172
  switch (addr % UART_ADDR_SPACE) {
173
    case UART_RXBUF:
174 409 markom
      { /* Print out FIFO for debugging */
175
        int i;
176 1392 nogj
        TRACE("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len,
177
              uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
178 1367 nogj
        for (i = 0; i < uart->istat.rxbuf_full; i++)
179 1392 nogj
          TRACE("%02x ", uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
180
        TRACE(")");
181 409 markom
      }
182 1367 nogj
      if (uart->istat.rxbuf_full) {
183
        value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
184
        uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
185
        uart->istat.rxbuf_full--;
186 355 markom
      }
187
 
188 1367 nogj
      if (uart->istat.rxbuf_full)
189
        uart->regs.lsr |= UART_LSR_RDRDY;
190 355 markom
      else
191 1367 nogj
        uart->regs.lsr &= ~UART_LSR_RDRDY;
192 409 markom
 
193 1367 nogj
      uart->istat.timeout_count = 0;
194 355 markom
      break;
195
    case UART_IER:
196 1367 nogj
      value = uart->regs.ier & UART_VALID_IER;
197 355 markom
      break;
198
    case UART_IIR:
199 1367 nogj
      value = (uart->regs.iir & UART_VALID_IIR) | 0xc0;
200
      if (uart->regs.iir & UART_IIR_THRI)
201
        uart->istat.thre_int = 0;
202 355 markom
      break;
203
    case UART_LCR:
204 1367 nogj
      value = uart->regs.lcr & UART_VALID_LCR;
205 355 markom
      break;
206
    case UART_MCR:
207
      value = 0;
208
      break;
209
    case UART_LSR:
210 1367 nogj
      value = uart->regs.lsr & UART_VALID_LSR;
211
      uart->regs.lsr &=
212 409 markom
        ~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
213
         | UART_LSR_FRAME | UART_LSR_RXERR);
214 355 markom
      break;
215
    case UART_MSR:
216 1367 nogj
      value = uart->regs.msr & UART_VALID_MSR;
217
      uart->regs.msr = 0;
218 355 markom
      break;
219
    case UART_SCR:
220 1367 nogj
      value = uart->regs.scr;
221 355 markom
      break;
222
    default:
223 1392 nogj
      TRACE("read out of range (addr %"PRIxADDR")\n", addr);
224 355 markom
  }
225 1392 nogj
  TRACE(" = %"PRIx8"\n", value);
226 355 markom
  return value;
227 31 lampret
}
228
 
229 336 markom
/* Function that handles incoming VAPI data.  */
230 1366 nogj
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
231 336 markom
{
232 1367 nogj
  struct dev_16450 *uart = dat;
233 1392 nogj
  TRACE("UART: id %08lx, data %08lx\n", id, data);
234 1367 nogj
  uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
235
  uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
236
  if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
237 341 markom
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
238
    exit (1);
239
  }
240
}
241 336 markom
 
242 1367 nogj
static void send_char (struct dev_16450 *uart, int bits_send)
243 409 markom
{
244 1367 nogj
  PRINTF ("%c", (char)uart->iregs.txser);
245 1392 nogj
  TRACE("TX \'%c\' via UART at %"PRIxADDR"...\n", (char)uart->iregs.txser,
246 1367 nogj
        uart->baseaddr);
247
  if (uart->regs.mcr & UART_MCR_LOOP)
248
    uart->iregs.loopback = uart->iregs.txser;
249 409 markom
  else {
250
    /* Send to either VAPI or to file */
251 1367 nogj
    if (uart->vapi_id) {
252 409 markom
      int par, pe, fe, nbits;
253
      int j, data;
254
      unsigned long packet = 0;
255
 
256 1367 nogj
      nbits = MIN (bits_send, (uart->regs.lcr & UART_LCR_WLEN8) + 5);
257 409 markom
      /* Encode a packet */
258 1367 nogj
      packet = uart->iregs.txser & ((1 << nbits) - 1);
259 409 markom
 
260
      /* Calculate parity */
261
      for (j = 0, par = 0; j < nbits; j++)
262
        par ^= (packet >> j) & 1;
263
 
264 1367 nogj
      if (uart->regs.lcr & UART_LCR_PARITY) {
265
        if (uart->regs.lcr & UART_LCR_SPAR) {
266 409 markom
          packet |= 1 << nbits;
267
        } else {
268 1367 nogj
          if (uart->regs.lcr & UART_LCR_EPAR)
269 409 markom
            packet |= par << nbits;
270
          else
271
            packet |= (par ^ 1) << nbits;
272
        }
273
        nbits++;
274
      }
275
      packet |= 1 << (nbits++);
276 1367 nogj
      if (uart->regs.lcr & UART_LCR_STOP)
277 409 markom
        packet |= 1 << (nbits++);
278
 
279
      /* Decode a packet */
280 1367 nogj
      nbits = (uart->vapi.lcr & UART_LCR_WLEN8) + 5;
281 409 markom
      data = packet & ((1 << nbits) - 1);
282
 
283
      /* Calculate parity, including parity bit */
284
      for (j = 0, par = 0; j < nbits + 1; j++)
285
        par ^= (packet >> j) & 1;
286
 
287 1367 nogj
      if (uart->vapi.lcr & UART_LCR_PARITY) {
288
        if (uart->vapi.lcr & UART_LCR_SPAR) {
289 409 markom
          pe = !((packet >> nbits) & 1);
290
        } else {
291 1367 nogj
          if (uart->vapi.lcr & UART_LCR_EPAR)
292 409 markom
            pe = par != 0;
293
          else
294
            pe = par != 1;
295
        }
296
        nbits++;
297
      } else
298
        pe = 0;
299
 
300
      fe = ((packet >> (nbits++)) & 1) ^ 1;
301 1367 nogj
      if (uart->vapi.lcr & UART_LCR_STOP)
302 409 markom
        fe |= ((packet >> (nbits++)) & 1) ^ 1;
303
 
304 1392 nogj
      TRACE ("lcr vapi %02x, uart %02x\n", uart->vapi.lcr, uart->regs.lcr);
305 1367 nogj
      data |= (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi.lcr << 8);
306
      PRINTF ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
307 1392 nogj
      TRACE ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
308 1367 nogj
      vapi_send (uart->vapi_id, data);
309 409 markom
    } else {
310 1367 nogj
      char buffer[1] = { uart->iregs.txser & 0xFF };
311
      channel_write(uart->channel, buffer, 1);
312 409 markom
    }
313
  }
314 1367 nogj
  uart->istat.txser_full = 0;
315
  uart->istat.txser_clks = 0;
316 409 markom
}
317
 
318 411 markom
/* Adds a character to the FIFO */
319
 
320 1367 nogj
void uart_add_char (struct dev_16450 *uart, int ch)
321 411 markom
{
322 1367 nogj
  if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
323
    uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
324 411 markom
  else {
325 1392 nogj
    TRACE("add %02x\n", ch);
326 1367 nogj
    uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
327
    uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
328
    uart->istat.rxbuf_full++;
329 411 markom
  }
330 1367 nogj
  uart->regs.lsr |= UART_LSR_RDRDY;
331
  uart->istat.timeout_count = 0;
332 411 markom
}
333
 
334 806 markom
/* Simulation hook. Must be called every clock cycle to simulate all UART
335
   devices. It does internal functional UART simulation. */
336 1367 nogj
void uart_clock16 (void *dat)
337 806 markom
{
338 1367 nogj
  struct dev_16450 *uart = dat;
339 806 markom
  int retval;
340 1073 rprescott
 
341 821 markom
  /* Schedule for later */
342 1390 nogj
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
343 1392 nogj
 
344
  TRACE("Running uart clock:\n");
345 821 markom
 
346 806 markom
  /* If VAPI is not selected, UART communicates with two file streams;
347
     if VAPI is selected, we use VAPI streams.  */
348
  /* if txfs is corrupted, skip this uart. */
349 1367 nogj
  if (!uart->vapi_id && !channel_ok(uart->channel)) return;
350 1392 nogj
 
351
  TRACE("\tChannel stream or VAPI checks out ok\n");
352 806 markom
 
353 1367 nogj
  if (uart->vapi.next_break_cnt >= 0)
354
    if (--uart->vapi.next_break_cnt < 0) {
355
      if (!(uart->vapi.cur_break = uart->vapi.next_break))
356
        uart->istat.break_set = 0;
357 806 markom
    }
358 821 markom
 
359 806 markom
  /***************** Transmit *****************/
360 1392 nogj
  TRACE("\tuart->istat.txser_full = %i\n", uart->istat.txser_full);
361
  TRACE("\tuart->istat.txbuf_full = %i\n", uart->istat.txser_full);
362
  TRACE("\tuart->char_clks = %li\n", uart->char_clks);
363 1367 nogj
  if (!uart->istat.txser_full) {
364
//      uart->regs.lsr |= UART_LSR_TXBUFE;
365
    if (uart->istat.txbuf_full) {
366
      uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
367
      uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
368
      uart->istat.txser_full = 1;
369
      uart->istat.txbuf_full--;
370
      uart->regs.lsr &= ~UART_LSR_TXSERE;
371 1143 sfurman
 
372
      // When UART is in either character mode, i.e. 16450 emulation mode, or FIFO mode,
373
      // the THRE interrupt is raised when THR transitions from full to empty.
374 1367 nogj
      if (!uart->istat.txbuf_full) {
375
        uart->istat.thre_int = 1;
376
        uart->regs.lsr |= UART_LSR_TXBUFE;
377 1143 sfurman
      }
378 806 markom
    } else {
379 1367 nogj
      uart->regs.lsr |= UART_LSR_TXSERE;
380 806 markom
    }
381 1367 nogj
  } else if (uart->char_clks <= uart->istat.txser_clks++) {
382
    send_char(uart, (uart->regs.lcr & UART_LCR_WLEN8) + 5); /* We've sent all bits */
383 806 markom
  } else {
384
    /* We are still sending char here*/
385
 
386
    /* Check if we set the break bit */
387 1367 nogj
    if (uart->regs.lcr & UART_LCR_SBC) {
388
      if (!uart->vapi.break_sent) {
389 806 markom
#if 0
390
        /* Send broken frame */
391 1367 nogj
        int nbits_sent = ((uart->regs.lcr & UART_LCR_WLEN8) + 5) * (uart->istat.txser_clks - 1) / uart->char_clks;
392 806 markom
        send_char(i, nbits_sent);
393
#endif
394
        /* Send one break signal */
395 1367 nogj
        vapi_send (uart->vapi_id, UART_LCR_SBC << 8);
396
        uart->vapi.break_sent = 1;
397 806 markom
      }
398
      /* mark as character was sent */
399 1367 nogj
      uart->istat.txser_full = 0;
400
      uart->istat.txser_clks = 0;
401 806 markom
    } else
402 1367 nogj
      uart->vapi.break_sent = 0;
403 1143 sfurman
 
404 806 markom
  }
405 1143 sfurman
 
406 806 markom
  /***************** Receive *****************/
407
 
408
  /* Is there a break? */
409 1367 nogj
  if (uart->vapi.cur_break) {
410
    uart->vapi.cur_break_cnt++;
411
    if (uart->vapi.cur_break_cnt > UART_BREAK_COUNT * uart->vapi.char_clks) {
412
      if (!uart->istat.break_set) {
413 806 markom
        unsigned lsr;
414 1367 nogj
        uart->istat.break_set = 1;
415 806 markom
        lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY;
416 1367 nogj
        PRINTF ("[%x]\n", uart->regs.lsr);
417
        uart->istat.rxser_full = 0;
418
        uart->istat.rxser_clks = 0;
419
        uart_add_char (uart, lsr << 8);
420 806 markom
      } else
421 1367 nogj
        uart->vapi.cur_break_cnt = 0;
422 806 markom
    }
423 1367 nogj
    if (uart->istat.rxser_full) {
424
      uart->istat.rxser_full = 0;
425
      uart->istat.rxser_clks = 0;
426 806 markom
    }
427
  } else {
428 1367 nogj
    if (uart->istat.rxser_full) {
429
      if (uart->char_clks <= uart->istat.rxser_clks++) {
430 806 markom
        /* Set unused character bits to zero and allow lsr register in fifo */
431 1367 nogj
        uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
432 1392 nogj
        TRACE("\tReceiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
433 1367 nogj
              uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
434
        PRINTF ("%c", (char)uart->iregs.rxser);
435
        uart->istat.rxser_full = 0;
436
        uart->istat.rxser_clks = 0;
437
        uart_add_char (uart, uart->iregs.rxser);
438 806 markom
      }
439
    }
440
  }
441
 
442
  /* Check if there is something waiting, and put it into rxser */
443 1367 nogj
  if (uart->regs.mcr & UART_MCR_LOOP) {
444
    uart->iregs.rxser = uart->iregs.loopback;
445
    uart->istat.rxser_full = 1;
446 806 markom
  } else {
447 1367 nogj
    if (!uart->vapi_id) {
448
      if(uart->istat.rxser_full == 0) {
449
        if (uart->slowdown)
450
          uart->slowdown--;
451 1073 rprescott
        else {
452
          char buffer[1];
453 1367 nogj
          retval = channel_read(uart->channel, buffer, 1);
454 1073 rprescott
          if(retval < 0)
455 1367 nogj
                  perror(uart->channel_str);
456 1073 rprescott
          else if(retval > 0) {
457 1367 nogj
            uart->iregs.rxser = (unsigned char)buffer[0];
458
            uart->istat.rxser_full = 1;
459 1073 rprescott
          } else
460 1367 nogj
            uart->slowdown = UART_FGETC_SLOWDOWN;
461 1073 rprescott
        }
462 806 markom
      }
463
    } else { /* VAPI */
464
      int received = 0;
465
      /* do not handle commands while receiving */
466 1367 nogj
      if (uart->istat.rxser_full) return;
467 806 markom
      while (!received) {
468 1367 nogj
        if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
469
          unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
470 1392 nogj
          TRACE("\tHandling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
471 1367 nogj
                uart->vapi_buf_tail_ptr);
472
          uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
473 806 markom
          switch (data >> 24) {
474
            case 0x00:
475 1367 nogj
              uart->vapi.lcr = (data >> 8) & 0xff;
476 806 markom
              /* Put data into rx fifo */
477 1367 nogj
              uart->iregs.rxser = data & 0xff;
478
              uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
479
              if ((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
480
               || uart->vapi.char_clks != uart->char_clks
481
               || uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
482 1392 nogj
                WARN("WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
483 1367 nogj
                      uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
484 806 markom
                /* Set error bits */
485 1367 nogj
                uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
486
                if (uart->regs.lcr & UART_LCR_PARITY) uart->iregs.rxser |= UART_LSR_PARITY << 8;
487 806 markom
              }
488 1367 nogj
              uart->istat.rxser_full = 1;
489 806 markom
              received = 1;
490
              break;
491
            case 0x01:
492 1367 nogj
              uart->vapi.dll = (data >> 0) & 0xff;
493
              uart->vapi.dlh = (data >> 8) & 0xff;
494 806 markom
              break;
495
            case 0x02:
496 1367 nogj
              uart->vapi.lcr = (data >> 8) & 0xff;
497 806 markom
              break;
498
            case 0x03:
499 1367 nogj
              uart->vapi.skew = (signed short)(data & 0xffff);
500 806 markom
              break;
501
            case 0x04:
502 1367 nogj
              uart->vapi.next_break_cnt = data & 0xffff;
503
              uart->vapi.next_break = (data >> 16) & 1;
504 806 markom
              break;
505
            default:
506 1392 nogj
              WARN ("WARNING: Invalid vapi command %02lx\n", data >> 24);
507 806 markom
              break;
508
          }
509
        } else break;
510
      }
511
    }
512
  }
513
 
514
  /***************** Loopback *****************/
515 1367 nogj
  if (uart->regs.mcr & UART_MCR_LOOP) {
516 1392 nogj
    TRACE("uart_clock: Loopback\n");
517 1367 nogj
    if ((uart->regs.mcr & UART_MCR_AUX2) !=
518
        ((uart->regs.msr & UART_MSR_DCD) >> 4))
519
      uart->regs.msr |= UART_MSR_DDCD;
520
    if ((uart->regs.mcr & UART_MCR_AUX1) <
521
        ((uart->regs.msr & UART_MSR_RI) >> 4))
522
      uart->regs.msr |= UART_MSR_TERI;
523
    if ((uart->regs.mcr & UART_MCR_RTS) !=
524
        ((uart->regs.msr & UART_MSR_CTS) >> 3))
525
      uart->regs.msr |= UART_MSR_DCTS;
526
    if ((uart->regs.mcr & UART_MCR_DTR) !=
527
        ((uart->regs.msr & UART_MSR_DSR) >> 5))
528
      uart->regs.msr |= UART_MSR_DDSR;
529
    uart->regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
530 806 markom
              | UART_MSR_DSR | UART_MSR_CTS);
531 1367 nogj
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_AUX2) << 4);
532
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_AUX1) << 4);
533
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_RTS) << 3);
534
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_DTR) << 5);
535 806 markom
  }
536
 
537 1367 nogj
  if (uart->regs.lsr & UART_LSR_RDRDY)
538
    uart->istat.timeout_count++;
539 806 markom
 
540
  /* Update LSR error bits from the ones from rx FIFO */
541 1367 nogj
  if (uart->istat.rxbuf_full) {
542
    uart->regs.lsr |= uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
543 806 markom
    /* we must delete the lsr status, so that we can clear it from lsr */
544 1367 nogj
    uart->regs.rxbuf[uart->istat.rxbuf_tail] &= 0xff;
545 806 markom
  }
546
 
547
  /* Interrupt detection in proper priority order. */
548 1367 nogj
  uart->regs.iir = UART_IIR_NO_INT;
549
  if (uart->regs.ier & UART_IER_RLSI &&                    /* Receiver LS */
550
      uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
551 806 markom
        | UART_LSR_FRAME | UART_LSR_BREAK)) {
552 1367 nogj
    uart->regs.iir = UART_IIR_RLSI;
553
  } else if ((uart->regs.ier & UART_IER_RDI)               /* RD available */
554
      && (uart->istat.rxbuf_full >= UART_FIFO_TRIGGER(uart->regs.fcr >> 6))
555
      && (uart->regs.lsr & UART_LSR_RDRDY)) {
556
    uart->regs.iir = UART_IIR_RDI;
557
  } else if ((uart->regs.ier & UART_IER_RDI)               /* timeout */
558
      && (uart->istat.timeout_count >= UART_CHAR_TIMEOUT * uart->char_clks)
559
      && (uart->istat.rxbuf_head != uart->istat.rxbuf_tail)) {
560
    uart->regs.iir = UART_IIR_CTI;
561
  } else if (uart->regs.ier & UART_IER_THRI &&             /* Transm. empty */
562
      uart->istat.thre_int == 1) {
563
    uart->regs.iir = UART_IIR_THRI;
564
  } else if (uart->regs.ier & UART_IER_MSI &&              /* Modem status */
565
      uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
566 806 markom
        | UART_MSR_TERI | UART_MSR_DDCD)) {
567 1367 nogj
    uart->regs.iir = UART_IIR_MSI;
568 806 markom
  }
569 1367 nogj
  if (!(uart->regs.iir & UART_IIR_NO_INT)) {
570 1392 nogj
    TRACE("\tuart->regs.iir = %i\t", uart->regs.iir);
571 1367 nogj
    report_interrupt(uart->irq);
572 806 markom
  }
573
}
574
 
575 341 markom
/* Reset.  It initializes all registers of all UART devices to zero values,
576 31 lampret
   (re)opens all RX/TX file streams and places devices in memory address
577 341 markom
   space.  */
578 1367 nogj
void uart_reset(void *dat)
579 31 lampret
{
580 1367 nogj
  struct dev_16450 *uart = dat;
581 261 markom
 
582 1394 nogj
  if(uart->vapi_id) {
583
    vapi_install_handler(uart->vapi_id, uart_vapi_read, dat);
584
  } else if (uart->channel_str && uart->channel_str[0]) { /* Try to create stream. */
585 1367 nogj
    if(uart->channel)
586
      channel_close(uart->channel);
587 341 markom
    else
588 1367 nogj
      uart->channel = channel_init(uart->channel_str);
589
    if(channel_open(uart->channel) < 0) {
590 1392 nogj
      WARN ("WARNING: UART has problems with channel \"%s\".\n", uart->channel_str);
591 1367 nogj
    } else if (config.sim.verbose)
592
      PRINTF("UART at 0x%"PRIxADDR" uses ", uart->baseaddr);
593
  } else {
594 1392 nogj
    WARN ("WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n", uart->baseaddr);
595 1367 nogj
  }
596 344 markom
 
597 1367 nogj
  if (uart->uart16550)
598
    uart->fifo_len = 16;
599
  else
600
    uart->fifo_len = 1;
601 1145 sfurman
 
602 1367 nogj
  uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
603
  uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
604
 
605
  uart->istat.txser_full = uart->istat.rxser_full = 0;
606
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
607 1145 sfurman
 
608 1367 nogj
  uart->istat.txser_clks = uart->istat.rxser_clks = 0;
609 492 markom
 
610 1367 nogj
  uart->istat.thre_int = 0;
611
  uart->istat.break_set = 0;
612
  uart->istat.timeout_count = 0;
613
 
614
  // For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
615
  uart->istat.thre_int = (uart->fifo_len == 16);
616
 
617
  uart->char_clks = 0;
618
  uart->slowdown = UART_FGETC_SLOWDOWN;
619
 
620
  uart->iregs.txser = 0;
621
  uart->iregs.rxser = 0;
622
  uart->iregs.loopback = 0;
623
 
624
  memset(uart->regs.txbuf, 0, sizeof(uart->regs.txbuf));
625
  memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
626
 
627
  uart->regs.dll = 0;
628
  uart->regs.dlh = 0;
629
  uart->regs.ier = 0;
630
  uart->regs.iir = 0;
631
  uart->regs.fcr = 0;
632
  uart->regs.lcr = UART_LCR_RESET;
633
  uart->regs.mcr = 0;
634
  uart->regs.lsr = 0;
635
  uart->regs.msr = 0;
636
  uart->regs.scr = 0;
637
 
638
  uart->vapi.cur_break = uart->vapi.cur_break_cnt = uart->vapi.next_break = 0;
639
  uart->vapi.next_break_cnt = -1;
640
  uart->vapi.break_sent = 0;
641
  uart->vapi.skew = 0;
642
  uart->vapi.lcr = 0;
643
  uart->vapi.dll = 0;
644
  uart->vapi.char_clks = 0;
645
 
646
  uart->vapi_buf_head_ptr = 0;
647
  uart->vapi_buf_tail_ptr = 0;
648
  memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
649
 
650 1390 nogj
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
651 31 lampret
}
652 261 markom
 
653 31 lampret
/* Print register values on stdout. */
654 1367 nogj
void uart_status(void *dat)
655 31 lampret
{
656 1367 nogj
  struct dev_16450 *uart = dat;
657
  int i;
658 355 markom
 
659 1367 nogj
  PRINTF("\nUART visible registers at 0x%"PRIxADDR":\n", uart->baseaddr);
660
  PRINTF("RXBUF: ");
661
  for (i = uart->istat.rxbuf_head; i != uart->istat.rxbuf_tail; i = (i + 1) % uart->fifo_len)
662
    PRINTF (" %.2x", uart->regs.rxbuf[i]);
663
  PRINTF("TXBUF: ");
664
  for (i = uart->istat.txbuf_head; i != uart->istat.txbuf_tail; i = (i + 1) % uart->fifo_len)
665
    PRINTF (" %.2x", uart->regs.txbuf[i]);
666
  PRINTF("\n");
667
  PRINTF("DLL  : %.2x  DLH  : %.2x\n", uart->regs.dll, uart->regs.dlh);
668
  PRINTF("IER  : %.2x  IIR  : %.2x\n", uart->regs.ier, uart->regs.iir);
669
  PRINTF("LCR  : %.2x  MCR  : %.2x\n", uart->regs.lcr, uart->regs.mcr);
670
  PRINTF("LSR  : %.2x  MSR  : %.2x\n", uart->regs.lsr, uart->regs.msr);
671
  PRINTF("SCR  : %.2x\n", uart->regs.scr);
672 31 lampret
 
673 1367 nogj
  PRINTF("\nInternal registers (sim debug):\n");
674
  PRINTF("RXSER: %.2lx  TXSER: %.2lx\n", uart->iregs.rxser, uart->iregs.txser);
675 31 lampret
 
676 1367 nogj
  PRINTF("\nInternal status (sim debug):\n");
677
  PRINTF("char_clks: %ld\n", uart->char_clks);
678
  PRINTF("rxser_clks: %ld  txser_clks: %ld\n", uart->istat.rxser_clks,
679
         uart->istat.txser_clks);
680
  PRINTF("rxser: %d  txser: %d\n", uart->istat.rxser_full, uart->istat.txser_full);
681
  PRINTF("rxbuf_full: %d  txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
682
  PRINTF("Using IRQ%i\n", uart->irq);
683
  if (uart->vapi_id)
684
    PRINTF ("Connected to vapi ID=%lx\n\n", uart->vapi_id);
685
  /* TODO: replace by a channel_status
686
  else
687
    PRINTF("RX fs: %p  TX fs: %p\n\n", uart->rxfs, uart->txfs);
688
  */
689 31 lampret
}
690 1358 nogj
 
691
/*---------------------------------------------------[ UART configuration ]---*/
692
void uart_baseaddr(union param_val val, void *dat)
693
{
694 1367 nogj
  struct dev_16450 *uart = dat;
695
  uart->baseaddr = val.addr_val;
696 1358 nogj
}
697
 
698
void uart_jitter(union param_val val, void *dat)
699
{
700 1367 nogj
  struct dev_16450 *uart = dat;
701
  uart->jitter = val.int_val;
702 1358 nogj
}
703
 
704
void uart_irq(union param_val val, void *dat)
705
{
706 1367 nogj
  struct dev_16450 *uart = dat;
707
  uart->irq = val.int_val;
708 1358 nogj
}
709
 
710
void uart_16550(union param_val val, void *dat)
711
{
712 1367 nogj
  struct dev_16450 *uart = dat;
713
  uart->uart16550 = val.int_val;
714 1358 nogj
}
715
 
716
void uart_channel(union param_val val, void *dat)
717
{
718 1367 nogj
  struct dev_16450 *uart = dat;
719
  if(!(uart->channel_str = strdup(val.str_val))) {
720
    fprintf(stderr, "Peripheral 16450: Run out of memory\n");
721
    exit(-1);
722
  }
723 1358 nogj
}
724
 
725
void uart_newway(union param_val val, void *dat)
726
{
727
  CONFIG_ERROR(" txfile and rxfile and now obsolete.\n\tUse 'channel = \"file:rxfile,txfile\"' instead.");
728
  exit(1);
729
}
730
 
731
void uart_vapi_id(union param_val val, void *dat)
732
{
733 1367 nogj
  struct dev_16450 *uart = dat;
734
  uart->vapi_id = val.int_val;
735 1358 nogj
}
736
 
737 1367 nogj
void *uart_sec_start(void)
738
{
739
  struct dev_16450 *new = malloc(sizeof(struct dev_16450));
740
 
741
  if(!new) {
742
    fprintf(stderr, "Peripheral 16450: Run out of memory\n");
743
    exit(-1);
744
  }
745
 
746
  new->channel_str = NULL;
747
  new->channel = NULL;
748
  new->vapi_id = 0;
749
 
750
  return new;
751
}
752
 
753
void uart_sec_end(void *dat)
754
{
755
  struct dev_16450 *uart = dat;
756
 
757
  register_memoryarea(uart->baseaddr, UART_ADDR_SPACE, 1, 0, uart_read_byte,
758
                      uart_write_byte, dat);
759
  reg_sim_reset(uart_reset, dat);
760
  reg_sim_stat(uart_status, dat);
761
}
762
 
763 1358 nogj
void reg_uart_sec(void)
764
{
765 1367 nogj
  struct config_section *sec = reg_config_sec("uart", uart_sec_start,
766
                                              uart_sec_end);
767 1358 nogj
 
768
  reg_config_param(sec, "baseaddr", paramt_addr, uart_baseaddr);
769
  reg_config_param(sec, "irq", paramt_int, uart_irq);
770
  reg_config_param(sec, "16550", paramt_int, uart_16550);
771
  reg_config_param(sec, "jitter", paramt_int, uart_jitter);
772
  reg_config_param(sec, "channel", paramt_str, uart_channel);
773
  reg_config_param(sec, "txfile", paramt_str, uart_newway);
774
  reg_config_param(sec, "rxfile", paramt_str, uart_newway);
775
  reg_config_param(sec, "vapi_id", paramt_int, uart_vapi_id);
776
}

powered by: WebSVN 2.1.0

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