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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [powerpc/] [eth_comm/] [canbus/] [canbus.c] - Blame information for rev 30

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
2
 * RTEMS CANBUS driver for eth-comm BSP
3
 *
4
 * Written by Jay Monkman (jmonkman@frasca.com)
5
 *
6
 *  COPYRIGHT (c) 1998
7
 *  Frasca International, Inc.
8
 *
9
 *  The license and distribution terms for this file may be
10
 *  found in the file LICENSE in this distribution or at
11
 *  http://www.OARcorp.com/rtems/license.html.
12
 *
13
 *  Note: All of this code assumes a 10Mhz clock input to the 82527
14
 *
15
 *  $Id: canbus.c,v 1.2 2001-09-27 12:00:35 chris Exp $
16
 */
17
#include <stdio.h>
18
#include <bsp.h>
19
#include <mpc860.h>
20
#include <rtems/error.h>
21
#include <canbus.h>
22
/* How many CAN interfaces are there? */
23
#define NUM_CAN_DEVS 3
24
 
25
/* How many received messages should be buffered for each channel */
26
#define RX_CAN_BUF_SIZE 16
27
 
28
int rxMsgBufHead[NUM_CAN_DEVS];
29
int rxMsgBufTail[NUM_CAN_DEVS];
30
i82527_msg_t rxMsgBuf[NUM_CAN_DEVS][RX_CAN_BUF_SIZE];
31
 
32
volatile i82527_t *candev[NUM_CAN_DEVS];
33
 
34
 
35
static rtems_isr
36
canInterruptHandler (rtems_vector_number v)
37
{
38
  int dev;
39
  int tmpTail;
40
 
41
  switch (v) {
42
  case PPC_IRQ_IRQ3: dev = 0; break;
43
  case PPC_IRQ_IRQ4: dev = 1; break;
44
  case PPC_IRQ_IRQ2: dev = 2; break;
45
  default:           return;    /* something screwed up */
46
  }
47
 
48
  /* we only do rx interrupts right now */
49
  if (!(candev[dev]->msg15.ctrl1 & I82527_MSG_CTRL_NEWDAT)) {
50
    /* Hmmm, that's odd. Why were we triggered? */
51
    candev[dev]->msg15.ctrl0 = 0xff & (I82527_MSG_CTRL_INTPND_CLR |
52
                                       I82527_MSG_CTRL_MSGVAL_SET);
53
    candev[dev]->msg15.ctrl1 = 0xff & (I82527_MSG_CTRL_RMTPND_CLR |
54
                                       I82527_MSG_CTRL_MSGLST_CLR |
55
                                       I82527_MSG_CTRL_NEWDAT_CLR);
56
    return;
57
  }
58
  tmpTail = rxMsgBufTail[dev];
59
  while (1) {
60
    if ((tmpTail == rxMsgBufHead[dev]) &&
61
        (rxMsgBuf[dev][tmpTail].ctrl1 & I82527_MSG_CTRL_NEWDAT)) {
62
      break;  /* Buf is full */
63
    }
64
 
65
    if (!(rxMsgBuf[dev][tmpTail].ctrl1 & I82527_MSG_CTRL_NEWDAT)) {
66
      int pkt_len;
67
      int i;
68
 
69
      rxMsgBuf[dev][tmpTail].ctrl0 = candev[dev]->msg15.ctrl0;
70
      rxMsgBuf[dev][tmpTail].ctrl1 = candev[dev]->msg15.ctrl1;
71
      rxMsgBuf[dev][tmpTail].arb = candev[dev]->msg15.arb;
72
      rxMsgBuf[dev][tmpTail].cfg = candev[dev]->msg15.cfg;
73
 
74
      pkt_len = (rxMsgBuf[dev][tmpTail].cfg >> 4) & 0xf;
75
      for (i=0; i<pkt_len; i++) {
76
        rxMsgBuf[dev][tmpTail].data[i] = candev[dev]->msg15.data[i];
77
      }
78
 
79
      tmpTail++;
80
      if (tmpTail == RX_CAN_BUF_SIZE) {
81
        tmpTail = 0;
82
      }
83
 
84
      rxMsgBufTail[dev] = tmpTail;
85
 
86
      break;
87
    }
88
 
89
    tmpTail++;
90
    if (tmpTail == RX_CAN_BUF_SIZE) {
91
      tmpTail = 0;
92
    }
93
    if (tmpTail == rxMsgBufTail[dev]) {
94
      break;
95
    }
96
  }
97
 
98
 
99
  candev[dev]->msg15.ctrl0  = 0xff & (I82527_MSG_CTRL_MSGVAL_SET |
100
                                      I82527_MSG_CTRL_INTPND_CLR);
101
  candev[dev]->msg15.ctrl1  = 0xff & (I82527_MSG_CTRL_NEWDAT_CLR |
102
                                      I82527_MSG_CTRL_RMTPND_CLR);
103
  candev[dev]->status = 0x0;
104
}
105
 
