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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_67/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 341

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 235 erez
#include "abstract.h"
35 31 lampret
#include "16450.h"
36
#include "sim-config.h"
37 102 lampret
#include "pic.h"
38 336 markom
#include "vapi.h"
39 31 lampret
 
40
static struct dev_16450 uarts[NR_UARTS];
41 221 markom
static int thre_int;
42 31 lampret
 
43
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
44
   before a single character is transmitted or received. */
45
static void set_char_clks(int uartchip)
46
{
47
        int bauds_per_char = 0;
48
 
49
        uarts[uartchip].char_clks = (uarts[uartchip].regs.dlh << 8)
50
                                        + uarts[uartchip].regs.dll;
51
 
52
        if (uarts[uartchip].regs.lcr & UART_LCR_PARITY)
53
                bauds_per_char++;
54
 
55
        if (uarts[uartchip].regs.lcr & UART_LCR_STOP)
56
                bauds_per_char += 2;
57
        else
58
                bauds_per_char++;
59
 
60
        bauds_per_char += (5 + (uarts[uartchip].regs.lcr & 0x2));
61
 
62
        uarts[uartchip].char_clks *= bauds_per_char;
63
}
64
 
65
/* Set a specific UART register with value. */
66 238 erez
void uart_write_byte(unsigned long addr, unsigned long value)
67 31 lampret
{
68
        int chipsel;
69
 
70 238 erez
        debug("uart_write_byte(%x,%02x)\n", addr, (unsigned)value);
71 341 markom
 
72 31 lampret
        for(chipsel = 0; chipsel < NR_UARTS; chipsel++)
73 341 markom
                if ((addr & ~(UART_ADDR_SPACE-1)) == config.uarts[chipsel].baseaddr)
74 31 lampret
                        break;
75
                else if (chipsel == NR_UARTS)
76
                        return;
77
 
78 221 markom
        if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) {
79
                switch (addr % UART_ADDR_SPACE) {
80
                        case UART_DLL:
81 235 erez
                                uarts[chipsel].regs.dll = value;
82 221 markom
                                break;
83
                        case UART_DLH:
84 235 erez
                                uarts[chipsel].regs.dlh = value;
85 221 markom
                                break;
86
                        case UART_LCR:
87 235 erez
                                uarts[chipsel].regs.lcr = value & UART_VALID_LCR;
88 221 markom
                                break;
89
                        default:
90
                                debug("write out of range (addr %x, DLAB=1)\n", addr);
91
                }
92 31 lampret
                set_char_clks(chipsel);
93
                return;
94 221 markom
        }
95 31 lampret
 
96
        switch (addr % UART_ADDR_SPACE) {
97
                case UART_TXBUF:
98 341 markom
                  if (uarts[chipsel].istat.txbuf_full < uarts[chipsel].fifo_len) {
99
                    uarts[chipsel].istat.txbuf_full++;
100
                          uarts[chipsel].regs.txbuf[uarts[chipsel].istat.txbuf_head] = value;
101
                          uarts[chipsel].istat.txbuf_head = (uarts[chipsel].istat.txbuf_head + 1) % uarts[chipsel].fifo_len;
102
                        } else
103
                          uarts[chipsel].regs.txbuf[uarts[chipsel].istat.txbuf_head] = value;
104
 
105
                        if (uarts[chipsel].istat.txbuf_full < uarts[chipsel].fifo_len)
106
                          uarts[chipsel].regs.lsr &= ~UART_LSR_TXBUFE;
107
                        else
108
                          uarts[chipsel].regs.lsr |= UART_LSR_TXBUFE;
109 31 lampret
                        uarts[chipsel].regs.lsr &= ~UART_LSR_TXSERE;
110 341 markom
 
111 221 markom
                        uarts[chipsel].istat.thre_int = 0;
112 31 lampret
                        break;
113
                case UART_IER:
114 235 erez
                        uarts[chipsel].regs.ier = value & UART_VALID_IER;
115 31 lampret
                        break;
116
                case UART_LCR:
117 235 erez
                        uarts[chipsel].regs.lcr = value & UART_VALID_LCR;
118 31 lampret
                        break;
119
                case UART_MCR:
120 235 erez
                        uarts[chipsel].regs.mcr = value & UART_VALID_MCR;
121 31 lampret
                        break;
122
                case UART_SCR:
123 235 erez
                        uarts[chipsel].regs.scr = value;
124 31 lampret
                        break;
125
                default:
126
                        debug("write out of range (addr %x)\n", addr);
127
        }
