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

Subversion Repositories or1k

[/] [or1k/] [tags/] [rel-0-3-0-rc2/] [or1ksim/] [peripheral/] [generic.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1745 jeremybenn
/* generic.c -- Generic external peripheral
2
 
3
   Copyright (C) 2008 Embecosm Limited
4
 
5
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
6
 
7
   This file is part of OpenRISC 1000 Architectural Simulator.
8
 
9
   This program is free software; you can redistribute it and/or modify it
10
   under the terms of the GNU General Public License as published by the Free
11
   Software Foundation; either version 3 of the License, or (at your option)
12
   any later version.
13
 
14
   This program is distributed in the hope that it will be useful, but WITHOUT
15
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17
   more details.
18
 
19
   You should have received a copy of the GNU General Public License along
20
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
21
 
22 1748 jeremybenn
/* This program is commented throughout in a fashion suitable for processing
23
   with Doxygen. */
24 1745 jeremybenn
 
25
/* This is functional simulation of any external peripheral. It's job is to
26
 * trap accesses in a specific range, so that the simulator can drive an
27
 * external device.
28
 */
29
 
30 1748 jeremybenn
/* Autoconf and/or portability configuration */
31
#include "config.h"
32
 
33
/* System includes */
34 1745 jeremybenn
#include <stdlib.h>
35
#include <stdio.h>
36
 
37 1748 jeremybenn
/* Package includes */
38 1745 jeremybenn
#include "arch.h"
39 1748 jeremybenn
#include "sim-config.h"
40 1745 jeremybenn
#include "abstract.h"
41 1748 jeremybenn
#include "toplevel-support.h"
42
#include "sim-cmd.h"
43 1745 jeremybenn
 
44
 
45 1748 jeremybenn
/*! State associated with the generic device. */
46
struct dev_generic
47
{
48 1745 jeremybenn
 
49 1748 jeremybenn
  /* Info about a particular transaction */
50 1745 jeremybenn
 
51 1748 jeremybenn
  enum
52
  {                             /* Direction of the access */
53
    GENERIC_READ,
54
    GENERIC_WRITE
55
  } trans_direction;
56 1745 jeremybenn
 
57 1748 jeremybenn
  enum
58
  {                             /* Size of the access */
59
    GENERIC_BYTE,
60
    GENERIC_HW,
61
    GENERIC_WORD
62
  } trans_size;
63
 
64
  uint32_t value;               /* The value to read/write */
65
 
66
  /* Configuration */
67
 
68
  int enabled;                  /* Device enabled */
69
  int byte_enabled;             /* Byte R/W allowed */
70
  int hw_enabled;               /* Half word R/W allowed */
71
  int word_enabled;             /* Full word R/W allowed */
72
  char *name;                   /* Name of the device */
73
  oraddr_t baseaddr;            /* Base address of device */
74
  uint32_t size;                /* Address space size (bytes) */
75
 
76
};
77
 
78
 
79 1745 jeremybenn
/* Generic read and write upcall routines. Note the address here is absolute,
80
   not relative to the device. */
81
 
82 1748 jeremybenn
static unsigned long int
83
ext_read (unsigned long int addr, unsigned long int mask)
84 1745 jeremybenn
{
85 1748 jeremybenn
  return config.ext.read_up (config.ext.class_ptr, addr, mask);
86 1745 jeremybenn
 
87 1748 jeremybenn
}                               /* ext_callback() */
88 1745 jeremybenn
 
89
 
90
/* Generic read and write upcall routines. Note the address here is absolute,
91
   not relative to the device. */
92
 
93 1748 jeremybenn
static void
94
ext_write (unsigned long int addr,
95
           unsigned long int mask, unsigned long int value)
96 1745 jeremybenn
{
97 1748 jeremybenn
  config.ext.write_up (config.ext.class_ptr, addr, mask, value);
98 1745 jeremybenn
 
99 1748 jeremybenn
}                               /* ext_callback() */
100 1745 jeremybenn
 
101 1748 jeremybenn
 
102 1745 jeremybenn
/* I/O routines. Note that address is relative to start of address space. */
103
 
104 1748 jeremybenn
static uint8_t
105
generic_read_byte (oraddr_t addr, void *dat)
106 1745 jeremybenn
{
107 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
108 1745 jeremybenn
 
109 1748 jeremybenn
  if (!config.ext.class_ptr)
110
    {
111
      fprintf (stderr, "Byte read from disabled generic device\n");
112
      return 0;
113
    }
114
  else if (addr >= dev->size)
115
    {
116
      fprintf (stderr, "Byte read  out of range for generic device %s "
117
               "(addr %" PRIxADDR ")\n", dev->name, addr);
118
      return 0;
119
    }
120
  else
121
    {
122
      unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr);
123
      unsigned long wordaddr = fulladdr & 0xfffffffc;
124
      unsigned long bitoff = (fulladdr & 0x00000003) << 3;
125 1745 jeremybenn
 
126 1751 jeremybenn
#ifdef OR32_BIG_ENDIAN
127 1748 jeremybenn
      unsigned long mask = 0x000000ff << (24 - bitoff);
128
      unsigned long res = ext_read (wordaddr, mask);
129 1745 jeremybenn
 
130 1748 jeremybenn
      return (uint8_t) ((res >> (24 - bitoff)) & 0x000000ff);
131 1745 jeremybenn
#else
132 1748 jeremybenn
      unsigned long mask = 0x000000ff << bitoff;
133
      unsigned long res = ext_read (wordaddr, mask);
134 1745 jeremybenn
 
135 1748 jeremybenn
      return (uint8_t) ((res >> bitoff) & 0x00000ff);
136
#endif
137
    }
138
}                               /* generic_read_byte() */
139 1745 jeremybenn
 