106
rtems_device_driver canbus_initialize(
107
  rtems_device_major_number  major,
108
  rtems_device_minor_number  minor,
109
  void                      *arg
110
)
111
{
112
  int i,j;
113
  char dev_str[16]; /* This allows us to have a device name up to */
114
                    /* 15 chars long. If we only use names like   */
115
                    /* /dev/can0 (9 chars) we will be fine up to  */
116
                    /* /dev/can9999999 */
117
  rtems_status_code status;
118
  rtems_isr_entry old_handler;
119
 
120
#if (NUM_CAN_DEVS > 0)
121
  candev[0]=&canbus0;
122
  rtems_interrupt_catch (canInterruptHandler,
123
                         PPC_IRQ_IRQ3,
124
                         &old_handler);
125
 
126
#if (NUM_CAN_DEVS > 1)
127
  candev[1]=&canbus1;
128
  rtems_interrupt_catch (canInterruptHandler,
129
                         PPC_IRQ_IRQ4,
130
                         &old_handler);
131
 
132
#if (NUM_CAN_DEVS > 2)
133
  candev[2]=&canbus2;
134
  rtems_interrupt_catch (canInterruptHandler,
135
                         PPC_IRQ_IRQ2,
136
                         &old_handler);
137
 
138
  /* Right now, we only support 3 CAN interfaces */
139
#else
140
#error NUM_CAN_DEVS is too big. Fix it, damnit!
141
#endif /* NUM_CAN_DEVS > 2 */
142
#endif /* NUM_CAN_DEVS > 1 */
143
#else
144
#error NUM_CAN_DEVS is 0. It needs to be at least 1
145
#endif /* NUM_CAN_DEVS > 0 */
146
 
147
 
148
  for (i=0; i < NUM_CAN_DEVS; i++) {
149
 
150
    /* clear rx buffers */
151
    rxMsgBufHead[i] = 0;
152
    rxMsgBufTail[i] = 0;
153
    for (j=0; j < RX_CAN_BUF_SIZE; j++) {
154
      rxMsgBuf[i][j].ctrl0 = 0x55; /* all flags are cleared */
155
      rxMsgBuf[i][j].ctrl1 = 0x55; /* all flags are cleared */
156
    }
157
 
158
    candev[i]->ctrl = I82527_CTRL_CCE | /* Enable cfg reg writes */
159
                      I82527_CTRL_INIT; /* Disable external xfers */
160
 
161
    candev[i]->cir = I82527_CIR_DMC;    /* Divide memory clock by 2 */
162
 
163
 
164
    /* We want 250 kbps so assuming an input clock rate of 10 MHz:
165
     *   DSC = 0  =>  SCLK = 10 MHz, tSCLK = 100ns
166
     *   BRP = 1  =>  tq = 200ns
167
     *   tSYNC_SEG = 1 tq
168
     *   tSEG1 = TSEG1+1 = 14+1 = 15
169
     *   tSEG2 = TSEG2+1 = 3+1  = 4
170
     *
171
     *  bittime = tSYNC_SEG + tSEG1 + tSEG2
172
     *          = 1 + 15 + 4 = 20
173
     *  baudrate = 1/(bittime * tq) = 1/(20 * 200ns) = 1/(4000ns) = 250 kbps
174
     */
175
    candev[i]->btr0 = 0xc1;  /* Baud rate prescaler=0, Sync jump width=3 */
176
 
177
    candev[i]->btr1 = I82527_BTR1_SPL | /* go for noise immunity */
178
                      (0x3 << 4) |      /* TSEG2 = 3 */
179
                      (0xe);            /* TSEG1 = 14 */
180
 
181
    candev[i]->gms = 0xffff;            /* addresses must match exactly */
182
    candev[i]->gml = 0xffffffff;        /* addresses must match exactly */
183
 
184
    candev[i]->mlm = 0x0;               /* all addresses accepted */
185
 
186
    candev[i]->p2conf = 0xff;           /* make all outputs */
187
 
188
    candev[i]->msg1.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
189
    candev[i]->msg1.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
190
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
191
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
192
                             I82527_MSG_CTRL_INTPND_CLR;
193
 
194
    candev[i]->msg2.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
195
    candev[i]->msg2.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
196
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
197
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
198
                             I82527_MSG_CTRL_INTPND_CLR;
199
 
200
    candev[i]->msg3.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
201
    candev[i]->msg3.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
202
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
203
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
204
                             I82527_MSG_CTRL_INTPND_CLR;
205
 
206
    candev[i]->msg4.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
207
    candev[i]->msg4.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
208
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
209
                             I82527_MSG_CTRL_RXIE_CLR  | /* no rx interrupts */
210
                             I82527_MSG_CTRL_INTPND_CLR;
211
 
212
    candev[i]->msg5.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
213
    candev[i]->msg5.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
214
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
215
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
216
                             I82527_MSG_CTRL_INTPND_CLR;
217
 
218
    candev[i]->msg6.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
219
    candev[i]->msg6.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
220
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
221
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
222
                             I82527_MSG_CTRL_INTPND_CLR;
223
 
224
    candev[i]->msg7.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
225
    candev[i]->msg7.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
226
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
227
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
228
                             I82527_MSG_CTRL_INTPND_CLR;
229
 
230
    candev[i]->msg8.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
231
    candev[i]->msg8.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
232
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
233
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
234
                             I82527_MSG_CTRL_INTPND_CLR;
235
 
236
    candev[i]->msg9.cfg    = I82527_MSG_CFG_DIR ;        /* dir is xmit */
237
    candev[i]->msg9.ctrl0  = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
238
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
239
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
240
                             I82527_MSG_CTRL_INTPND_CLR;
241
 
242
    candev[i]->msg10.cfg   = I82527_MSG_CFG_DIR ;        /* dir is xmit */
243
    candev[i]->msg10.ctrl0 = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
244
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
245
                             I82527_MSG_CTRL_RXIE_CLR  | /* no rx interrupts */
246
                             I82527_MSG_CTRL_INTPND_CLR;
247
 
248
    candev[i]->msg11.cfg   = I82527_MSG_CFG_DIR ;        /* dir is xmit */
249
    candev[i]->msg11.ctrl0 = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
250
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
251
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
252
                             I82527_MSG_CTRL_INTPND_CLR;
253
 
254
    candev[i]->msg12.cfg   = I82527_MSG_CFG_DIR ;        /* dir is xmit */
255
    candev[i]->msg12.ctrl0 = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
256
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
257
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
258
                             I82527_MSG_CTRL_INTPND_CLR;
259
 
260
    candev[i]->msg13.cfg   = I82527_MSG_CFG_DIR ;        /* dir is xmit */
261
    candev[i]->msg13.ctrl0 = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
262
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
263
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
264
                             I82527_MSG_CTRL_INTPND_CLR;
265
 
266
    candev[i]->msg14.cfg   = I82527_MSG_CFG_DIR ;        /* dir is xmit */
267
    candev[i]->msg14.ctrl0 = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
268
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
269
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
270
                             I82527_MSG_CTRL_INTPND_CLR;
271
 
272
    candev[i]->msg15.cfg   = 0 ;        /* dir is rcv */
273
    candev[i]->msg15.ctrl0 = I82527_MSG_CTRL_MSGVAL_CLR |/* this msg invalid */
274
                             I82527_MSG_CTRL_TXIE_CLR   |/* no tx interrupts */
275
                             I82527_MSG_CTRL_RXIE_CLR   |/* no rx interrupts */
276
                             I82527_MSG_CTRL_INTPND_CLR;
277
    candev[i]->msg15.ctrl1 = I82527_MSG_CTRL_RMTPND_CLR |
278
                             I82527_MSG_CTRL_TXRQ_CLR   |
279
                             I82527_MSG_CTRL_MSGLST_CLR |
280
                             I82527_MSG_CTRL_NEWDAT_CLR;
281
 
282
  }
283
 
284
  if ((status=rtems_io_register_name ("/dev/can0", major, 0)) !=
285
      RTEMS_SUCCESSFUL) {
286
    rtems_fatal_error_occurred (status);
287
  }
288
  if ((status=rtems_io_register_name ("/dev/can1", major, 1)) !=
289
      RTEMS_SUCCESSFUL) {
290
    rtems_fatal_error_occurred (status);
291
  }
292
  if ((status=rtems_io_register_name ("/dev/can2", major, 2)) !=
293
      RTEMS_SUCCESSFUL) {
294
    rtems_fatal_error_occurred (status);
295
  }
296
  return RTEMS_SUCCESSFUL;
297
}
298
 