128
        set_char_clks(chipsel);
129
        return;
130
}
131
 
132
/* Read a specific UART register. */
133 238 erez
unsigned long uart_read_byte(unsigned long addr)
134 31 lampret
{
135
        unsigned char value = 0;
136
        int chipsel;
137
 
138 238 erez
        debug("uart_read_byte(%x)\n", addr);
139 221 markom
 
140 31 lampret
        for(chipsel = 0; chipsel < NR_UARTS; chipsel++)
141 341 markom
                if ((addr & ~(UART_ADDR_SPACE-1)) == config.uarts[chipsel].baseaddr)
142 31 lampret
                        break;
143
                else if (chipsel == NR_UARTS)
144
                        return 0;
145
 
146 221 markom
        if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) {
147
                switch (addr % UART_ADDR_SPACE) {
148
                        case UART_DLL:
149
                                value = uarts[chipsel].regs.dll;
150
                                break;
151
                        case UART_DLH:
152
                                value = uarts[chipsel].regs.dlh;
153
                                break;
154
                        default:
155
                                debug("read out of range (addr %x, DLAB=1)\n", addr);
156
                }
157 235 erez
                return value;
158 221 markom
        }
159 31 lampret
 
160
        switch (addr % UART_ADDR_SPACE) {
161
                case UART_RXBUF:
162 341 markom
                  if (uarts[chipsel].istat.rxbuf_full) {
163
                          value = uarts[chipsel].regs.rxbuf[uarts[chipsel].istat.rxbuf_tail];
164
                          uarts[chipsel].istat.rxbuf_tail = (uarts[chipsel].istat.rxbuf_tail + 1) % uarts[chipsel].fifo_len;
165
                          uarts[chipsel].istat.rxbuf_full--;
166
                        }
167
 
168
                        if (uarts[chipsel].istat.rxbuf_full)
169
                          uarts[chipsel].regs.lsr |= UART_LSR_RDRDY;
170
                        else
171
                          uarts[chipsel].regs.lsr &= ~UART_LSR_RDRDY;
172 31 lampret
                        break;
173
                case UART_IER:
174
                        value = uarts[chipsel].regs.ier & UART_VALID_IER;
175
                        break;
176
                case UART_IIR:
177
                        value = uarts[chipsel].regs.iir & UART_VALID_IIR;
178 221 markom
                        uarts[chipsel].istat.thre_int = 0;
179 31 lampret
                        break;
180
                case UART_LCR:
181
                        value = uarts[chipsel].regs.lcr & UART_VALID_LCR;
182
                        break;
183
                case UART_MCR:
184
                        value = uarts[chipsel].regs.mcr & UART_VALID_MCR;
185
                        break;
186
                case UART_LSR:
187
                        value = uarts[chipsel].regs.lsr & UART_VALID_LSR;
188
                        uarts[chipsel].regs.lsr &=
189
                                ~(UART_LSR_OVRRUN | UART_LSR_PARITY
190
                                 | UART_LSR_FRAME | UART_LSR_BREAK);
191
                        break;
192
                case UART_MSR:
193
                        value = uarts[chipsel].regs.msr & UART_VALID_MSR;
194
                        uarts[chipsel].regs.msr = 0;
195
                        break;
196
                case UART_SCR:
197
                        value = uarts[chipsel].regs.scr;
198
                        break;
199
                default:
200
                        debug("read out of range (addr %x)\n", addr);
201
        }
202 235 erez
        return value;
203 31 lampret
}
204
 
205 336 markom
/* Function that handles incoming VAPI data.  */
206
void uart_vapi_read (unsigned long id, unsigned long data)
207
{
208 341 markom
  int uart;
209
  debug("UART: id %08x, data %08x\n", id, data);
210
  uart = id & VAPI_DEVICE_ID;
211
  uarts[uart].vapi_buf[uarts[uart].vapi_buf_head_ptr] = data;
212
  uarts[uart].vapi_buf_head_ptr = (uarts[uart].vapi_buf_head_ptr + 1) % UART_RX_BUF;
213
  if (uarts[uart].vapi_buf_tail_ptr == uarts[uart].vapi_buf_head_ptr) {
214
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
215
    exit (1);
216
  }
217
}
218 336 markom
 
