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 1502

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

powered by: WebSVN 2.1.0

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