299
rtems_device_driver canbus_open(
300
  rtems_device_major_number major,
301
  rtems_device_minor_number minor,
302
  void                    * arg
303
)
304
{
305
    /* msg is in use, rx interrupts are enabled */
306
  candev[minor]->msg15.ctrl0 = 0xff & (I82527_MSG_CTRL_MSGVAL_SET |
307
                                       I82527_MSG_CTRL_RXIE_SET);
308
 
309
  candev[minor]->ctrl |= I82527_CTRL_IE;
310
  candev[minor]->ctrl &= ~(I82527_CTRL_CCE | I82527_CTRL_INIT);
311
  switch (minor) {
312
  case 0: m860.simask |= M860_SIMASK_IRM3; break;
313
  case 1: m860.simask |= M860_SIMASK_IRM4; break;
314
  case 2: m860.simask |= M860_SIMASK_IRM2; break;
315
  default: return;
316
  }
317
 
318
  return RTEMS_SUCCESSFUL;
319
}
320
 
321
rtems_device_driver canbus_close(
322
  rtems_device_major_number major,
323
  rtems_device_minor_number minor,
324
  void                    * arg
325
)
326
{
327
  /* msg is not in use, rx & txinterrupts are disbled */
328
  candev[minor]->msg15.ctrl0 = 0xff & (I82527_MSG_CTRL_MSGVAL_CLR |
329
                                       I82527_MSG_CTRL_RXIE_CLR |
330
                                       I82527_MSG_CTRL_TXIE_CLR);
331
 
332
  /* Take transceiver off the bus, enable cfg. reg. writes */
333
  candev[minor]->ctrl |= (I82527_CTRL_CCE | I82527_CTRL_INIT);
334
 
335
  return RTEMS_SUCCESSFUL;
336
}
337
 