219 341 markom
/* Reset.  It initializes all registers of all UART devices to zero values,
220 31 lampret
   (re)opens all RX/TX file streams and places devices in memory address
221 341 markom
   space.  */
222 31 lampret
void uart_reset()
223
{
224 235 erez
        int i;
225 221 markom
 
226 261 markom
  if (!config.uarts_enabled)
227
    config.nuarts = 0;
228 341 markom
 
229
  if (config.sim.verbose && config.nuarts)
230
    printf("Resetting %u UART(s).\n", config.nuarts);
231
 
232 336 markom
        memset(uarts, 0, sizeof(uarts));
233 261 markom
 
234 341 markom
        for(i = 0; i < config.nuarts; i++) {
235
    if (config.uarts[i].vapi_id) {
236
      if ((config.uarts[i].vapi_id & VAPI_DEVICE_ID) != i) {
237
        fprintf (stderr, "ERROR: Wrong vapi_id (0x%x) for uart %i, last byte is required to be %02x; ignoring.\n", config.uarts[i].vapi_id, i, i);
238
        config.uarts[i].vapi_id = 0;
239
        uarts[i].txfs = 0;
240
      } else {
241
                    vapi_install_handler (config.uarts[i].vapi_id, uart_vapi_read);
242
                    register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
243
                  }
244
                } else if (config.uarts[i].txfile) { /* MM: Try to create stream.  */
245 235 erez
                        if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r"))
246
                                && !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) {
247 341 markom
                                fprintf(stderr, "WARNING: UART%d has problems with RX file stream.\n", i);
248 235 erez
                                continue;
249
                        }
250
                        uarts[i].txfs = fopen(config.uarts[i].txfile, "a");
251 341 markom
                        if (uarts[i].rxfs && uarts[i].txfs && config.sim.verbose) {
252
                                printf("UART%d at 0x%.8x uses ", i, config.uarts[i].baseaddr);
253 235 erez
                                printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile);
254
                        } else
255 341 markom
                                fprintf(stderr, "WARNING: UART%d has problems with TX file stream.\n", i);
256
                  register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
257
    }
258
 
259
    if (config.uarts[i].uart16550)
260
      uarts[i].fifo_len = 16;
261
    else
262
      uarts[i].fifo_len = 1;
263
    uarts[i].istat.rxbuf_head = uarts[i].istat.rxbuf_tail = 0;
264
    uarts[i].istat.txbuf_head = uarts[i].istat.txbuf_tail = 0;
265 336 markom
  }
266 31 lampret
}
267 261 markom
 
268 31 lampret
/* Simulation hook. Must be called every clock cycle to simulate all UART
269
   devices. It does internal functional UART simulation. */
