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 221

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
#include "16450.h"
35
#include "sim-config.h"
36 102 lampret
#include "pic.h"
37 31 lampret
 
38
static struct dev_16450 uarts[NR_UARTS];
39 221 markom
static int thre_int;
40 31 lampret
 
41
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
42
   before a single character is transmitted or received. */
43
static void set_char_clks(int uartchip)
44
{
45
        int bauds_per_char = 0;
46
 
47
        uarts[uartchip].char_clks = (uarts[uartchip].regs.dlh << 8)
48
                                        + uarts[uartchip].regs.dll;
49
 
50
        if (uarts[uartchip].regs.lcr & UART_LCR_PARITY)
51
                bauds_per_char++;
52
 
53
        if (uarts[uartchip].regs.lcr & UART_LCR_STOP)
54
                bauds_per_char += 2;
55
        else
56
                bauds_per_char++;
57
 
58
        bauds_per_char += (5 + (uarts[uartchip].regs.lcr & 0x2));
59
 
60
        uarts[uartchip].char_clks *= bauds_per_char;
61
}
62
 
63
/* Set a specific UART register with value. */
64 221 markom
void uart_write(unsigned long addr, unsigned long value)
65 31 lampret
{
66
        int chipsel;
67
 
68 221 markom
        debug("uart_write(%x,%x)\n", addr, (value >> 24));
69
 
70 31 lampret
        for(chipsel = 0; chipsel < NR_UARTS; chipsel++)
71
                if ((addr & ~(UART_ADDR_SPACE-1)) == uarts[chipsel].baseaddr)
72
                        break;
73
                else if (chipsel == NR_UARTS)
74
                        return;
75
 
76 221 markom
        if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) {
77
                switch (addr % UART_ADDR_SPACE) {
78
                        case UART_DLL:
79
                                uarts[chipsel].regs.dll = (value >> 24);
80
                                break;
81
                        case UART_DLH:
82
                                uarts[chipsel].regs.dlh = (value >> 24);
83
                                break;
84
                        case UART_LCR:
85
                                uarts[chipsel].regs.lcr = (value >> 24) & UART_VALID_LCR;
86
                                break;
87
                        default:
88
                                debug("write out of range (addr %x, DLAB=1)\n", addr);
89
                }
90 31 lampret
                set_char_clks(chipsel);
91
                return;
92 221 markom
        }
93 31 lampret
 
94
        switch (addr % UART_ADDR_SPACE) {
95
                case UART_TXBUF:
96 221 markom
                        uarts[chipsel].regs.txbuf = (value >> 24);
97 31 lampret
                        uarts[chipsel].istat.txbuf = FULL;
98
                        uarts[chipsel].regs.lsr &= ~UART_LSR_TXBUFE;
99
                        uarts[chipsel].regs.lsr &= ~UART_LSR_TXSERE;
100 221 markom
                        uarts[chipsel].istat.thre_int = 0;
101 31 lampret
                        break;
102
                case UART_IER:
103 221 markom
                        uarts[chipsel].regs.ier = (value >> 24) & UART_VALID_IER;
104 31 lampret
                        break;
105
                case UART_LCR:
106 221 markom
                        uarts[chipsel].regs.lcr = (value >> 24) & UART_VALID_LCR;
107 31 lampret
                        break;
108
                case UART_MCR:
109 221 markom
                        uarts[chipsel].regs.mcr = (value >> 24) & UART_VALID_MCR;
110 31 lampret
                        break;
111
                case UART_SCR:
112 221 markom
                        uarts[chipsel].regs.scr = (value >> 24);
113 31 lampret
                        break;
114
                default:
115
                        debug("write out of range (addr %x)\n", addr);
116
        }
117
        set_char_clks(chipsel);
118
        return;
119
}
120
 