338
 
339
rtems_device_driver canbus_read(
340
  rtems_device_major_number major,
341
  rtems_device_minor_number minor,
342
  void                    * arg
343
)
344
{
345
  i82527_msg_t *msg;
346
  int i;
347
  int tmpHead;
348
 
349
  msg = arg;
350
  tmpHead = rxMsgBufHead[minor];
351
 
352
  while (1){
353
    if ((tmpHead == rxMsgBufTail[minor]) &&
354
        !(rxMsgBuf[minor][tmpHead].ctrl1 & I82527_MSG_CTRL_NEWDAT)) {
355
      break;
356
    }
357
    if (rxMsgBuf[minor][tmpHead].ctrl1 & I82527_MSG_CTRL_NEWDAT) {
358
      int pkt_len;
359
      msg->ctrl0 = rxMsgBuf[minor][tmpHead].ctrl0;
360
      msg->ctrl1 = rxMsgBuf[minor][tmpHead].ctrl1;
361
      msg->arb = rxMsgBuf[minor][tmpHead].arb;
362
      msg->cfg = rxMsgBuf[minor][tmpHead].cfg;
363
 
364
      pkt_len = (msg->cfg >> 4) & 0xf;
365
      for (i=0; i<pkt_len; i++) {
366
        msg->data[i] = rxMsgBuf[minor][tmpHead].data[i];
367
      }
368
      rxMsgBuf[minor][tmpHead].ctrl1 = 0xff & I82527_MSG_CTRL_NEWDAT_CLR;
369
 
370
      tmpHead++;
371
      if (tmpHead == RX_CAN_BUF_SIZE) {
372
        tmpHead = 0;
373
      }
374
      rxMsgBufHead[minor] = tmpHead;
375
 
376
      return RTEMS_SUCCESSFUL;
377
 
378
    }
379
 
380
    tmpHead++;
381
    if (tmpHead == RX_CAN_BUF_SIZE) {
382
      tmpHead = 0;
383
    }
384
    if (tmpHead == rxMsgBufHead[minor]) {
385
      break;
386
    }
387
  }
388
 
389
  return RTEMS_UNSATISFIED;
390
 
391
}
392
 
