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

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc3/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 1499

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 1350 nogj
#include "config.h"
35
 
36
#ifdef HAVE_INTTYPES_H
37
#include <inttypes.h>
38
#endif
39
 
40
#include "port.h"
41
#include "arch.h"
42 235 erez
#include "abstract.h"
43 31 lampret
#include "16450.h"
44
#include "sim-config.h"
45 102 lampret
#include "pic.h"
46 336 markom
#include "vapi.h"
47 805 markom
#include "sched.h"
48 1073 rprescott
#include "channel.h"
49 1308 phoenix
#include "debug.h"
50 31 lampret
 
51 1392 nogj
DEFAULT_DEBUG_CHANNEL(uart);
52
 
53 409 markom
#define MIN(a,b) ((a) < (b) ? (a) : (b))
54
 
55 1499 nogj
void uart_tx_send(void *dat);
56
 
57 31 lampret
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
58
   before a single character is transmitted or received. */
59 355 markom
static unsigned long char_clks(int dll, int dlh, int lcr)
60 31 lampret
{
61 1396 nogj
  unsigned int bauds_per_char = 2;
62 806 markom
  unsigned long char_clks = ((dlh << 8) + dll);
63 355 markom
 
64
  if (lcr & UART_LCR_PARITY)
65 1396 nogj
    bauds_per_char += 2;
66 31 lampret
 
67 355 markom
  /* stop bits 1 or two */
68
  if (lcr & UART_LCR_STOP)
69 1396 nogj
    bauds_per_char += 4;
70 355 markom
  else
71
    if ((lcr & 0x3) != 0)
72 1396 nogj
      bauds_per_char += 2;
73 355 markom
    else
74 1396 nogj
      bauds_per_char += 3;
75 355 markom
 
76 1396 nogj
  bauds_per_char += 10 + ((lcr & 0x3) << 1);
77 355 markom
 
78 1396 nogj
  return (char_clks * bauds_per_char) >> 1;
79 31 lampret
}
80
 
81 1499 nogj
/*----------------------------------------------------[ Transmitter logic ]---*/
82
/* Sends the data in the shift register to the outside world */
83
static void send_char (struct dev_16450 *uart, int bits_send)
84
{
85
  PRINTF ("%c", (char)uart->iregs.txser);
86
  TRACE("TX \'%c\' via UART at %"PRIxADDR"\n", (char)uart->iregs.txser,
87
        uart->baseaddr);
88
  if (uart->regs.mcr & UART_MCR_LOOP)
89
    uart->iregs.loopback = uart->iregs.txser;
90
  else {
91
    /* Send to either VAPI or to file */
92
    if (uart->vapi_id) {
93
      int par, pe, fe, nbits;
94
      int j, data;
95
      unsigned long packet = 0;
96
 
97
      nbits = MIN (bits_send, (uart->regs.lcr & UART_LCR_WLEN8) + 5);
98
      /* Encode a packet */
99
      packet = uart->iregs.txser & ((1 << nbits) - 1);
100
 
101
      /* Calculate parity */
102
      for (j = 0, par = 0; j < nbits; j++)
103
        par ^= (packet >> j) & 1;
104
 
105
      if (uart->regs.lcr & UART_LCR_PARITY) {
106
        if (uart->regs.lcr & UART_LCR_SPAR) {
107
          packet |= 1 << nbits;
108
        } else {
109
          if (uart->regs.lcr & UART_LCR_EPAR)
110
            packet |= par << nbits;
111
          else
112
            packet |= (par ^ 1) << nbits;
113
        }
114
        nbits++;
115
      }
116
      packet |= 1 << (nbits++);
117
      if (uart->regs.lcr & UART_LCR_STOP)
118
        packet |= 1 << (nbits++);
119
 
120
      /* Decode a packet */
121
      nbits = (uart->vapi.lcr & UART_LCR_WLEN8) + 5;
122
      data = packet & ((1 << nbits) - 1);
123
 
124
      /* Calculate parity, including parity bit */
125
      for (j = 0, par = 0; j < nbits + 1; j++)
126
        par ^= (packet >> j) & 1;
127
 
128
      if (uart->vapi.lcr & UART_LCR_PARITY) {
129
        if (uart->vapi.lcr & UART_LCR_SPAR) {
130
          pe = !((packet >> nbits) & 1);
131
        } else {
132
          if (uart->vapi.lcr & UART_LCR_EPAR)
133
            pe = par != 0;
134
          else
135
            pe = par != 1;
136
        }
137
        nbits++;
138
      } else
139
        pe = 0;
140
 
141
      fe = ((packet >> (nbits++)) & 1) ^ 1;
142
      if (uart->vapi.lcr & UART_LCR_STOP)
143
        fe |= ((packet >> (nbits++)) & 1) ^ 1;
144
 
145
      TRACE ("lcr vapi %02x, uart %02x\n", uart->vapi.lcr, uart->regs.lcr);
146
      data |= (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi.lcr << 8);
147
      TRACE ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
148
      vapi_send (uart->vapi_id, data);
149
    } else {
150
      char buffer[1] = { uart->iregs.txser & 0xFF };
151
      channel_write(uart->channel, buffer, 1);
152
    }
153
  }
154
}
155
 
