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 1504

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

powered by: WebSVN 2.1.0

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