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

Subversion Repositories or1k

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

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
  char buffer[1];
535
  int retval;
536
 
537
  /* Check if there is something waiting, and put it into rxser */
538
  retval = channel_read(uart->channel, buffer, 1);
539
  if(retval > 0) {
540
    uart->iregs.rxser = (unsigned char)buffer[0];
541
    uart->istat.receiveing = 1;
542
    SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
543
    return;
544
  }
545
 
546
  if(!retval) {
547
    SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
548
    return;
549
  }
550
 
551
  if(retval < 0)
552
    perror(uart->channel_str);
553
}
554
 
555
static void uart_sched_recv_check(struct dev_16450 *uart)
556
{
557
  if(!uart->vapi_id)
558
    SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
559
}
560
 
561 1505 nogj
/*----------------------------------------------------[ UART I/O handling ]---*/
562 31 lampret
/* Set a specific UART register with value. */
563 1486 nogj
void uart_write_byte(oraddr_t addr, uint8_t value, void *dat)
564 31 lampret
{
565 1367 nogj
  struct dev_16450 *uart = dat;
566 355 markom
 
567 1367 nogj
  if (uart->regs.lcr & UART_LCR_DLAB) {
568 1486 nogj
    switch (addr) {
569 355 markom
      case UART_DLL:
570 1367 nogj
        uart->regs.dll = value;
571
        uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
572 1392 nogj
        TRACE("\tSetting char_clks to %li (%02x, %02x, %02x)\n", uart->char_clks,
573
              uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
574 355 markom
        return;
575
      case UART_DLH:
576 1505 nogj
        TRACE("Setting dlh with %"PRIx8"\n", value);
577 1367 nogj
        uart->regs.dlh = value;
578 355 markom
        return;
579
    }
580
  }
581
 
582 1486 nogj
  switch (addr) {
583 355 markom
    case UART_TXBUF:
584 1505 nogj
      TRACE("Adding %"PRIx8" to TX FIFO\n", value);
585 1499 nogj
      uart->regs.lsr &= ~UART_LSR_TXBUFE;
586 1367 nogj
      if (uart->istat.txbuf_full < uart->fifo_len) {
587
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
588
        uart->istat.txbuf_head = (uart->istat.txbuf_head + 1) % uart->fifo_len;
589 1499 nogj
        if(!uart->istat.txbuf_full++ && (uart->regs.lsr & UART_LSR_TXSERE))
590
          SCHED_ADD(uart_tx_send, uart, 0);
591 355 markom
      } else
592 1367 nogj
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
593 341 markom
 
594 1502 nogj
      uart_clear_int(uart, UART_IIR_THRI);
595 355 markom
      break;
596 409 markom
    case UART_FCR:
597 1505 nogj
      TRACE("Setting FCR reg with %"PRIx8"\n", value);
598 1367 nogj
      uart->regs.fcr = value & UART_VALID_FCR;
599
      if ((uart->fifo_len == 1 && (value & UART_FCR_FIE))
600
       || (uart->fifo_len != 1 && !(value & UART_FCR_FIE)))
601 409 markom
        value |= UART_FCR_RRXFI | UART_FCR_RTXFI;
602 1367 nogj
      uart->fifo_len = (value & UART_FCR_FIE) ? 16 : 1;
603 409 markom
      if (value & UART_FCR_RTXFI) {
604 1367 nogj
        uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
605
        uart->istat.txbuf_full = 0;
606
        uart->regs.lsr |= UART_LSR_TXBUFE;
607 1145 sfurman
 
608 1502 nogj
        /* For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
609
         */
610
        if(uart->fifo_len == 16)
611
          SCHED_ADD(uart_int_thri, uart, 0);
612 1499 nogj
 
613
        SCHED_FIND_REMOVE(uart_tx_send, uart);
614 409 markom
      }
615
      if (value & UART_FCR_RRXFI) {
616 1367 nogj
        uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
617
        uart->istat.rxbuf_full = 0;
618
        uart->regs.lsr &= ~UART_LSR_RDRDY;
619 1502 nogj
        uart_clear_int(uart, UART_IIR_RDI);
620
        uart_clear_int(uart, UART_IIR_CTI);
621 409 markom
      }
622
      break;
623 355 markom
    case UART_IER:
624 1367 nogj
      uart->regs.ier = value & UART_VALID_IER;
625 1505 nogj
      TRACE("Enabling 0x%02x interrupts with 0x%x interrupts pending\n",
626
            value, uart->istat.ints);
627 1502 nogj
      SCHED_ADD(uart_next_int, uart, 0);
628 355 markom
      break;
629
    case UART_LCR:
630 1505 nogj
      TRACE("Setting LCR reg with %"PRIx8"\n", value);
631 1499 nogj
      if((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) {
632
        if((value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
633
          /* Schedule a job to send the break char */
634
          SCHED_FIND_REMOVE(uart_char_clock, uart);
635
          SCHED_ADD(uart_send_break, uart, 0);
636
        }
637
        if(!(value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
638
          /* Schedule a job to start sending characters */
639
          SCHED_ADD(uart_tx_send, uart, 0);
640
          /* Remove the uart_send_break job just in case it has not run yet */
641
          SCHED_FIND_REMOVE(uart_char_clock, uart);
642
        }
643
      }
644 1367 nogj
      uart->regs.lcr = value & UART_VALID_LCR;
645
      uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
646 355 markom
      break;
647
    case UART_MCR:
648 1505 nogj
      TRACE("Setting MCR reg with %"PRIx8"\n", value);
649 1367 nogj
      uart->regs.mcr = value & UART_VALID_MCR;
650 1503 nogj
      uart_loopback(uart);
651 355 markom
      break;
652
    case UART_SCR:
653 1505 nogj
      TRACE("Setting SCR reg with %"PRIx8"\n", value);
654 1367 nogj
      uart->regs.scr = value;
655 355 markom
      break;
656
    default:
657 1505 nogj
      TRACE("write out of range (addr %"PRIxADDR")\n", addr);
658 355 markom
  }
659 31 lampret
}
660
 
661
/* Read a specific UART register. */
662 1486 nogj
uint8_t uart_read_byte(oraddr_t addr, void *dat)
663 31 lampret
{
664 1367 nogj
  struct dev_16450 *uart = dat;
665 1350 nogj
  uint8_t value = 0;
666 355 markom
 
667 1367 nogj
  if (uart->regs.lcr & UART_LCR_DLAB) {
668 1486 nogj
    switch (addr) {
669 355 markom
      case UART_DLL:
670 1367 nogj
        value = uart->regs.dll;
671 1505 nogj
        TRACE("reading DLL = %"PRIx8"\n", value);
672 355 markom
        return value;
673
      case UART_DLH:
674 1367 nogj
        value = uart->regs.dlh;
675 1505 nogj
        TRACE("reading DLH = %"PRIx8"\n", value);
676 355 markom
        return value;
677
    }
678
  }
679
 
680 1486 nogj
  switch (addr) {
681 355 markom
    case UART_RXBUF:
682 409 markom
      { /* Print out FIFO for debugging */
683
        int i;
684 1392 nogj
        TRACE("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len,
685
              uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
686 1367 nogj
        for (i = 0; i < uart->istat.rxbuf_full; i++)
687 1505 nogj
          TRACE("%02x ",
688
                uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
689 1392 nogj
        TRACE(")");
690 409 markom
      }
691 1367 nogj
      if (uart->istat.rxbuf_full) {
692
        value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
693
        uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
694
        uart->istat.rxbuf_full--;
695 1501 nogj
        TRACE("Reading %"PRIx8" out of RX FIFO\n", value);
696
      } else
697
        TRACE("Trying to read out of RX FIFO but it's empty!\n");
698 1502 nogj
 
699
      uart_clear_int(uart, UART_IIR_RDI);
700
      uart_clear_int(uart, UART_IIR_CTI);
701
      SCHED_FIND_REMOVE(uart_int_cti, uart);
702
 
703
      if(uart->istat.rxbuf_full) {
704 1501 nogj
        uart->regs.lsr |= UART_LSR_RDRDY | uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
705 1502 nogj
        SCHED_ADD(uart_int_cti, uart,
706
                  uart->char_clks * UART_CHAR_TIMEOUT * UART_CLOCK_DIVIDER);
707
        /* Since we're not allowed to raise interrupts from read/write functions
708
         * schedule them to run just after we have executed this read
709
         * instruction. */
710
        SCHED_ADD(uart_check_rlsi, uart, 0);
711
        SCHED_ADD(uart_check_rdi, uart, 0);
712
      } else {
713 1367 nogj
        uart->regs.lsr &= ~UART_LSR_RDRDY;
714 1502 nogj
      }
715 355 markom
      break;
716
    case UART_IER:
717 1367 nogj
      value = uart->regs.ier & UART_VALID_IER;
718 1505 nogj
      TRACE("reading IER = %"PRIx8"\n", value);
719 355 markom
      break;
720
    case UART_IIR:
721 1367 nogj
      value = (uart->regs.iir & UART_VALID_IIR) | 0xc0;
722 1502 nogj
      /* Only clear the thri interrupt if it is the one we are repporting */
723
      if(uart->regs.iir == UART_IIR_THRI)
724
        uart_clear_int(uart, UART_IIR_THRI);
725 1505 nogj
      TRACE("reading IIR = %"PRIx8"\n", value);
726 355 markom
      break;
727
    case UART_LCR:
728 1367 nogj
      value = uart->regs.lcr & UART_VALID_LCR;
729 1505 nogj
      TRACE("reading LCR = %"PRIx8"\n", value);
730 355 markom
      break;
731
    case UART_MCR:
732
      value = 0;
733 1505 nogj
      TRACE("reading MCR = %"PRIx8"\n", value);
734 355 markom
      break;
735
    case UART_LSR:
736 1367 nogj
      value = uart->regs.lsr & UART_VALID_LSR;
737
      uart->regs.lsr &=
738 409 markom
        ~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
739
         | UART_LSR_FRAME | UART_LSR_RXERR);
740 1502 nogj
      /* Clear potentially pending RLSI interrupt */
741
      uart_clear_int(uart, UART_IIR_RLSI);
742 1505 nogj
      TRACE("reading LSR = %"PRIx8"\n", value);
743 355 markom
      break;
744
    case UART_MSR:
745 1367 nogj
      value = uart->regs.msr & UART_VALID_MSR;
746
      uart->regs.msr = 0;
747 1502 nogj
      uart_clear_int(uart, UART_IIR_MSI);
748 1503 nogj
      uart_loopback(uart);
749 1505 nogj
      TRACE("reading MSR = %"PRIx8"\n", value);
750 355 markom
      break;
751
    case UART_SCR:
752 1367 nogj
      value = uart->regs.scr;
753 1505 nogj
      TRACE("reading SCR = %"PRIx8"\n", value);
754 355 markom
      break;
755
    default:
756 1392 nogj
      TRACE("read out of range (addr %"PRIxADDR")\n", addr);
757 355 markom
  }
758
  return value;
759 31 lampret
}
760
 
761 1500 nogj
/*--------------------------------------------------------[ VAPI handling ]---*/
762
/* Decodes the read vapi command */
763 1501 nogj
static void uart_vapi_cmd(void *dat)
764 1500 nogj
{
765 1501 nogj
  struct dev_16450 *uart = dat;
766 1500 nogj
  int received = 0;
767
 
768
  while (!received) {
769
    if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
770
      unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
771
      TRACE("\tHandling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
772
            uart->vapi_buf_tail_ptr);
773
      uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
774
      switch (data >> 24) {
775
      case 0x00:
776
        uart->vapi.lcr = (data >> 8) & 0xff;
777
        /* Put data into rx fifo */
778
        uart->iregs.rxser = data & 0xff;
779
        uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
780
        if((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
781
            || uart->vapi.char_clks != uart->char_clks
782
            || uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
783
          if((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC))
784
            WARN("unmatched VAPI (%02"PRIx8") and uart (%02"PRIx8") modes.\n",
785
                 uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
786
          if(uart->vapi.char_clks != uart->char_clks) {
787
            WARN("unmatched VAPI (%li) and uart (%li) char clocks.\n",
788
                 uart->vapi.char_clks, uart->char_clks);
789
            WARN("VAPI: lcr: %02"PRIx8", dll: %02"PRIx8", dlh: %02"PRIx8"\n",
790
                 uart->vapi.lcr, uart->vapi.dll, uart->vapi.dlh);
791
            WARN("UART: lcr: %02"PRIx8", dll: %02"PRIx8", dlh: %02"PRIx8"\n",
792
                 uart->regs.lcr, uart->regs.dll, uart->vapi.dlh);
793
          }
794
          if(uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW)
795
            WARN("VAPI skew is beyond max: %i\n", uart->vapi.skew);
796
          /* Set error bits */
797
          uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
798
          if(uart->regs.lcr & UART_LCR_PARITY)
799
            uart->iregs.rxser |= UART_LSR_PARITY << 8;
800
        }
801 1501 nogj
        if(!uart->istat.recv_break) {
802
          uart->istat.receiveing = 1;
803
          SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
804
        }
805 1500 nogj
        received = 1;
806
        break;
807
      case 0x01:
808
        uart->vapi.dll = (data >> 0) & 0xff;
809
        uart->vapi.dlh = (data >> 8) & 0xff;
810
        break;
811
      case 0x02:
812
        uart->vapi.lcr = (data >> 8) & 0xff;
813
        break;
814
      case 0x03:
815
        uart->vapi.skew = (signed short)(data & 0xffff);
816
        break;
817
      case 0x04:
818 1501 nogj
        if((data >> 16) & 1) {
819
          /* If data & 0xffff is 0 then set the break imediatly and handle the
820
           * following commands as appropriate */
821
          if(!(data & 0xffff))
822
            uart_recv_break_start(uart);
823
          else
824
            /* Schedule a job to start sending breaks */
825
            SCHED_ADD(uart_recv_break_start, uart,
826
                      (data & 0xffff) * UART_CLOCK_DIVIDER);
827
        } else {
828
          /* If data & 0xffff is 0 then release the break imediatly and handle
829
           * the following commands as appropriate */
830
          if(!(data & 0xffff))
831
            uart_recv_break_stop(uart);
832
          else
833
            /* Schedule a job to stop sending breaks */
834
            SCHED_ADD(uart_recv_break_stop, uart,
835
                      (data & 0xffff) * UART_CLOCK_DIVIDER);
836
        }
837 1500 nogj
        break;
838
      default:
839
        WARN("WARNING: Invalid vapi command %02lx\n", data >> 24);
840
        break;
841
      }
842
    } else break;
843
  }
844
}
845
 
846 336 markom
/* Function that handles incoming VAPI data.  */
847 1366 nogj
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
848 336 markom
{
849 1367 nogj
  struct dev_16450 *uart = dat;
850 1392 nogj
  TRACE("UART: id %08lx, data %08lx\n", id, data);
851 1367 nogj
  uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
852
  uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
853
  if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
854 341 markom
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
855
    exit (1);
856
  }
857 1501 nogj
  if(!uart->istat.receiveing)
858
    uart_vapi_cmd(uart);
859 341 markom
}
860 336 markom
 
861 1505 nogj
/*--------------------------------------------------------[ Sim callbacks ]---*/
862 341 markom
/* Reset.  It initializes all registers of all UART devices to zero values,
863 1505 nogj
 * (re)opens all RX/TX file streams and places devices in memory address
864
 * space.  */
865 1367 nogj
void uart_reset(void *dat)
866 31 lampret
{
867 1367 nogj
  struct dev_16450 *uart = dat;
868 261 markom
 
869 1394 nogj
  if(uart->vapi_id) {
870
    vapi_install_handler(uart->vapi_id, uart_vapi_read, dat);
871
  } else if (uart->channel_str && uart->channel_str[0]) { /* Try to create stream. */
872 1367 nogj
    if(uart->channel)
873
      channel_close(uart->channel);
874 341 markom
    else
875 1367 nogj
      uart->channel = channel_init(uart->channel_str);
876
    if(channel_open(uart->channel) < 0) {
877 1476 nogj
      WARN ("WARNING: problem with channel \"%s\" detected.\n", uart->channel_str);
878 1367 nogj
    } else if (config.sim.verbose)
879 1486 nogj
      PRINTF("UART at 0x%"PRIxADDR"\n", uart->baseaddr);
880 1367 nogj
  } else {
881 1476 nogj
    WARN ("WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n",
882
          uart->baseaddr);
883 1367 nogj
  }
884 344 markom
 
885 1367 nogj
  if (uart->uart16550)
886
    uart->fifo_len = 16;
887
  else
888
    uart->fifo_len = 1;
889 1145 sfurman
 
890 1367 nogj
  uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
891
  uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
892
 
893
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
894 1145 sfurman
 
895 1367 nogj
  uart->char_clks = 0;
896
 
897
  uart->iregs.txser = 0;
898
  uart->iregs.rxser = 0;
899
  uart->iregs.loopback = 0;
900 1501 nogj
  uart->istat.receiveing = 0;
901
  uart->istat.recv_break = 0;
902 1502 nogj
  uart->istat.ints = 0;
903 1367 nogj
 
904
  memset(uart->regs.txbuf, 0, sizeof(uart->regs.txbuf));
905
  memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
906
 
907
  uart->regs.dll = 0;
908
  uart->regs.dlh = 0;
909
  uart->regs.ier = 0;
910 1502 nogj
  uart->regs.iir = UART_IIR_NO_INT;
911 1367 nogj
  uart->regs.fcr = 0;
912
  uart->regs.lcr = UART_LCR_RESET;
913
  uart->regs.mcr = 0;
914 1499 nogj
  uart->regs.lsr = UART_LSR_TXBUFE | UART_LSR_TXSERE;
915 1367 nogj
  uart->regs.msr = 0;
916
  uart->regs.scr = 0;
917
 
918
  uart->vapi.skew = 0;
919
  uart->vapi.lcr = 0;
920
  uart->vapi.dll = 0;
921
  uart->vapi.char_clks = 0;
922
 
923
  uart->vapi_buf_head_ptr = 0;
924
  uart->vapi_buf_tail_ptr = 0;
925
  memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
926
 
927 1501 nogj
  uart_sched_recv_check(uart);
928 31 lampret
}
929 261 markom
 
930 31 lampret
/* Print register values on stdout. */
931 1367 nogj
void uart_status(void *dat)
932 31 lampret
{
933 1367 nogj
  struct dev_16450 *uart = dat;
934
  int i;
935 355 markom
 
936 1367 nogj
  PRINTF("\nUART visible registers at 0x%"PRIxADDR":\n", uart->baseaddr);
937
  PRINTF("RXBUF: ");
938
  for (i = uart->istat.rxbuf_head; i != uart->istat.rxbuf_tail; i = (i + 1) % uart->fifo_len)
939
    PRINTF (" %.2x", uart->regs.rxbuf[i]);
940
  PRINTF("TXBUF: ");
941
  for (i = uart->istat.txbuf_head; i != uart->istat.txbuf_tail; i = (i + 1) % uart->fifo_len)
942
    PRINTF (" %.2x", uart->regs.txbuf[i]);
943
  PRINTF("\n");
944
  PRINTF("DLL  : %.2x  DLH  : %.2x\n", uart->regs.dll, uart->regs.dlh);
945
  PRINTF("IER  : %.2x  IIR  : %.2x\n", uart->regs.ier, uart->regs.iir);
946
  PRINTF("LCR  : %.2x  MCR  : %.2x\n", uart->regs.lcr, uart->regs.mcr);
947
  PRINTF("LSR  : %.2x  MSR  : %.2x\n", uart->regs.lsr, uart->regs.msr);
948
  PRINTF("SCR  : %.2x\n", uart->regs.scr);
949 31 lampret
 
950 1367 nogj
  PRINTF("\nInternal registers (sim debug):\n");
951 1504 nogj
  PRINTF("RXSER: %.2"PRIx16"  TXSER: %.2"PRIx8"\n", uart->iregs.rxser,
952
         uart->iregs.txser);
953 31 lampret
 
954 1367 nogj
  PRINTF("\nInternal status (sim debug):\n");
955
  PRINTF("char_clks: %ld\n", uart->char_clks);
956
  PRINTF("rxbuf_full: %d  txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
957
  PRINTF("Using IRQ%i\n", uart->irq);
958
  if (uart->vapi_id)
959
    PRINTF ("Connected to vapi ID=%lx\n\n", uart->vapi_id);
960
  /* TODO: replace by a channel_status
961
  else
962
    PRINTF("RX fs: %p  TX fs: %p\n\n", uart->rxfs, uart->txfs);
963
  */
964 31 lampret
}
965 1358 nogj
 
966
/*---------------------------------------------------[ UART configuration ]---*/
967
void uart_baseaddr(union param_val val, void *dat)
968
{
969 1367 nogj
  struct dev_16450 *uart = dat;
970
  uart->baseaddr = val.addr_val;
971 1358 nogj
}
972
 
973
void uart_jitter(union param_val val, void *dat)
974
{
975 1367 nogj
  struct dev_16450 *uart = dat;
976
  uart->jitter = val.int_val;
977 1358 nogj
}
978
 
979
void uart_irq(union param_val val, void *dat)
980
{
981 1367 nogj
  struct dev_16450 *uart = dat;
982
  uart->irq = val.int_val;
983 1358 nogj
}
984
 
985
void uart_16550(union param_val val, void *dat)
986
{
987 1367 nogj
  struct dev_16450 *uart = dat;
988
  uart->uart16550 = val.int_val;
989 1358 nogj
}
990
 
991
void uart_channel(union param_val val, void *dat)
992
{
993 1367 nogj
  struct dev_16450 *uart = dat;
994
  if(!(uart->channel_str = strdup(val.str_val))) {
995
    fprintf(stderr, "Peripheral 16450: Run out of memory\n");
996
    exit(-1);
997
  }
998 1358 nogj
}
999
 
1000
void uart_newway(union param_val val, void *dat)
1001
{
1002
  CONFIG_ERROR(" txfile and rxfile and now obsolete.\n\tUse 'channel = \"file:rxfile,txfile\"' instead.");
1003
  exit(1);
1004
}
1005
 
1006
void uart_vapi_id(union param_val val, void *dat)
1007
{
1008 1367 nogj
  struct dev_16450 *uart = dat;
1009
  uart->vapi_id = val.int_val;
1010 1358 nogj
}
1011
 
1012 1461 nogj
void uart_enabled(union param_val val, void *dat)
1013
{
1014
  struct dev_16450 *uart = dat;
1015
  uart->enabled = val.int_val;
1016
}
1017
 
1018 1367 nogj
void *uart_sec_start(void)
1019
{
1020
  struct dev_16450 *new = malloc(sizeof(struct dev_16450));
1021
 
1022
  if(!new) {
1023
    fprintf(stderr, "Peripheral 16450: Run out of memory\n");
1024
    exit(-1);
1025
  }
1026
 
1027 1461 nogj
  new->enabled = 1;
1028 1367 nogj
  new->channel_str = NULL;
1029
  new->channel = NULL;
1030
  new->vapi_id = 0;
1031
 
1032
  return new;
1033
}
1034
 
1035
void uart_sec_end(void *dat)
1036
{
1037
  struct dev_16450 *uart = dat;
1038 1486 nogj
  struct mem_ops ops;
1039 1367 nogj
 
1040 1461 nogj
  if(!uart->enabled) {
1041
    free(dat);
1042
    return;
1043
  }
1044 1486 nogj
 
1045
  memset(&ops, 0, sizeof(struct mem_ops));
1046
 
1047
  ops.readfunc8 = uart_read_byte;
1048
  ops.writefunc8 = uart_write_byte;
1049
  ops.read_dat8 = dat;
1050
  ops.write_dat8 = dat;
1051
 
1052
  /* FIXME: What should these be? */
1053
  ops.delayr = 2;
1054
  ops.delayw = 2;
1055
 
1056
  reg_mem_area(uart->baseaddr, UART_ADDR_SPACE, 0, &ops);
1057
 
1058 1367 nogj
  reg_sim_reset(uart_reset, dat);
1059
  reg_sim_stat(uart_status, dat);
1060
}
1061
 
1062 1358 nogj
void reg_uart_sec(void)
1063
{
1064 1367 nogj
  struct config_section *sec = reg_config_sec("uart", uart_sec_start,
1065
                                              uart_sec_end);
1066 1358 nogj
 
1067
  reg_config_param(sec, "baseaddr", paramt_addr, uart_baseaddr);
1068 1461 nogj
  reg_config_param(sec, "enabled", paramt_int, uart_enabled);
1069 1358 nogj
  reg_config_param(sec, "irq", paramt_int, uart_irq);
1070
  reg_config_param(sec, "16550", paramt_int, uart_16550);
1071
  reg_config_param(sec, "jitter", paramt_int, uart_jitter);
1072
  reg_config_param(sec, "channel", paramt_str, uart_channel);
1073
  reg_config_param(sec, "txfile", paramt_str, uart_newway);
1074
  reg_config_param(sec, "rxfile", paramt_str, uart_newway);
1075
  reg_config_param(sec, "vapi_id", paramt_int, uart_vapi_id);
1076
}

powered by: WebSVN 2.1.0

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