156
/* Called when all the bits have been shifted out of the shift register */
157
void uart_char_clock(void *dat)
158
{
159
  struct dev_16450 *uart = dat;
160
 
161
  TRACE("Sending data in shift reg: 0x%02lx\n", uart->iregs.txser);
162
  /* We've sent all bits */
163
  send_char(uart, (uart->regs.lcr & UART_LCR_WLEN8) + 5);
164
 
165
  if(!uart->istat.txbuf_full)
166
    uart->regs.lsr |= UART_LSR_TXSERE;
167
  else
168
    uart_tx_send(uart);
169
}
170
 
171
/* Called when a break has been shifted out of the shift register */
172
void uart_send_break(void *dat)
173
{
174
  struct dev_16450 *uart = dat;
175
 
176
  TRACE("Sending break\n");
177
#if 0
178
  /* Send broken frame */
179
  int nbits_sent = ((uart->regs.lcr & UART_LCR_WLEN8) + 5) * (uart->istat.txser_clks - 1) / uart->char_clks;
180
  send_char(i, nbits_sent);
181
#endif
182
  /* Send one break signal */
183
  vapi_send (uart->vapi_id, UART_LCR_SBC << 8);
184
 
185
  /* Send the next char (if there is one) */
186
  if(!uart->istat.txbuf_full)
187
    uart->regs.lsr |= UART_LSR_TXSERE;
188
  else
189
    uart_tx_send(uart);
190
}
191
 
192
/* Scheduled whenever the TX buffer has characters in it and we aren't sending
193
 * a character. */
194
void uart_tx_send(void *dat)
195
{
196
  struct dev_16450 *uart = dat;
197
 
198
  uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
199
  uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
200
  uart->istat.txbuf_full--;
201
  uart->regs.lsr &= ~UART_LSR_TXSERE;
202
 
203
  TRACE("Moveing head of TX fifo (fill: %i) to shift reg 0x%02lx\n",
204
        uart->istat.txbuf_full, uart->iregs.txser);
205
 
206
  /* Schedules a char_clock to run in the correct amount of time */
207
  if(!(uart->regs.lcr & UART_LCR_SBC)) {
208
    SCHED_ADD(uart_char_clock, uart, uart->char_clks * UART_CLOCK_DIVIDER);
209
  } else {
210
    TRACE("Sending break not char\n");
211
    SCHED_ADD(uart_send_break, uart, 0);
212
  }
213
 
214
  /* When UART is in either character mode, i.e. 16450 emulation mode, or FIFO
215
   * mode, the THRE interrupt is raised when THR transitions from full to empty.
216
   */
217
  if (!uart->istat.txbuf_full) {
218
    uart->regs.lsr |= UART_LSR_TXBUFE;
219
    uart->istat.thre_int = 1;
220
  }
221
}
222
 