140
 
141 1748 jeremybenn
static void
142
generic_write_byte (oraddr_t addr, uint8_t value, void *dat)
143 1745 jeremybenn
{
144 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
145 1745 jeremybenn
 
146 1748 jeremybenn
  if (!config.ext.class_ptr)
147
    {
148
      fprintf (stderr, "Byte write to disabled generic device\n");
149
    }
150
  else if (addr >= dev->size)
151
    {
152
      fprintf (stderr, "Byte written out of range for generic device %s "
153
               "(addr %" PRIxADDR ")\n", dev->name, addr);
154
    }
155
  else
156
    {
157
      unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr);
158
      unsigned long wordaddr = fulladdr & 0xfffffffc;
159
      unsigned long bitoff = (fulladdr & 0x00000003) << 3;
160 1745 jeremybenn
 
161 1751 jeremybenn
#ifdef OR32_BIG_ENDIAN
162 1748 jeremybenn
      unsigned long mask = 0x000000ff << (24 - bitoff);
163
      unsigned long wordval = ((unsigned long int) value) << (24 - bitoff);
164 1745 jeremybenn
#else
165 1748 jeremybenn
      unsigned long mask = 0x000000ff << bitoff;
166
      unsigned long wordval = ((unsigned long int) value) << bitoff;
167
#endif
168 1745 jeremybenn
 
169 1748 jeremybenn
      ext_write (wordaddr, mask, wordval);
170
    }
171
}                               /* generic_write_byte() */
172 1745 jeremybenn
 
173
 
174 1748 jeremybenn
static uint16_t
175
generic_read_hw (oraddr_t addr, void *dat)
176 1745 jeremybenn
{
177 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
178 1745 jeremybenn
 
179 1748 jeremybenn
  if (!config.ext.class_ptr)
180
    {
181
      fprintf (stderr, "Half word read from disabled generic device\n");
182
      return 0;
183
    }
184
  else if (addr >= dev->size)
185
    {
186
      fprintf (stderr, "Half-word read  out of range for generic device %s "
187
               "(addr %" PRIxADDR ")\n", dev->name, addr);
188
      return 0;
189
    }
190
  else if (addr & 0x1)
191
    {
192
      fprintf (stderr,
193
               "Unaligned half word read from 0x%" PRIxADDR " ignored\n",
194
               addr);
195
      return 0;
196
    }
197
  else
198
    {
199
      unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr);
200
      unsigned long wordaddr = fulladdr & 0xfffffffc;
201
      unsigned long bitoff = (fulladdr & 0x00000003) << 3;
202 1745 jeremybenn
 
203 1751 jeremybenn
#ifdef OR32_BIG_ENDIAN
204 1748 jeremybenn
      unsigned long mask = 0x0000ffff << (16 - bitoff);
205
      unsigned long res = ext_read (wordaddr, mask);
206 1745 jeremybenn
 
207 1748 jeremybenn
      return (uint16_t) ((res >> (16 - bitoff)) & 0x0000ffff);
208 1745 jeremybenn
#else
209 1748 jeremybenn
      unsigned long mask = 0x0000ffff << bitoff;
210
      unsigned long res = ext_read (wordaddr, mask);
211 1745 jeremybenn
 
212 1748 jeremybenn
      return (uint16_t) ((res >> bitoff) & 0x0000ffff);
213
#endif
214
    }
215
}                               /* generic_read_hw() */
216 1745 jeremybenn
 
217
 