270
void uart_clock()
271
{
272 221 markom
        int i, retval;
273 341 markom
 
274 261 markom
        for(i = 0; i < config.nuarts; i++) {
275 341 markom
    /* If VAPI is not selected, UART communicates with two file streams;
276
       if VAPI is selected, we use VAPI streams.  */
277
 
278
    /* if txfs is corrupted, skip this uart. */
279
                if (!config.uarts[i].vapi_id && !uarts[i].txfs) continue;
280 31 lampret
 
281 221 markom
                /* Transmit */
282 341 markom
                if (!uarts[i].istat.txser_full) {
283 221 markom
                        uarts[i].regs.lsr |= UART_LSR_TXBUFE;
284 341 markom
                        if (uarts[i].istat.txbuf_full) {
285
                                uarts[i].iregs.txser = uarts[i].regs.txbuf[uarts[i].istat.txbuf_tail];
286
                                uarts[i].istat.txbuf_tail = (uarts[i].istat.txbuf_tail + 1) % uarts[i].fifo_len;
287
                                uarts[i].istat.txser_full = 1;
288
                                uarts[i].istat.txbuf_full--;
289 221 markom
                                uarts[i].regs.lsr &= ~UART_LSR_TXSERE;
290
                                uarts[i].istat.thre_int = 1;
291
                        } else
292
                                uarts[i].regs.lsr |= UART_LSR_TXSERE;
293 341 markom
                } else if (uarts[i].char_clks >= uarts[i].istat.txser_clks++) {
294 221 markom
                        debug("TX \'%c\' via UART%d...\n", uarts[i].iregs.txser, i);
295
                        if (uarts[i].regs.mcr & UART_MCR_LOOP)
296
                                uarts[i].iregs.loopback = uarts[i].iregs.txser;
297
                        else {
298 341 markom
                          /* Send to either VAPI or to file */
299
                          if (config.uarts[i].vapi_id) {
300
                            vapi_send (config.uarts[i].vapi_id, uarts[i].iregs.txser);
301
                          } else {
302
                                  fputc((int)(uarts[i].iregs.txser & 0xFF), uarts[i].txfs);
303
                                  fflush(uarts[i].txfs);
304
                                }
305 221 markom
                        }
306 341 markom
                        uarts[i].istat.txser_full = 1;
307 221 markom
                        uarts[i].istat.txser_clks = 0;
308
                }
309 31 lampret
 
310 221 markom
                /* Receive */
311 341 markom
                if (uarts[i].istat.rxser_full) {
312
                        if (uarts[i].char_clks >= uarts[i].istat.rxser_clks++) {
313
                        debug("Receiving via UART%d...\n", i);
314
            uarts[i].istat.rxser_full = 0;
315
                        uarts[i].istat.rxser_clks = 0;
316
 
317
                        if (++uarts[i].istat.rxbuf_full > uarts[i].fifo_len)
318
                                  uarts[i].regs.lsr |= UART_LSR_OVRRUN;
319
                          else {
320
                            uarts[i].regs.rxbuf[uarts[i].istat.rxbuf_head] = uarts[i].iregs.rxser & 0xFF;
321
                            uarts[i].istat.rxbuf_head = (uarts[i].istat.rxbuf_head + 1) % uarts[i].fifo_len;
322
                            uarts[i].istat.rxbuf_full++;
323
                          }
324
                          uarts[i].regs.lsr |= UART_LSR_RDRDY;
325
      }
326 221 markom
                }
327 341 markom
 
328
                /* Check if there is something waiting, and put it into rxser */
329
                if (uarts[i].regs.mcr & UART_MCR_LOOP) {
330
                        uarts[i].iregs.rxser = uarts[i].iregs.loopback;
331
                        uarts[i].istat.rxser_full = 1;
332
          } else {
333
            if (!config.uarts[i].vapi_id) {
334
                    if((retval = fgetc(uarts[i].rxfs)) != EOF)
335
                          uarts[i].iregs.rxser = (char)retval;
336
                          uarts[i].istat.rxser_full = 1;
337
          } else { /* VAPI */
338
          if (uarts[i].vapi_buf_head_ptr != uarts[i].vapi_buf_tail_ptr) {
339
                                uarts[i].iregs.rxser = uarts[i].vapi_buf[uarts[i].vapi_buf_tail_ptr];
340
                                uarts[i].vapi_buf_tail_ptr = (uarts[i].vapi_buf_tail_ptr + 1) % uarts[i].fifo_len;
341
                                uarts[i].istat.rxser_full = 1;
342
                        }
343
          }
344
                }
345
 
346 221 markom
                /* Loopback */
347
                if (uarts[i].regs.mcr & UART_MCR_LOOP) {
348
                        debug("uart_clock: Loopback\n");
349
                        if ((uarts[i].regs.mcr & UART_MCR_AUX2) !=
350
                            ((uarts[i].regs.msr & UART_MSR_DCD) >> 4))
351
                                uarts[i].regs.msr |= UART_MSR_DDCD;
352
                        if ((uarts[i].regs.mcr & UART_MCR_AUX1) <
353
                            ((uarts[i].regs.msr & UART_MSR_RI) >> 4))
354
                                uarts[i].regs.msr |= UART_MSR_TERI;
355
                        if ((uarts[i].regs.mcr & UART_MCR_RTS) !=
356
                            ((uarts[i].regs.msr & UART_MSR_CTS) >> 3))
357
                                uarts[i].regs.msr |= UART_MSR_DCTS;
358
                        if ((uarts[i].regs.mcr & UART_MCR_DTR) !=
359
                            ((uarts[i].regs.msr & UART_MSR_DSR) >> 5))
360
                                uarts[i].regs.msr |= UART_MSR_DDSR;
361
                        uarts[i].regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
362
                                              | UART_MSR_DSR | UART_MSR_CTS);
363
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX2) << 4);
364
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX1) << 4);
365
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_RTS) << 3);
366
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_DTR) << 5);
367
                }