223 31 lampret
/* Set a specific UART register with value. */
224 1486 nogj
void uart_write_byte(oraddr_t addr, uint8_t value, void *dat)
225 31 lampret
{
226 1367 nogj
  struct dev_16450 *uart = dat;
227 355 markom
 
228 1486 nogj
  TRACE("uart_write_byte(%"PRIxADDR",%02"PRIx8")\n", addr, value);
229 341 markom
 
230 1367 nogj
  if (uart->regs.lcr & UART_LCR_DLAB) {
231 1486 nogj
    switch (addr) {
232 355 markom
      case UART_DLL:
233 1367 nogj
        uart->regs.dll = value;
234
        uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
235 1392 nogj
        TRACE("\tSetting char_clks to %li (%02x, %02x, %02x)\n", uart->char_clks,
236
              uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
237 355 markom
        return;
238
      case UART_DLH:
239 1367 nogj
        uart->regs.dlh = value;
240 355 markom
        return;
241
    }
242
  }
243
 
244 1486 nogj
  switch (addr) {
245 355 markom
    case UART_TXBUF:
246 1499 nogj
      uart->regs.lsr &= ~UART_LSR_TXBUFE;
247 1367 nogj
      if (uart->istat.txbuf_full < uart->fifo_len) {
248
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
249
        uart->istat.txbuf_head = (uart->istat.txbuf_head + 1) % uart->fifo_len;
250 1499 nogj
        if(!uart->istat.txbuf_full++ && (uart->regs.lsr & UART_LSR_TXSERE))
251
          SCHED_ADD(uart_tx_send, uart, 0);
252 355 markom
      } else
253 1367 nogj
        uart->regs.txbuf[uart->istat.txbuf_head] = value;
254 341 markom
 
255 1367 nogj
      if (uart->regs.iir & UART_IIR_THRI)
256
        uart->istat.thre_int = 0;
257 355 markom
      break;
258 409 markom
    case UART_FCR:
259 1367 nogj
      uart->regs.fcr = value & UART_VALID_FCR;
260
      if ((uart->fifo_len == 1 && (value & UART_FCR_FIE))
261
       || (uart->fifo_len != 1 && !(value & UART_FCR_FIE)))
262 409 markom
        value |= UART_FCR_RRXFI | UART_FCR_RTXFI;
263 1367 nogj
      uart->fifo_len = (value & UART_FCR_FIE) ? 16 : 1;
264 409 markom
      if (value & UART_FCR_RTXFI) {
265 1367 nogj
        uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
266
        uart->istat.txbuf_full = 0;
267
        uart->regs.lsr |= UART_LSR_TXBUFE;
268 1145 sfurman
 
269
        // For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty
270 1367 nogj
        uart->istat.thre_int = (uart->fifo_len == 16);
271 1499 nogj
 
272
        SCHED_FIND_REMOVE(uart_tx_send, uart);
273 409 markom
      }
274
      if (value & UART_FCR_RRXFI) {
275 1367 nogj
        uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
276
        uart->istat.rxbuf_full = 0;
277
        uart->regs.lsr &= ~UART_LSR_RDRDY;
278 409 markom
      }
279
      break;
280 355 markom
    case UART_IER:
281 1367 nogj
      uart->regs.ier = value & UART_VALID_IER;
282 355 markom
      break;
283
    case UART_LCR:
284 1499 nogj
      if((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) {
285
        if((value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
286
          /* Schedule a job to send the break char */
287
          SCHED_FIND_REMOVE(uart_char_clock, uart);
288
          SCHED_ADD(uart_send_break, uart, 0);
289
        }
290
        if(!(value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) {
291
          /* Schedule a job to start sending characters */
292
          SCHED_ADD(uart_tx_send, uart, 0);
293
          /* Remove the uart_send_break job just in case it has not run yet */
294
          SCHED_FIND_REMOVE(uart_char_clock, uart);
295
        }
296
      }
297 1367 nogj
      uart->regs.lcr = value & UART_VALID_LCR;
298
      uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
299 355 markom
      break;
300
    case UART_MCR:
301 1367 nogj
      uart->regs.mcr = value & UART_VALID_MCR;
302 355 markom
      break;
303
    case UART_SCR:
304 1367 nogj
      uart->regs.scr = value;
305 355 markom
      break;
306
    default:
307 1392 nogj
      TRACE("write out of range (addr %x)\n", addr);
308 355 markom
  }
309 31 lampret
}
310
 
311
/* Read a specific UART register. */
312 1486 nogj
uint8_t uart_read_byte(oraddr_t addr, void *dat)
313 31 lampret
{
314 1367 nogj
  struct dev_16450 *uart = dat;
315 1350 nogj
  uint8_t value = 0;
316 355 markom
 
317 1392 nogj
  TRACE("uart_read_byte(%"PRIxADDR")", addr);
318 355 markom
 
319 1367 nogj
  if (uart->regs.lcr & UART_LCR_DLAB) {
320 1486 nogj
    switch (addr) {
321 355 markom
      case UART_DLL:
322 1367 nogj
        value = uart->regs.dll;
323 1392 nogj
        TRACE("= %"PRIx8"\n", value);
324 355 markom
        return value;
325
      case UART_DLH:
326 1367 nogj
        value = uart->regs.dlh;
327 1392 nogj
        TRACE("= %"PRIx8"\n", value);
328 355 markom
        return value;
329
    }
330
  }
331
 
332 1486 nogj
  switch (addr) {
333 355 markom
    case UART_RXBUF:
334 409 markom
      { /* Print out FIFO for debugging */
335
        int i;
336 1392 nogj
        TRACE("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len,
337
              uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
338 1367 nogj
        for (i = 0; i < uart->istat.rxbuf_full; i++)
339 1392 nogj
          TRACE("%02x ", uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
340
        TRACE(")");
341 409 markom
      }
342 1367 nogj
      if (uart->istat.rxbuf_full) {
343
        value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
344
        uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
345
        uart->istat.rxbuf_full--;
346 355 markom
      }
347
 
348 1367 nogj
      if (uart->istat.rxbuf_full)
349
        uart->regs.lsr |= UART_LSR_RDRDY;
350 355 markom
      else
351 1367 nogj
        uart->regs.lsr &= ~UART_LSR_RDRDY;
352 409 markom
 
353 1367 nogj
      uart->istat.timeout_count = 0;
354 355 markom
      break;
355
    case UART_IER:
356 1367 nogj
      value = uart->regs.ier & UART_VALID_IER;
357 355 markom
      break;
358
    case UART_IIR:
359 1367 nogj
      value = (uart->regs.iir & UART_VALID_IIR) | 0xc0;
360
      if (uart->regs.iir & UART_IIR_THRI)
361
        uart->istat.thre_int = 0;
362 355 markom
      break;
363
    case UART_LCR:
364 1367 nogj
      value = uart->regs.lcr & UART_VALID_LCR;
365 355 markom
      break;
366
    case UART_MCR:
367
      value = 0;
368
      break;
369
    case UART_LSR:
370 1367 nogj
      value = uart->regs.lsr & UART_VALID_LSR;
371
      uart->regs.lsr &=
372 409 markom
        ~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
373
         | UART_LSR_FRAME | UART_LSR_RXERR);
374 355 markom
      break;
375
    case UART_MSR:
376 1367 nogj
      value = uart->regs.msr & UART_VALID_MSR;
377
      uart->regs.msr = 0;
378 355 markom
      break;
379
    case UART_SCR:
380 1367 nogj
      value = uart->regs.scr;
381 355 markom
      break;
382
    default:
383 1392 nogj
      TRACE("read out of range (addr %"PRIxADDR")\n", addr);
384 355 markom
  }
385 1392 nogj
  TRACE(" = %"PRIx8"\n", value);
386 355 markom
  return value;
387 31 lampret
}
388
 
389 336 markom
/* Function that handles incoming VAPI data.  */
390 1366 nogj
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
391 336 markom
{
392 1367 nogj
  struct dev_16450 *uart = dat;
393 1392 nogj
  TRACE("UART: id %08lx, data %08lx\n", id, data);
394 1367 nogj
  uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
395
  uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
396
  if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
397 341 markom
    fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
398
    exit (1);
399
  }
400
}
401 336 markom
 
402 411 markom
/* Adds a character to the FIFO */
403
 
404 1367 nogj
void uart_add_char (struct dev_16450 *uart, int ch)
405 411 markom
{
406 1367 nogj
  if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
407
    uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
408 411 markom
  else {
409 1392 nogj
    TRACE("add %02x\n", ch);
410 1367 nogj
    uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
411
    uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
412
    uart->istat.rxbuf_full++;
413 411 markom
  }
414 1367 nogj
  uart->regs.lsr |= UART_LSR_RDRDY;
415
  uart->istat.timeout_count = 0;
416 411 markom
}
417
 
418 806 markom
/* Simulation hook. Must be called every clock cycle to simulate all UART
419
   devices. It does internal functional UART simulation. */
420 1367 nogj
void uart_clock16 (void *dat)
421 806 markom
{
422 1367 nogj
  struct dev_16450 *uart = dat;
423 806 markom
  int retval;
424 1073 rprescott
 
425 821 markom
  /* Schedule for later */
426 1390 nogj
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
427 1392 nogj
 
428
  TRACE("Running uart clock:\n");
429 821 markom
 
430 806 markom
  /* If VAPI is not selected, UART communicates with two file streams;
431
     if VAPI is selected, we use VAPI streams.  */
432
  /* if txfs is corrupted, skip this uart. */
433 1367 nogj
  if (!uart->vapi_id && !channel_ok(uart->channel)) return;
434 1392 nogj
 
435
  TRACE("\tChannel stream or VAPI checks out ok\n");
436 806 markom
 
437 1367 nogj
  if (uart->vapi.next_break_cnt >= 0)
438
    if (--uart->vapi.next_break_cnt < 0) {
439
      if (!(uart->vapi.cur_break = uart->vapi.next_break))
440
        uart->istat.break_set = 0;
441 806 markom
    }
442 821 markom
 
443 806 markom
  /***************** Receive *****************/
444
 
445
  /* Is there a break? */
446 1367 nogj
  if (uart->vapi.cur_break) {
447
    uart->vapi.cur_break_cnt++;
448
    if (uart->vapi.cur_break_cnt > UART_BREAK_COUNT * uart->vapi.char_clks) {
449
      if (!uart->istat.break_set) {
450 806 markom
        unsigned lsr;
451 1367 nogj
        uart->istat.break_set = 1;
452 806 markom
        lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY;
453 1367 nogj
        PRINTF ("[%x]\n", uart->regs.lsr);
454
        uart->istat.rxser_full = 0;
455
        uart->istat.rxser_clks = 0;
456
        uart_add_char (uart, lsr << 8);
457 806 markom
      } else
458 1367 nogj
        uart->vapi.cur_break_cnt = 0;
459 806 markom
    }
460 1367 nogj
    if (uart->istat.rxser_full) {
461
      uart->istat.rxser_full = 0;
462
      uart->istat.rxser_clks = 0;
463 806 markom
    }
464
  } else {
465 1367 nogj
    if (uart->istat.rxser_full) {
466
      if (uart->char_clks <= uart->istat.rxser_clks++) {
467 806 markom
        /* Set unused character bits to zero and allow lsr register in fifo */
468 1367 nogj
        uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
469 1392 nogj
        TRACE("\tReceiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
470 1367 nogj
              uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
471
        PRINTF ("%c", (char)uart->iregs.rxser);
472
        uart->istat.rxser_full = 0;
473
        uart->istat.rxser_clks = 0;
474
        uart_add_char (uart, uart->iregs.rxser);
475 806 markom
      }
476
    }
477
  }
478
 
479
  /* Check if there is something waiting, and put it into rxser */
480 1367 nogj
  if (uart->regs.mcr & UART_MCR_LOOP) {
481
    uart->iregs.rxser = uart->iregs.loopback;
482
    uart->istat.rxser_full = 1;
483 806 markom
  } else {
484 1367 nogj
    if (!uart->vapi_id) {
485
      if(uart->istat.rxser_full == 0) {
486
        if (uart->slowdown)
487
          uart->slowdown--;
488 1073 rprescott
        else {
489
          char buffer[1];
490 1367 nogj
          retval = channel_read(uart->channel, buffer, 1);
491 1073 rprescott
          if(retval < 0)
492 1367 nogj
                  perror(uart->channel_str);
493 1073 rprescott
          else if(retval > 0) {
494 1367 nogj
            uart->iregs.rxser = (unsigned char)buffer[0];
495
            uart->istat.rxser_full = 1;
496 1073 rprescott
          } else
497 1367 nogj
            uart->slowdown = UART_FGETC_SLOWDOWN;
498 1073 rprescott
        }
499 806 markom
      }
500
    } else { /* VAPI */
501
      int received = 0;
502
      /* do not handle commands while receiving */
503 1367 nogj
      if (uart->istat.rxser_full) return;
504 806 markom
      while (!received) {
505 1367 nogj
        if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
506
          unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
507 1392 nogj
          TRACE("\tHandling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
508 1367 nogj
                uart->vapi_buf_tail_ptr);
509
          uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
510 806 markom
          switch (data >> 24) {
511
            case 0x00:
512 1367 nogj
              uart->vapi.lcr = (data >> 8) & 0xff;
513 806 markom
              /* Put data into rx fifo */
514 1367 nogj
              uart->iregs.rxser = data & 0xff;
515
              uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
516
              if ((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
517
               || uart->vapi.char_clks != uart->char_clks
518
               || uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
519 1392 nogj
                WARN("WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
520 1367 nogj
                      uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
521 806 markom
                /* Set error bits */
522 1367 nogj
                uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
523
                if (uart->regs.lcr & UART_LCR_PARITY) uart->iregs.rxser |= UART_LSR_PARITY << 8;
524 806 markom
              }
525 1367 nogj
              uart->istat.rxser_full = 1;
526 806 markom
              received = 1;
527
              break;
528
            case 0x01:
529 1367 nogj
              uart->vapi.dll = (data >> 0) & 0xff;
530
              uart->vapi.dlh = (data >> 8) & 0xff;
531 806 markom
              break;
532
            case 0x02:
533 1367 nogj
              uart->vapi.lcr = (data >> 8) & 0xff;
534 806 markom
              break;
535
            case 0x03:
536 1367 nogj
              uart->vapi.skew = (signed short)(data & 0xffff);
537 806 markom
              break;
538
            case 0x04:
539 1367 nogj
              uart->vapi.next_break_cnt = data & 0xffff;
540
              uart->vapi.next_break = (data >> 16) & 1;
541 806 markom
              break;
542
            default:
543 1392 nogj
              WARN ("WARNING: Invalid vapi command %02lx\n", data >> 24);
544 806 markom
              break;
545
          }
546
        } else break;
547
      }
548
    }
549
  }
550
 
551
  /***************** Loopback *****************/
552 1367 nogj
  if (uart->regs.mcr & UART_MCR_LOOP) {
553 1392 nogj
    TRACE("uart_clock: Loopback\n");
554 1367 nogj
    if ((uart->regs.mcr & UART_MCR_AUX2) !=
555
        ((uart->regs.msr & UART_MSR_DCD) >> 4))
556
      uart->regs.msr |= UART_MSR_DDCD;
557
    if ((uart->regs.mcr & UART_MCR_AUX1) <
558
        ((uart->regs.msr & UART_MSR_RI) >> 4))
559
      uart->regs.msr |= UART_MSR_TERI;
560
    if ((uart->regs.mcr & UART_MCR_RTS) !=
561
        ((uart->regs.msr & UART_MSR_CTS) >> 3))
562
      uart->regs.msr |= UART_MSR_DCTS;
563
    if ((uart->regs.mcr & UART_MCR_DTR) !=
564
        ((uart->regs.msr & UART_MSR_DSR) >> 5))
565
      uart->regs.msr |= UART_MSR_DDSR;
566
    uart->regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
567 806 markom
              | UART_MSR_DSR | UART_MSR_CTS);
568 1367 nogj
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_AUX2) << 4);
569
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_AUX1) << 4);
570
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_RTS) << 3);
571
    uart->regs.msr |= ((uart->regs.mcr & UART_MCR_DTR) << 5);
572 806 markom
  }