218 1748 jeremybenn
static void
219
generic_write_hw (oraddr_t addr, uint16_t value, void *dat)
220 1745 jeremybenn
{
221 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
222 1745 jeremybenn
 
223 1748 jeremybenn
  if (!config.ext.class_ptr)
224
    {
225
      fprintf (stderr, "Half word write to disabled generic device\n");
226
    }
227
  else if (addr >= dev->size)
228
    {
229
      fprintf (stderr, "Half-word written  out of range for generic device %s "
230
               "(addr %" PRIxADDR ")\n", dev->name, addr);
231
    }
232
  else if (addr & 0x1)
233
    {
234
      fprintf (stderr,
235
               "Unaligned half word write to 0x%" PRIxADDR " ignored\n", addr);
236
    }
237
  else
238
    {
239
      unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr);
240
      unsigned long wordaddr = fulladdr & 0xfffffffc;
241
      unsigned long bitoff = (fulladdr & 0x00000003) << 3;
242 1745 jeremybenn
 
243 1751 jeremybenn
#ifdef OR32_BIG_ENDIAN
244 1748 jeremybenn
      unsigned long mask = 0x0000ffff << (16 - bitoff);
245
      unsigned long wordval = ((unsigned long int) value) << (16 - bitoff);
246 1745 jeremybenn
#else
247 1748 jeremybenn
      unsigned long mask = 0x0000ffff << bitoff;
248
      unsigned long wordval = ((unsigned long int) value) << bitoff;
249
#endif
250 1745 jeremybenn
 
251 1748 jeremybenn
      ext_write (wordaddr, mask, wordval);
252
    }
253
}                               /* generic_write_hw() */
254 1745 jeremybenn
 
255
 
256 1748 jeremybenn
static uint32_t
257
generic_read_word (oraddr_t addr, void *dat)
258 1745 jeremybenn
{
259 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
260 1745 jeremybenn
 
261 1748 jeremybenn
  if (!config.ext.class_ptr)
262
    {
263
      fprintf (stderr, "Full word read from disabled generic device\n");
264
      return 0;
265
    }
266
  else if (addr >= dev->size)
267
    {
268
      fprintf (stderr, "Full word read  out of range for generic device %s "
269
               "(addr %" PRIxADDR ")\n", dev->name, addr);
270
      return 0;
271
    }
272
  else if (0 != (addr & 0x3))
273
    {
274
      fprintf (stderr,
275
               "Unaligned full word read from 0x%" PRIxADDR " ignored\n",
276
               addr);
277
      return 0;
278
    }
279
  else
280
    {
281
      unsigned long wordaddr = (unsigned long int) (addr + dev->baseaddr);
282 1745 jeremybenn
 
283 1748 jeremybenn
      return (uint32_t) ext_read (wordaddr, 0xffffffff);
284
    }
285
}                               /* generic_read_word() */
286 1745 jeremybenn
 
287
 
288 1748 jeremybenn
static void
289
generic_write_word (oraddr_t addr, uint32_t value, void *dat)
290 1745 jeremybenn
{
291 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
292 1745 jeremybenn
 
293 1748 jeremybenn
  if (!config.ext.class_ptr)
294
    {
295
      fprintf (stderr, "Full word write to disabled generic device\n");
296
    }
297
  else if (addr >= dev->size)
298
    {
299
      fprintf (stderr, "Full word written  out of range for generic device %s "
300
               "(addr %" PRIxADDR ")\n", dev->name, addr);
301
    }
302
  else if (0 != (addr & 0x3))
303
    {
304
      fprintf (stderr,
305
               "Unaligned full word write to 0x%" PRIxADDR " ignored\n", addr);
306
    }
307
  else
308
    {
309
      unsigned long wordaddr = (unsigned long int) (addr + dev->baseaddr);
310 1745 jeremybenn
 
311 1748 jeremybenn
      ext_write (wordaddr, 0xffffffff, value);
312
    }
313
}                               /* generic_write_word() */
314 1745 jeremybenn
 
315
 
316
/* Reset is a null operation */
317
 
318 1748 jeremybenn
static void
319
generic_reset (void *dat)
320 1745 jeremybenn
{
321
  return;
322
 
323 1748 jeremybenn
}                               /* generic_reset() */
324 1745 jeremybenn
 
325
 
326
/* Status report can only advise of configuration. */
327
 
