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

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc2/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 1500

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

powered by: WebSVN 2.1.0

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