573
 
574 1367 nogj
  if (uart->regs.lsr & UART_LSR_RDRDY)
575
    uart->istat.timeout_count++;
576 806 markom
 
577
  /* Update LSR error bits from the ones from rx FIFO */
578 1367 nogj
  if (uart->istat.rxbuf_full) {
579
    uart->regs.lsr |= uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
580 806 markom
    /* we must delete the lsr status, so that we can clear it from lsr */
581 1367 nogj
    uart->regs.rxbuf[uart->istat.rxbuf_tail] &= 0xff;
582 806 markom
  }
583
 
584
  /* Interrupt detection in proper priority order. */
585 1367 nogj
  uart->regs.iir = UART_IIR_NO_INT;
586
  if (uart->regs.ier & UART_IER_RLSI &&                    /* Receiver LS */
587
      uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
588 806 markom
        | UART_LSR_FRAME | UART_LSR_BREAK)) {
589 1367 nogj
    uart->regs.iir = UART_IIR_RLSI;
590
  } else if ((uart->regs.ier & UART_IER_RDI)               /* RD available */
591
      && (uart->istat.rxbuf_full >= UART_FIFO_TRIGGER(uart->regs.fcr >> 6))
592
      && (uart->regs.lsr & UART_LSR_RDRDY)) {
593
    uart->regs.iir = UART_IIR_RDI;
594
  } else if ((uart->regs.ier & UART_IER_RDI)               /* timeout */
595
      && (uart->istat.timeout_count >= UART_CHAR_TIMEOUT * uart->char_clks)
596
      && (uart->istat.rxbuf_head != uart->istat.rxbuf_tail)) {
597
    uart->regs.iir = UART_IIR_CTI;
598
  } else if (uart->regs.ier & UART_IER_THRI &&             /* Transm. empty */
599
      uart->istat.thre_int == 1) {
600
    uart->regs.iir = UART_IIR_THRI;
601
  } else if (uart->regs.ier & UART_IER_MSI &&              /* Modem status */
602
      uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
603 806 markom
        | UART_MSR_TERI | UART_MSR_DDCD)) {
604 1367 nogj
    uart->regs.iir = UART_IIR_MSI;
605 806 markom
  }
