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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_43/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 31

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

powered by: WebSVN 2.1.0

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