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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_52/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 332

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 261 markom
  if (!config.uarts_enabled)
199
    config.nuarts = 0;
200
 
201
        for(i = 0; i < config.nuarts; i++)
202 235 erez
                if (config.uarts[i].txfile) { /* MM: Try to create stream.  */
203
                        if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r"))
204
                                && !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) {
205
                                printf("UART%d has problems with RX file stream.\n", i);
206
                                continue;
207
                        }
208
                        uarts[i].txfs = fopen(config.uarts[i].txfile, "a");
209
                        uarts[i].baseaddr = config.uarts[i].baseaddr;
210 252 erez
                        if (uarts[i].rxfs && uarts[i].txfs) {
211 235 erez
                                printf("UART%d at 0x%.8x uses ", i, uarts[i].baseaddr);
212
                                printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile);
213
                        } else
214
                                printf("UART%d has problems with TX file stream.\n", i);
215 261 markom
                        register_memoryarea(uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
216 235 erez
                }
217 31 lampret
}
218 261 markom
 
219 31 lampret
/* Simulation hook. Must be called every clock cycle to simulate all UART
220
   devices. It does internal functional UART simulation. */
221
void uart_clock()
222
{
223 221 markom
        int i, retval;
224 31 lampret
 
225 261 markom
        for(i = 0; i < config.nuarts; i++) {
226 221 markom
                if (!uarts[i].txfs) {
227
                        continue;
228
                }
229 31 lampret
 
230 221 markom
                /* Transmit */
231
                if (uarts[i].istat.txser == EMPTY) {
232
                        uarts[i].regs.lsr |= UART_LSR_TXBUFE;
233
                        if (uarts[i].istat.txbuf == FULL) {
234
                                uarts[i].iregs.txser = uarts[i].regs.txbuf;
235
                                uarts[i].istat.txser = FULL;
236
                                uarts[i].istat.txbuf = EMPTY;
237
                                uarts[i].regs.lsr &= ~UART_LSR_TXSERE;
238
                                uarts[i].istat.thre_int = 1;
239
                        } else
240
                                uarts[i].regs.lsr |= UART_LSR_TXSERE;
241
                } else if (uarts[i].char_clks == uarts[i].istat.txser_clks++) {
242
                        debug("TX \'%c\' via UART%d...\n", uarts[i].iregs.txser, i);
243
                        if (uarts[i].regs.mcr & UART_MCR_LOOP)
244
                                uarts[i].iregs.loopback = uarts[i].iregs.txser;
245
                        else {
246
                                fputc((int)uarts[i].iregs.txser, uarts[i].txfs);
247
                                fflush(uarts[i].txfs);
248
                        }
249
                        uarts[i].istat.txser = EMPTY;
250
                        uarts[i].istat.txser_clks = 0;
251
                }
252 31 lampret
 
253 221 markom
                /* Receive */
254
                if (uarts[i].istat.rxser == EMPTY)
255
                        uarts[i].istat.rxser = FULL;
256
                else if (uarts[i].char_clks == uarts[i].istat.rxser_clks++) {
257
                        debug("Receiving via UART%d...\n", i);
258
                        if (uarts[i].regs.mcr & UART_MCR_LOOP)
259
                                uarts[i].iregs.rxser = uarts[i].iregs.loopback;
260
                        else if((retval = fgetc(uarts[i].rxfs)) != EOF) {
261
                                uarts[i].iregs.rxser = (char)retval;
262
                                if (uarts[i].istat.rxbuf == FULL)
263
                                        uarts[i].regs.lsr |= UART_LSR_OVRRUN;
264
                                uarts[i].regs.lsr |= UART_LSR_RDRDY;
265
                                uarts[i].regs.rxbuf = uarts[i].iregs.rxser;
266
                                uarts[i].istat.rxbuf = FULL;
267
                        }
268
                        uarts[i].istat.rxser = EMPTY;
269
                        uarts[i].istat.rxser_clks = 0;
270
                }
271 31 lampret
 
272 221 markom
                /* Loopback */
273
                if (uarts[i].regs.mcr & UART_MCR_LOOP) {
274
                        debug("uart_clock: Loopback\n");
275
                        if ((uarts[i].regs.mcr & UART_MCR_AUX2) !=
276
                            ((uarts[i].regs.msr & UART_MSR_DCD) >> 4))
277
                                uarts[i].regs.msr |= UART_MSR_DDCD;
278
                        if ((uarts[i].regs.mcr & UART_MCR_AUX1) <
279
                            ((uarts[i].regs.msr & UART_MSR_RI) >> 4))
280
                                uarts[i].regs.msr |= UART_MSR_TERI;
281
                        if ((uarts[i].regs.mcr & UART_MCR_RTS) !=
282
                            ((uarts[i].regs.msr & UART_MSR_CTS) >> 3))
283
                                uarts[i].regs.msr |= UART_MSR_DCTS;
284
                        if ((uarts[i].regs.mcr & UART_MCR_DTR) !=
285
                            ((uarts[i].regs.msr & UART_MSR_DSR) >> 5))
286
                                uarts[i].regs.msr |= UART_MSR_DDSR;
287
                        uarts[i].regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
288
                                              | UART_MSR_DSR | UART_MSR_CTS);
289
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX2) << 4);
290
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX1) << 4);
291
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_RTS) << 3);
292
                        uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_DTR) << 5);