606 1367 nogj
  if (!(uart->regs.iir & UART_IIR_NO_INT)) {
607 1392 nogj
    TRACE("\tuart->regs.iir = %i\t", uart->regs.iir);
608 1367 nogj
    report_interrupt(uart->irq);
609 806 markom
  }
610
}
611
 
612 341 markom
/* Reset.  It initializes all registers of all UART devices to zero values,
613 31 lampret
   (re)opens all RX/TX file streams and places devices in memory address
614 341 markom
   space.  */
615 1367 nogj
void uart_reset(void *dat)
616 31 lampret
{
617 1367 nogj
  struct dev_16450 *uart = dat;
618 261 markom
 
619 1394 nogj
  if(uart->vapi_id) {
620
    vapi_install_handler(uart->vapi_id, uart_vapi_read, dat);
621
  } else if (uart->channel_str && uart->channel_str[0]) { /* Try to create stream. */
622 1367 nogj
    if(uart->channel)
623
      channel_close(uart->channel);
624 341 markom
    else
625 1367 nogj
      uart->channel = channel_init(uart->channel_str);
626
    if(channel_open(uart->channel) < 0) {
627 1476 nogj
      WARN ("WARNING: problem with channel \"%s\" detected.\n", uart->channel_str);
628 1367 nogj
    } else if (config.sim.verbose)
629 1486 nogj
      PRINTF("UART at 0x%"PRIxADDR"\n", uart->baseaddr);
630 1367 nogj
  } else {
631 1476 nogj
    WARN ("WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n",
632
          uart->baseaddr);
633 1367 nogj
  }
634 344 markom
 
635 1367 nogj
  if (uart->uart16550)
636
    uart->fifo_len = 16;
637
  else
638
    uart->fifo_len = 1;
639 1145 sfurman
 
640 1367 nogj
  uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
641
  uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
642
 
643 1499 nogj
  uart->istat.rxser_full = 0;
644 1367 nogj
  uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
645 1145 sfurman
 
646 1499 nogj
  uart->istat.rxser_clks = 0;
647 492 markom
 
648 1367 nogj
  uart->istat.thre_int = 0;
649
  uart->istat.break_set = 0;
650
  uart->istat.timeout_count = 0;
651
 
652
  // For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
653
  uart->istat.thre_int = (uart->fifo_len == 16);
654
 
655
  uart->char_clks = 0;
656
  uart->slowdown = UART_FGETC_SLOWDOWN;
657
 
658
  uart->iregs.txser = 0;
659
  uart->iregs.rxser = 0;
660
  uart->iregs.loopback = 0;
661
 
662
  memset(uart->regs.txbuf, 0, sizeof(uart->regs.txbuf));
663
  memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
664
 
665
  uart->regs.dll = 0;
666
  uart->regs.dlh = 0;
667
  uart->regs.ier = 0;
668
  uart->regs.iir = 0;
669
  uart->regs.fcr = 0;
670
  uart->regs.lcr = UART_LCR_RESET;
671
  uart->regs.mcr = 0;
672 1499 nogj
  uart->regs.lsr = UART_LSR_TXBUFE | UART_LSR_TXSERE;
673 1367 nogj
  uart->regs.msr = 0;
674
  uart->regs.scr = 0;
675
 
676
  uart->vapi.cur_break = uart->vapi.cur_break_cnt = uart->vapi.next_break = 0;
677
  uart->vapi.next_break_cnt = -1;
678
  uart->vapi.skew = 0;
679
  uart->vapi.lcr = 0;
680
  uart->vapi.dll = 0;
681
  uart->vapi.char_clks = 0;
682
 
683
  uart->vapi_buf_head_ptr = 0;
684
  uart->vapi_buf_tail_ptr = 0;
685
  memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
686
 
687 1390 nogj
  SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
688 31 lampret
}
689 261 markom
 
