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 1501

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

powered by: WebSVN 2.1.0

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