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

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc3/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 1518

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

powered by: WebSVN 2.1.0

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