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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_66/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 344

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

powered by: WebSVN 2.1.0

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