393
rtems_device_driver canbus_write(
394
  rtems_device_major_number major,
395
  rtems_device_minor_number minor,
396
  void                    * arg
397
)
398
{
399
  i82527_msg_t *msg;
400
  int i;
401
 
402
  msg = arg;
403
  while(candev[minor]->msg1.ctrl1 & I82527_MSG_CTRL_TXRQ){
404
    continue;
405
  }
406
  candev[minor]->msg1.ctrl1  = 0xff & I82527_MSG_CTRL_CPUUPD_SET;
407
 
408
  candev[minor]->msg1.cfg = msg->cfg;
409
  candev[minor]->msg1.arb = msg->arb;
410
 
411
  for (i=0; i < ((msg->cfg >> 4) & 0xff);  i++) {
412
    candev[minor]->msg1.data[i] = msg->data[i];
413
  }
414
 
415
  candev[minor]->msg1.ctrl0  = 0xff & (I82527_MSG_CTRL_INTPND_CLR |
416
                                       I82527_MSG_CTRL_MSGVAL_SET |
417
                                       I82527_MSG_CTRL_TXIE_CLR);
418
  candev[minor]->msg1.cfg    |= I82527_MSG_CFG_DIR;
419
  candev[minor]->msg1.ctrl1  = 0xff & (I82527_MSG_CTRL_NEWDAT_SET |
420
                                       I82527_MSG_CTRL_CPUUPD_CLR |
421
                                       I82527_MSG_CTRL_TXRQ_SET);
422
 
423
 
424
 
425
  return RTEMS_SUCCESSFUL;
426
}
427
rtems_device_driver canbus_control(
428
  rtems_device_major_number major,
429
  rtems_device_minor_number minor,
430
  void                    * arg
431
)
432
{
433
  return RTEMS_SUCCESSFUL;
434
}
435
 
436
 
437
/* part of old canbus_read */
438
#if 0 
439
  for (i=0; i < RX_CAN_BUF_SIZE) {
440
    if (rxMsgBuf[minor][i].ctrl1 & I82527_MSG_CTRL_NEWDAT)
441
      break;
442
  }
443
 
444
  if (i < RX_CAN_BUF_SIZE) {
445
    int pkt_len;
446
    int j;
447
    msg.arb = rxMsgBuf[minor][i].arb;
448
    msg.cfg = rxMsgBuf[minor][i].cfg;
449
 
450
    pkt_len = (msg.cfg >> 4) & 0xf;
451
 
452
    for (j=0; j < pkt_len; j++)
453
      msg.data[j] = rxMsgBuf[minor][i].data[j];
454
 
455
 
456
  /* wait until there is a msg */
457
  while (!(candev->msg15.ctrl1 & I82527_MSG_CTRL_NEWDAT))
458
     continue;
459
 
460
  msg->ctrl1 = candev->msg15.ctrl1;
461
  msg->cfg = candev->msg15.cfg;
462
  msg->arb = candev->msg15.arb;
463
 
464
  for (i=0; i < ((candev->msg15.cfg >> 4) & 0xff);  i++) {
465
    msg->data[i] = candev->msg15.data[i];
466
  }
467
 
468
  candev->msg15.ctrl0  = 0xff & (I82527_MSG_CTRL_MSGVAL_SET |
469
                                 I82527_MSG_CTRL_INTPND_CLR);
470
  candev->msg15.ctrl1  = 0xff & (I82527_MSG_CTRL_NEWDAT_CLR |
471
                                 I82527_MSG_CTRL_RMTPND_CLR);
472
 
473
  candev->status = 0x0;
474
 
475
 
476
  return RTEMS_SUCCESSFUL;
477
#endif
478
 
479
 

powered by: WebSVN 2.1.0

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