328 1748 jeremybenn
static void
329
generic_status (void *dat)
330 1745 jeremybenn
{
331 1748 jeremybenn
  struct dev_generic *dev = (struct dev_generic *) dat;
332 1745 jeremybenn
 
333 1748 jeremybenn
  PRINTF ("\nGeneric device \"%s\" at 0x%" PRIxADDR ":\n", dev->name,
334
          dev->baseaddr);
335
  PRINTF ("  Size 0x%" PRIx32 "\n", dev->size);
336 1745 jeremybenn
 
337 1748 jeremybenn
  if (dev->byte_enabled)
338
    {
339
      PRINTF ("  Byte R/W enabled\n");
340
    }
341 1745 jeremybenn
 
342 1748 jeremybenn
  if (dev->hw_enabled)
343
    {
344
      PRINTF ("  Half word R/W enabled\n");
345
    }
346 1745 jeremybenn
 
347 1748 jeremybenn
  if (dev->word_enabled)
348
    {
349
      PRINTF ("  Full word R/W enabled\n");
350
    }
351 1745 jeremybenn
 
352 1748 jeremybenn
  PRINTF ("\n");
353 1745 jeremybenn
 
354 1748 jeremybenn
}                               /* generic_status() */
355 1745 jeremybenn
 
356
 
357
/* Functions to set configuration */
358
 
359 1748 jeremybenn
static void
360
generic_enabled (union param_val val, void *dat)
361 1745 jeremybenn
{
362 1748 jeremybenn
  ((struct dev_generic *) dat)->enabled = val.int_val;
363 1745 jeremybenn
 
364 1748 jeremybenn
}                               /* generic_enabled() */
365 1745 jeremybenn
 
366
 
367 1748 jeremybenn
static void
368
generic_byte_enabled (union param_val val, void *dat)
369 1745 jeremybenn
{
370 1748 jeremybenn
  ((struct dev_generic *) dat)->byte_enabled = val.int_val;
371 1745 jeremybenn
 
372 1748 jeremybenn
}                               /* generic_byte_enabled() */
373 1745 jeremybenn
 
374
 
375 1748 jeremybenn
static void
376
generic_hw_enabled (union param_val val, void *dat)
377 1745 jeremybenn
{
378 1748 jeremybenn
  ((struct dev_generic *) dat)->hw_enabled = val.int_val;
379 1745 jeremybenn
 
380 1748 jeremybenn
}                               /* generic_hw_enabled() */
381 1745 jeremybenn
 
382
 
383 1748 jeremybenn
static void
384
generic_word_enabled (union param_val val, void *dat)
385 1745 jeremybenn
{
386 1748 jeremybenn
  ((struct dev_generic *) dat)->word_enabled = val.int_val;
387 1745 jeremybenn
 
388 1748 jeremybenn
}                               /* generic_word_enabled() */
389 1745 jeremybenn
 
390
 
391 1748 jeremybenn
static void
392
generic_name (union param_val val, void *dat)
393 1745 jeremybenn
{
394 1748 jeremybenn
  ((struct dev_generic *) dat)->name = strdup (val.str_val);
395 1745 jeremybenn
 
396 1748 jeremybenn
  if (!((struct dev_generic *) dat)->name)
397
    {
398
      fprintf (stderr, "Peripheral 16450: name \"%s\": Run out of memory\n",
399
               val.str_val);
400
      exit (-1);
401
    }
402
}                               /* generic_name() */
403 1745 jeremybenn
 
404
 
405 1748 jeremybenn
static void
406
generic_baseaddr (union param_val val, void *dat)
407 1745 jeremybenn
{
408 1748 jeremybenn
  ((struct dev_generic *) dat)->baseaddr = val.addr_val;
409 1745 jeremybenn
 
410 1748 jeremybenn
}                               /* generic_baseaddr() */
411 1745 jeremybenn
 
412
 
413 1748 jeremybenn
static void
414
generic_size (union param_val val, void *dat)
415 1745 jeremybenn
{
416 1748 jeremybenn
  ((struct dev_generic *) dat)->size = val.int_val;
417 1745 jeremybenn
 
418 1748 jeremybenn
}                               /* generic_size() */
419 1745 jeremybenn
 
420
 
421
/* Start of new generic section */
422
 
423 1748 jeremybenn
static void *
424
generic_sec_start ()
425 1745 jeremybenn
{
426
  struct dev_generic *new =
427 1748 jeremybenn
    (struct dev_generic *) malloc (sizeof (struct dev_generic));
428 1745 jeremybenn
 
429 1748 jeremybenn
  if (0 == new)
430
    {
431
      fprintf (stderr, "Generic peripheral: Run out of memory\n");
432
      exit (-1);
433
    }
434 1745 jeremybenn
 
435
  /* Default names */
436
 
437 1748 jeremybenn
  new->enabled = 1;
438 1745 jeremybenn
  new->byte_enabled = 1;
439 1748 jeremybenn
  new->hw_enabled = 1;
440 1745 jeremybenn
  new->word_enabled = 1;
441 1748 jeremybenn
  new->name = "anonymous external peripheral";
442
  new->baseaddr = 0;
443
  new->size = 0;
444 1745 jeremybenn
 
445 1748 jeremybenn
  return new;
446 1745 jeremybenn
 
447 1748 jeremybenn
}                               /* generic_sec_start() */
448 1745 jeremybenn
 
