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 102

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

powered by: WebSVN 2.1.0

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