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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_34/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 238

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