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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 1392

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

powered by: WebSVN 2.1.0

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