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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_67/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 336

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

powered by: WebSVN 2.1.0

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