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 1563

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

powered by: WebSVN 2.1.0

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