121
/* Read a specific UART register. */
122 221 markom
unsigned long uart_read(unsigned long addr)
123 31 lampret
{
124
        unsigned char value = 0;
125
        int chipsel;
126
 
127
        debug("uart_read(%x)\n", addr);
128 221 markom
 
129 31 lampret
        for(chipsel = 0; chipsel < NR_UARTS; chipsel++)
130
                if ((addr & ~(UART_ADDR_SPACE-1)) == uarts[chipsel].baseaddr)
131
                        break;
132
                else if (chipsel == NR_UARTS)
133
                        return 0;
134
 
135 221 markom
        if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) {
136
                switch (addr % UART_ADDR_SPACE) {
137
                        case UART_DLL:
138
                                value = uarts[chipsel].regs.dll;
139
                                break;
140
                        case UART_DLH:
141
                                value = uarts[chipsel].regs.dlh;
142
                                break;
143
                        default:
144
                                debug("read out of range (addr %x, DLAB=1)\n", addr);
145
                }
146
                return (value << 24);
147
        }
148 31 lampret
 
149
        switch (addr % UART_ADDR_SPACE) {
150
                case UART_RXBUF:
151
                        value = uarts[chipsel].regs.rxbuf;
152
                        uarts[chipsel].istat.rxbuf = EMPTY;
153
                        uarts[chipsel].regs.lsr &= ~UART_LSR_RDRDY;
154
                        break;
155
                case UART_IER:
156
                        value = uarts[chipsel].regs.ier & UART_VALID_IER;
157
                        break;
158
                case UART_IIR:
159
                        value = uarts[chipsel].regs.iir & UART_VALID_IIR;
160 221 markom
                        uarts[chipsel].istat.thre_int = 0;
161 31 lampret
                        break;
162
                case UART_LCR:
163
                        value = uarts[chipsel].regs.lcr & UART_VALID_LCR;
164
                        break;
165
                case UART_MCR:
166
                        value = uarts[chipsel].regs.mcr & UART_VALID_MCR;
167
                        break;
168
                case UART_LSR:
169
                        value = uarts[chipsel].regs.lsr & UART_VALID_LSR;
170
                        uarts[chipsel].regs.lsr &=
171
                                ~(UART_LSR_OVRRUN | UART_LSR_PARITY
172
                                 | UART_LSR_FRAME | UART_LSR_BREAK);
173
                        break;
174
                case UART_MSR:
175
                        value = uarts[chipsel].regs.msr & UART_VALID_MSR;
176
                        uarts[chipsel].regs.msr = 0;
177
                        break;
178
                case UART_SCR:
179
                        value = uarts[chipsel].regs.scr;
180
                        break;
181
                default:
182
                        debug("read out of range (addr %x)\n", addr);
183
        }
184 221 markom
        return (value << 24);
185 31 lampret
}
186
 
187
/* Reset. It initializes all registers of all UART devices to zero values,
188
   (re)opens all RX/TX file streams and places devices in memory address
189
   space. */
190
void uart_reset()
191
{
192 123 markom
  int i;
193 221 markom
 
194 123 markom
  printf("Resetting %u UART(s).\n", NR_UARTS);
195
  memset(uarts, 0, sizeof(uarts));
196
 
197
  for(i = 0; i < NR_UARTS; i++)
198
    if (config.uarts[i].txfile) { /* MM: Try to create stream.  */
199 221 markom
      if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r"))
200
          && !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) {
201
        printf("UART%d has problems with RX file stream.\n", i);
202
        continue;
203
      }
204
      uarts[i].txfs = fopen(config.uarts[i].txfile, "a");
205 123 markom
      uarts[i].baseaddr = config.uarts[i].baseaddr;
206 221 markom
      if (uarts[i].txfs && uarts[i].txfs) {
207
        printf("UART%d at 0x%.8x uses ", i, uarts[i].baseaddr);
208
        printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile);
209
      } else
210
        printf("UART%d has problems with TX file stream.\n", i);
211
      register_memoryarea(uarts[i].baseaddr, UART_ADDR_SPACE, uart_read, uart_write);
212 123 markom
    }
213 31 lampret
}
214 123 markom
 