449
 
450
/* End of new generic section */
451
 
452 1748 jeremybenn
static void
453
generic_sec_end (void *dat)
454 1745 jeremybenn
{
455 1748 jeremybenn
  struct dev_generic *generic = (struct dev_generic *) dat;
456
  struct mem_ops ops;
457 1745 jeremybenn
 
458
  /* Give up if not enabled, or if size is zero, or if no access size is
459
     enabled. */
460
 
461 1748 jeremybenn
  if (!generic->enabled)
462
    {
463
      free (dat);
464
      return;
465
    }
466 1745 jeremybenn
 
467 1748 jeremybenn
  if (0 == generic->size)
468
    {
469
      fprintf (stderr, "Generic peripheral \"%s\" has size 0: ignoring",
470
               generic->name);
471
      free (dat);
472
      return;
473
    }
474 1745 jeremybenn
 
475 1748 jeremybenn
  if (!generic->byte_enabled &&
476
      !generic->hw_enabled && !generic->word_enabled)
477
    {
478
      fprintf (stderr, "Generic peripheral \"%s\" has no access: ignoring",
479
               generic->name);
480
      free (dat);
481
      return;
482
    }
483 1745 jeremybenn
 
484
  /* Zero all the ops, then set the ones we care about. Read/write delays will
485
   * come from the peripheral if desired.
486
   */
487
 
488 1748 jeremybenn
  memset (&ops, 0, sizeof (struct mem_ops));
489 1745 jeremybenn
 
490 1748 jeremybenn
  if (generic->byte_enabled)
491
    {
492
      ops.readfunc8 = generic_read_byte;
493
      ops.writefunc8 = generic_write_byte;
494
      ops.read_dat8 = dat;
495
      ops.write_dat8 = dat;
496
    }
497 1745 jeremybenn
 
498 1748 jeremybenn
  if (generic->hw_enabled)
499
    {
500
      ops.readfunc16 = generic_read_hw;
501
      ops.writefunc16 = generic_write_hw;
502
      ops.read_dat16 = dat;
503
      ops.write_dat16 = dat;
504
    }
505 1745 jeremybenn
 
506 1748 jeremybenn
  if (generic->word_enabled)
507
    {
508
      ops.readfunc32 = generic_read_word;
509
      ops.writefunc32 = generic_write_word;
510
      ops.read_dat32 = dat;
511
      ops.write_dat32 = dat;
512
    }
513 1745 jeremybenn
 
514
  /* Register everything */
515
 
516 1748 jeremybenn
  reg_mem_area (generic->baseaddr, generic->size, 0, &ops);
517 1745 jeremybenn
 
518 1748 jeremybenn
  reg_sim_reset (generic_reset, dat);
519
  reg_sim_stat (generic_status, dat);
520 1745 jeremybenn
 
521 1748 jeremybenn
}                               /* generic_sec_end() */
522 1745 jeremybenn
 
523
 
524
/* Register a generic section. */
525
 
526 1748 jeremybenn
void
527
reg_generic_sec (void)
528 1745 jeremybenn
{
529 1748 jeremybenn
  struct config_section *sec = reg_config_sec ("generic",
530 1745 jeremybenn
                                               generic_sec_start,
531 1748 jeremybenn
                                               generic_sec_end);
532 1745 jeremybenn
 
533 1748 jeremybenn
  reg_config_param (sec, "enabled", paramt_int, generic_enabled);
534
  reg_config_param (sec, "byte_enabled", paramt_int, generic_byte_enabled);
535
  reg_config_param (sec, "hw_enabled", paramt_int, generic_hw_enabled);
536
  reg_config_param (sec, "word_enabled", paramt_int, generic_word_enabled);
537
  reg_config_param (sec, "name", paramt_str, generic_name);
538
  reg_config_param (sec, "baseaddr", paramt_addr, generic_baseaddr);
539
  reg_config_param (sec, "size", paramt_int, generic_size);
540 1745 jeremybenn
 
541 1748 jeremybenn
}                               /* reg_generic_sec */

powered by: WebSVN 2.1.0

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