293
                }
294
 
295
                /* Interrupt detection in proper priority order. */
296
                uarts[i].regs.iir = UART_IIR_NO_INT;
297
                if (uarts[i].regs.ier & UART_IER_RLSI &&
298
                    uarts[i].regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
299
                                        | UART_LSR_FRAME | UART_LSR_BREAK)) {
300
                        uarts[i].regs.iir = UART_IIR_RLSI;
301
                }
302
                else if (uarts[i].regs.ier & UART_IER_RDI &&
303
                    uarts[i].regs.lsr & UART_LSR_RDRDY) {
304
                        uarts[i].regs.iir = UART_IIR_RDI;
305
                }
306
                else if (uarts[i].regs.ier & UART_IER_THRI &&
307
                    uarts[i].regs.lsr & UART_LSR_TXBUFE &&
308
                    uarts[i].istat.thre_int == 1) {
309
                        uarts[i].regs.iir = UART_IIR_THRI;
310
                }
311
                else if (uarts[i].regs.ier & UART_IER_MSI &&
312
                    uarts[i].regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
313
                                        | UART_MSR_TERI | UART_MSR_DDCD)) {
314
                        uarts[i].regs.iir = UART_IIR_MSI;
315
                }
316
                if (!(uarts[i].regs.iir & UART_IIR_NO_INT))
317 332 markom
                        report_interrupt(config.uarts[i].irq);
318 31 lampret
        }
319
}
320
 
321
/* Print register values on stdout. */
322
void uart_status()
323
{
324 221 markom
        int i;
325 31 lampret
 
326 261 markom
        for(i = 0; i < config.nuarts; i++) {
327 235 erez
                if ( !uarts[i].baseaddr )
328 221 markom
                        continue;
329
                printf("\nUART%d visible registers at 0x%.8x:\n", i, uarts[i].baseaddr);
330
                printf("RXBUF: %.2x  TXBUF: %.2x\n", uarts[i].regs.rxbuf, uarts[i].regs.txbuf);
331
                printf("DLL  : %.2x  DLH  : %.2x\n", uarts[i].regs.dll, uarts[i].regs.dlh);
332
                printf("IER  : %.2x  IIR  : %.2x\n", uarts[i].regs.ier, uarts[i].regs.iir);
333
                printf("LCR  : %.2x  MCR  : %.2x\n", uarts[i].regs.lcr, uarts[i].regs.mcr);
334
                printf("LSR  : %.2x  MSR  : %.2x\n", uarts[i].regs.lsr, uarts[i].regs.msr);
335
                printf("SCR  : %.2x\n", uarts[i].regs.scr);
336 31 lampret
 
337 221 markom
                printf("\nInternal registers (sim debug):\n");
338
                printf("RXSER: %.2x  TXSER: %.2x\n", uarts[i].iregs.rxser, uarts[i].iregs.txser);
339 31 lampret
 
340 221 markom
                printf("\nInternal status (sim debug):\n");
341
                printf("char_clks: %d\n", uarts[i].char_clks);
342
                printf("rxser_clks: %d  txser_clks: %d\n", uarts[i].istat.rxser_clks, uarts[i].istat.txser_clks);
343
                printf("rxser: %d  txser: %d\n", uarts[i].istat.rxser, uarts[i].istat.txser);
344
                printf("rxbuf: %d  txbuf: %d\n", uarts[i].istat.rxbuf, uarts[i].istat.txbuf);
345 31 lampret
 
346 221 markom
                printf("RX fs: %p  TX fs: %p\n\n", uarts[i].rxfs, uarts[i].txfs);
347 31 lampret
        }
348
}

powered by: WebSVN 2.1.0

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