368
 
369
                /* Interrupt detection in proper priority order. */
370
                uarts[i].regs.iir = UART_IIR_NO_INT;
371
                if (uarts[i].regs.ier & UART_IER_RLSI &&
372
                    uarts[i].regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
373
                                        | UART_LSR_FRAME | UART_LSR_BREAK)) {
374
                        uarts[i].regs.iir = UART_IIR_RLSI;
375
                }
376
                else if (uarts[i].regs.ier & UART_IER_RDI &&
377
                    uarts[i].regs.lsr & UART_LSR_RDRDY) {
378
                        uarts[i].regs.iir = UART_IIR_RDI;
379
                }
380
                else if (uarts[i].regs.ier & UART_IER_THRI &&
381
                    uarts[i].regs.lsr & UART_LSR_TXBUFE &&
382
                    uarts[i].istat.thre_int == 1) {
383
                        uarts[i].regs.iir = UART_IIR_THRI;
384
                }
385
                else if (uarts[i].regs.ier & UART_IER_MSI &&
386
                    uarts[i].regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
387
                                        | UART_MSR_TERI | UART_MSR_DDCD)) {
388
                        uarts[i].regs.iir = UART_IIR_MSI;
389
                }
390
                if (!(uarts[i].regs.iir & UART_IIR_NO_INT))
391 332 markom
                        report_interrupt(config.uarts[i].irq);
392 31 lampret
        }
393
}
394
 
395
/* Print register values on stdout. */
396
void uart_status()
397
{
398 341 markom
        int i, j;
399 31 lampret
 
400 261 markom
        for(i = 0; i < config.nuarts; i++) {
401 341 markom
                if ( !config.uarts[i].baseaddr )
402 221 markom
                        continue;
403 341 markom
                printf("\nUART%d visible registers at 0x%.8x:\n", i, config.uarts[i].baseaddr);
404
                printf("RXBUF:");
405
                for (j = uarts[i].istat.rxbuf_head; j != uarts[i].istat.rxbuf_tail; j = (j + 1) % uarts[i].fifo_len)
406
                  printf (" %.2x", uarts[i].regs.rxbuf[j]);
407
                printf("  TXBUF: %.2x\n", uarts[i].regs.txbuf);
408 221 markom
                printf("DLL  : %.2x  DLH  : %.2x\n", uarts[i].regs.dll, uarts[i].regs.dlh);
409
                printf("IER  : %.2x  IIR  : %.2x\n", uarts[i].regs.ier, uarts[i].regs.iir);
410
                printf("LCR  : %.2x  MCR  : %.2x\n", uarts[i].regs.lcr, uarts[i].regs.mcr);
411
                printf("LSR  : %.2x  MSR  : %.2x\n", uarts[i].regs.lsr, uarts[i].regs.msr);
412
                printf("SCR  : %.2x\n", uarts[i].regs.scr);
413 31 lampret
 
414 221 markom
                printf("\nInternal registers (sim debug):\n");
415
                printf("RXSER: %.2x  TXSER: %.2x\n", uarts[i].iregs.rxser, uarts[i].iregs.txser);
416 31 lampret
 
417 221 markom
                printf("\nInternal status (sim debug):\n");
418
                printf("char_clks: %d\n", uarts[i].char_clks);
419
                printf("rxser_clks: %d  txser_clks: %d\n", uarts[i].istat.rxser_clks, uarts[i].istat.txser_clks);
420 341 markom
                printf("rxser: %d  txser: %d\n", uarts[i].istat.rxser_full, uarts[i].istat.txser_full);
421
                printf("rxbuf: %d  txbuf: %d\n", uarts[i].istat.rxbuf_full, uarts[i].istat.txbuf_full);
422
    printf("Using IRQ%i", config.uarts[i].irq);
423 336 markom
    if (config.uarts[i].vapi_id)
424
      printf ("Connected to vapi ID=%x\n\n", config.uarts[i].vapi_id);
425
    else
426
                  printf("RX fs: %p  TX fs: %p\n\n", uarts[i].rxfs, uarts[i].txfs);
427 31 lampret
        }
428
}

powered by: WebSVN 2.1.0

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