215 31 lampret
/* Simulation hook. Must be called every clock cycle to simulate all UART
216
   devices. It does internal functional UART simulation. */
217
void uart_clock()
218
{
219 221 markom
        int i, retval;
220 31 lampret
 
221
        for(i = 0; i < NR_UARTS; i++) {
222 221 markom
                if (!uarts[i].txfs) {
223
                        continue;
224
                }
225 31 lampret
 
226 221 markom
                /* Transmit */
227
                if (uarts[i].istat.txser == EMPTY) {
228
                        uarts[i].regs.lsr |= UART_LSR_TXBUFE;
229
                        if (uarts[i].istat.txbuf == FULL) {
230
                                uarts[i].iregs.txser = uarts[i].regs.txbuf;
231
                                uarts[i].istat.txser = FULL;
232
                                uarts[i].istat.txbuf = EMPTY;
233
                                uarts[i].regs.lsr &= ~UART_LSR_TXSERE;
234
                                uarts[i].istat.thre_int = 1;
235
                        } else
236
                                uarts[i].regs.lsr |= UART_LSR_TXSERE;
237
                } else if (uarts[i].char_clks == uarts[i].istat.txser_clks++) {
238
                        debug("TX \'%c\' via UART%d...\n", uarts[i].iregs.txser, i);
239
                        if (uarts[i].regs.mcr & UART_MCR_LOOP)
240
                                uarts[i].iregs.loopback = uarts[i].iregs.txser;
241
                        else {
242
                                fputc((int)uarts[i].iregs.txser, uarts[i].txfs);
243
                                fflush(uarts[i].txfs);
244
                        }
245
                        uarts[i].istat.txser = EMPTY;
246
                        uarts[i].istat.txser_clks = 0;
247
                }
248 31 lampret
 
249 221 markom
                /* Receive */
250
                if (uarts[i].istat.rxser == EMPTY)
251
                        uarts[i].istat.rxser = FULL;
252
                else if (uarts[i].char_clks == uarts[i].istat.rxser_clks++) {
253
                        debug("Receiving via UART%d...\n", i);
254
                        if (uarts[i].regs.mcr & UART_MCR_LOOP)
255
                                uarts[i].iregs.rxser = uarts[i].iregs.loopback;
256
                        else if((retval = fgetc(uarts[i].rxfs)) != EOF) {
257
                                uarts[i].iregs.rxser = (char)retval;
258
                                if (uarts[i].istat.rxbuf == FULL)
259
                                        uarts[i].regs.lsr |= UART_LSR_OVRRUN;
260
                                uarts[i].regs.lsr |= UART_LSR_RDRDY;
261
                                uarts[i].regs.rxbuf = uarts[i].iregs.rxser;
262
                                uarts[i].istat.rxbuf = FULL;
263
                        }
264
                        uarts[i].istat.rxser = EMPTY;
265
                        uarts[i].istat.rxser_clks = 0;
266
                }
267 31 lampret
 
268 221 markom
                /* Loopback */
269
                if (uarts[i].regs.mcr & UART_MCR_LOOP) {
270
                        debug("uart_clock: Loopback\n");
271
                        if ((uarts[i].regs.mcr & UART_MCR_AUX2) !=
272
                            ((uarts[i].regs.msr & UART_MSR_DCD) >> 4))
273
                                uarts[i].regs.msr |= UART_MSR_DDCD;
274
                        if ((uarts[i].regs.mcr & UART_MCR_AUX1) <
275
                            ((uarts[i].regs.msr & UART_MSR_RI) >> 4))
276
                                uarts[i].regs.msr |= UART_MSR_TERI;
277
                        if ((uarts[i].regs.mcr & UART_MCR_RTS) !=
278
                            ((uarts[i].regs.msr & UART_MSR_CTS) >> 3))
279
                                uarts[i].regs.msr |= UART_MSR_DCTS;
280
                        if ((uarts[i].regs.mcr & UART_MCR_DTR) !=
281
                            ((uarts[i].regs.msr & UART_MSR_DSR) >> 5))
282
                                uarts[i].regs.msr |= UART_MSR_DDSR;
283
                        uarts[i].regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
284
                                              | UART_MSR_DSR | UART_MSR_CTS);
285
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX2) << 4);
286
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX1) << 4);
287
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_RTS) << 3);
288
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_DTR) << 5);
289
                }