690 31 lampret
/* Print register values on stdout. */
691 1367 nogj
void uart_status(void *dat)
692 31 lampret
{
693 1367 nogj
  struct dev_16450 *uart = dat;
694
  int i;
695 355 markom
 
696 1367 nogj
  PRINTF("\nUART visible registers at 0x%"PRIxADDR":\n", uart->baseaddr);
697
  PRINTF("RXBUF: ");
698
  for (i = uart->istat.rxbuf_head; i != uart->istat.rxbuf_tail; i = (i + 1) % uart->fifo_len)
699
    PRINTF (" %.2x", uart->regs.rxbuf[i]);
700
  PRINTF("TXBUF: ");
701
  for (i = uart->istat.txbuf_head; i != uart->istat.txbuf_tail; i = (i + 1) % uart->fifo_len)
702
    PRINTF (" %.2x", uart->regs.txbuf[i]);
703
  PRINTF("\n");
704
  PRINTF("DLL  : %.2x  DLH  : %.2x\n", uart->regs.dll, uart->regs.dlh);
705
  PRINTF("IER  : %.2x  IIR  : %.2x\n", uart->regs.ier, uart->regs.iir);
706
  PRINTF("LCR  : %.2x  MCR  : %.2x\n", uart->regs.lcr, uart->regs.mcr);
707
  PRINTF("LSR  : %.2x  MSR  : %.2x\n", uart->regs.lsr, uart->regs.msr);
708
  PRINTF("SCR  : %.2x\n", uart->regs.scr);
709 31 lampret
 
710 1367 nogj
  PRINTF("\nInternal registers (sim debug):\n");
711
  PRINTF("RXSER: %.2lx  TXSER: %.2lx\n", uart->iregs.rxser, uart->iregs.txser);
712 31 lampret
 
713 1367 nogj
  PRINTF("\nInternal status (sim debug):\n");
714
  PRINTF("char_clks: %ld\n", uart->char_clks);
715 1499 nogj
  PRINTF("rxser_clks: %ld\n", uart->istat.rxser_clks);
716
  PRINTF("rxser: %d\n", uart->istat.rxser_full);
717 1367 nogj
  PRINTF("rxbuf_full: %d  txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
718
  PRINTF("Using IRQ%i\n", uart->irq);
719
  if (uart->vapi_id)
720
    PRINTF ("Connected to vapi ID=%lx\n\n", uart->vapi_id);
721
  /* TODO: replace by a channel_status
722
  else
723
    PRINTF("RX fs: %p  TX fs: %p\n\n", uart->rxfs, uart->txfs);
724
  */
725 31 lampret
}
726 1358 nogj
 
727
/*---------------------------------------------------[ UART configuration ]---*/
728
void uart_baseaddr(union param_val val, void *dat)
729
{
730 1367 nogj
  struct dev_16450 *uart = dat;
731
  uart->baseaddr = val.addr_val;
732 1358 nogj
}
733
 
734
void uart_jitter(union param_val val, void *dat)
735
{
736 1367 nogj
  struct dev_16450 *uart = dat;
737
  uart->jitter = val.int_val;
738 1358 nogj
}
739
 
740
void uart_irq(union param_val val, void *dat)
741
{
742 1367 nogj
  struct dev_16450 *uart = dat;
743
  uart->irq = val.int_val;
744 1358 nogj
}
745
 
746
void uart_16550(union param_val val, void *dat)
747
{
748 1367 nogj
  struct dev_16450 *uart = dat;
749
  uart->uart16550 = val.int_val;
750 1358 nogj
}
751
 
752
void uart_channel(union param_val val, void *dat)
753
{
754 1367 nogj
  struct dev_16450 *uart = dat;
755
  if(!(uart->channel_str = strdup(val.str_val))) {
756
    fprintf(stderr, "Peripheral 16450: Run out of memory\n");
757
    exit(-1);
758
  }
759 1358 nogj
}
760
 
761
void uart_newway(union param_val val, void *dat)
762
{
763
  CONFIG_ERROR(" txfile and rxfile and now obsolete.\n\tUse 'channel = \"file:rxfile,txfile\"' instead.");
764
  exit(1);
765
}
766
 
767
void uart_vapi_id(union param_val val, void *dat)
768
{
769 1367 nogj
  struct dev_16450 *uart = dat;
770
  uart->vapi_id = val.int_val;
771 1358 nogj
}
772
 
773 1461 nogj
void uart_enabled(union param_val val, void *dat)
774
{
775
  struct dev_16450 *uart = dat;
776
  uart->enabled = val.int_val;
777
}
778
 
779 1367 nogj
void *uart_sec_start(void)
780
{
781
  struct dev_16450 *new = malloc(sizeof(struct dev_16450));
782
 
783
  if(!new) {
784
    fprintf(stderr, "Peripheral 16450: Run out of memory\n");
785
    exit(-1);
786
  }
787
 
788 1461 nogj
  new->enabled = 1;
789 1367 nogj
  new->channel_str = NULL;
790
  new->channel = NULL;
791
  new->vapi_id = 0;
792
 
793
  return new;
794
}
795
 
796
void uart_sec_end(void *dat)
797
{
798
  struct dev_16450 *uart = dat;
799 1486 nogj
  struct mem_ops ops;
800 1367 nogj
 
801 1461 nogj
  if(!uart->enabled) {
802
    free(dat);
803
    return;
804
  }
805 1486 nogj
 
806
  memset(&ops, 0, sizeof(struct mem_ops));
807
 
808
  ops.readfunc8 = uart_read_byte;
809
  ops.writefunc8 = uart_write_byte;
810
  ops.read_dat8 = dat;
811
  ops.write_dat8 = dat;
812
 
813
  /* FIXME: What should these be? */
814
  ops.delayr = 2;
815
  ops.delayw = 2;
816
 
817
  reg_mem_area(uart->baseaddr, UART_ADDR_SPACE, 0, &ops);
818
 
819 1367 nogj
  reg_sim_reset(uart_reset, dat);
820
  reg_sim_stat(uart_status, dat);
821
}
822
 
823 1358 nogj
void reg_uart_sec(void)
824
{
825 1367 nogj
  struct config_section *sec = reg_config_sec("uart", uart_sec_start,
826
                                              uart_sec_end);
827 1358 nogj
 
828
  reg_config_param(sec, "baseaddr", paramt_addr, uart_baseaddr);
829 1461 nogj
  reg_config_param(sec, "enabled", paramt_int, uart_enabled);
830 1358 nogj
  reg_config_param(sec, "irq", paramt_int, uart_irq);
831
  reg_config_param(sec, "16550", paramt_int, uart_16550);
832
  reg_config_param(sec, "jitter", paramt_int, uart_jitter);
833
  reg_config_param(sec, "channel", paramt_str, uart_channel);
834
  reg_config_param(sec, "txfile", paramt_str, uart_newway);
835
  reg_config_param(sec, "rxfile", paramt_str, uart_newway);
836
  reg_config_param(sec, "vapi_id", paramt_int, uart_vapi_id);
837
}

powered by: WebSVN 2.1.0

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