290
 
291
                /* Interrupt detection in proper priority order. */
292
                uarts[i].regs.iir = UART_IIR_NO_INT;
293
                if (uarts[i].regs.ier & UART_IER_RLSI &&
294
                    uarts[i].regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
295
                                        | UART_LSR_FRAME | UART_LSR_BREAK)) {
296
                        uarts[i].regs.iir = UART_IIR_RLSI;
297
                }
298
                else if (uarts[i].regs.ier & UART_IER_RDI &&
299
                    uarts[i].regs.lsr & UART_LSR_RDRDY) {
300
                        uarts[i].regs.iir = UART_IIR_RDI;
301
                }
302
                else if (uarts[i].regs.ier & UART_IER_THRI &&
303
                    uarts[i].regs.lsr & UART_LSR_TXBUFE &&
304
                    uarts[i].istat.thre_int == 1) {
305
                        uarts[i].regs.iir = UART_IIR_THRI;
306
                }
307
                else if (uarts[i].regs.ier & UART_IER_MSI &&
308
                    uarts[i].regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
309
                                        | UART_MSR_TERI | UART_MSR_DDCD)) {
310
                        uarts[i].regs.iir = UART_IIR_MSI;
311
                }
312
                if (!(uarts[i].regs.iir & UART_IIR_NO_INT))
313
                        report_interrupt(INT_UART);
314 31 lampret
        }
315
}
316
 
317
/* Print register values on stdout. */
318
void uart_status()
319
{
320 221 markom
        int i;
321 31 lampret
 
322 221 markom
        for(i = 0; i < NR_UARTS; i++) {
323
/*              if (!uarts[i].txfs)
324
                        continue;
325
*/
326
                printf("\nUART%d visible registers at 0x%.8x:\n", i, uarts[i].baseaddr);
327
                printf("RXBUF: %.2x  TXBUF: %.2x\n", uarts[i].regs.rxbuf, uarts[i].regs.txbuf);
328
                printf("DLL  : %.2x  DLH  : %.2x\n", uarts[i].regs.dll, uarts[i].regs.dlh);
329
                printf("IER  : %.2x  IIR  : %.2x\n", uarts[i].regs.ier, uarts[i].regs.iir);
330
                printf("LCR  : %.2x  MCR  : %.2x\n", uarts[i].regs.lcr, uarts[i].regs.mcr);
331
                printf("LSR  : %.2x  MSR  : %.2x\n", uarts[i].regs.lsr, uarts[i].regs.msr);
332
                printf("SCR  : %.2x\n", uarts[i].regs.scr);
333 31 lampret
 
334 221 markom
                printf("\nInternal registers (sim debug):\n");
335
                printf("RXSER: %.2x  TXSER: %.2x\n", uarts[i].iregs.rxser, uarts[i].iregs.txser);
336 31 lampret
 
337 221 markom
                printf("\nInternal status (sim debug):\n");
338
                printf("char_clks: %d\n", uarts[i].char_clks);
339
                printf("rxser_clks: %d  txser_clks: %d\n", uarts[i].istat.rxser_clks, uarts[i].istat.txser_clks);
340
                printf("rxser: %d  txser: %d\n", uarts[i].istat.rxser, uarts[i].istat.txser);
341
                printf("rxbuf: %d  txbuf: %d\n", uarts[i].istat.rxbuf, uarts[i].istat.txbuf);
342 31 lampret
 
343 221 markom
                printf("RX fs: %p  TX fs: %p\n\n", uarts[i].rxfs, uarts[i].txfs);
344 31 lampret
        }
345
}

powered by: WebSVN 2.1.0

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