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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [generic.c] - Blame information for rev 19

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

Line No. Rev Author Line
1 19 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
/* This program is commented throughout in a fashion suitable for processing
23
   with Doxygen. */
24
 
25
 
26
/* This is functional simulation of any external peripheral. It's job is to
27
 * trap accesses in a specific range, so that the simulator can drive an
28
 * external device.
29
 *
30
 * A note on endianess. All external communication is done using HOST
31
 * endianess. A set of functions are provided to convert between host and
32
 * model endianess (htoml, htoms, mtohl, mtohs).
33
 */
34
 
35
/* Autoconf and/or portability configuration */
36
#include "config.h"
37
 
38
/* System includes */
39
#include <stdlib.h>
40
#include <stdio.h>
41
 
42
/* Package includes */
43
#include "arch.h"
44
#include "sim-config.h"
45
#include "abstract.h"
46
#include "toplevel-support.h"
47
#include "sim-cmd.h"
48
 
49
 
50
/*! State associated with the generic device. */
51
struct dev_generic
52
{
53
 
54
  /* Info about a particular transaction */
55
 
56
  enum
57
  {                             /* Direction of the access */
58
    GENERIC_READ,
59
    GENERIC_WRITE
60
  } trans_direction;
61
 
62
  enum
63
  {                             /* Size of the access */
64
    GENERIC_BYTE,
65
    GENERIC_HW,
66
    GENERIC_WORD
67
  } trans_size;
68
 
69
  uint32_t value;               /* The value to read/write */
70
 
71
  /* Configuration */
72
 
73
  int enabled;                  /* Device enabled */
74
  int byte_enabled;             /* Byte R/W allowed */
75
  int hw_enabled;               /* Half word R/W allowed */
76
  int word_enabled;             /* Full word R/W allowed */
77
  char *name;                   /* Name of the device */
78
  oraddr_t baseaddr;            /* Base address of device */
79
  uint32_t size;                /* Address space size (bytes) */
80
 
81
};
82
 
83
 
84
/* Convert a 32-bit value from host to model endianess */
85
static unsigned long int
86
htoml (unsigned long int  host_val)
87
{
88
  unsigned char  model_array[4];
89
 
90
#ifdef OR32_BIG_ENDIAN
91
  model_array[0] = (host_val >> 24) & 0xff;
92
  model_array[1] = (host_val >> 16) & 0xff;
93
  model_array[2] = (host_val >>  8) & 0xff;
94
  model_array[3] = (host_val      ) & 0xff;
95
#else
96
  model_array[0] = (host_val      ) & 0xff;
97
  model_array[1] = (host_val >>  8) & 0xff;
98
  model_array[2] = (host_val >> 16) & 0xff;
99
  model_array[3] = (host_val >> 24) & 0xff;
100
#endif
101
 
102
  return *((unsigned long int *)model_array);
103
 
104
}       /* htoml () */
105
 
106
 
107
/* Convert a 16-bit value from host to model endianess */
108
static unsigned short int
109
htoms (unsigned short int  host_val)
110
{
111
  unsigned char  model_array[2];
112
 
113
#ifdef OR32_BIG_ENDIAN
114
  model_array[0] = (host_val >>  8) & 0xff;
115
  model_array[1] = (host_val      ) & 0xff;
116
#else
117
  model_array[0] = (host_val      ) & 0xff;
118
  model_array[1] = (host_val >>  8) & 0xff;
119
#endif
120
 
121
  return *((unsigned short int *)model_array);
122
 
123
}       /* htoms () */
124
 
125
 
126
/* Convert a 32-bit value from model to host endianess */
127
static unsigned long int
128
mtohl (unsigned long int  model_val)
129
{
130
  unsigned char     *model_array = (unsigned char *)(&model_val);
131
  unsigned long int  host_val;
132
 
133
#ifdef OR32_BIG_ENDIAN
134
  host_val =                   model_array[0];
135
  host_val = (host_val << 8) | model_array[1];
136
  host_val = (host_val << 8) | model_array[2];
137
  host_val = (host_val << 8) | model_array[3];
138
#else
139
  host_val =                   model_array[3];
140
  host_val = (host_val << 8) | model_array[2];
141
  host_val = (host_val << 8) | model_array[1];
142
  host_val = (host_val << 8) | model_array[0];
143
#endif
144
 
145
  return  host_val;
146
 
147
}       /* mtohl () */
148
 
149
 
150
/* Convert a 32-bit value from model to host endianess */
151
static unsigned short int
152
mtohs (unsigned short int  model_val)
153
{
154
  unsigned char      *model_array = (unsigned char *)(&model_val);
155
  unsigned short int  host_val;
156
 
157
#ifdef OR32_BIG_ENDIAN
158
  host_val =                   model_array[0];
159
  host_val = (host_val << 8) | model_array[1];
160
#else
161
  host_val =                   model_array[1];
162
  host_val = (host_val << 8) | model_array[0];
163
#endif
164
 
165
  return  host_val;
166
 
167
}       /* mtohs () */
168
 
169
 
170
/* Generic read and write upcall routines. Note the address here is absolute,
171
   not relative to the device. The mask uses host endianess, not Or1ksim
172
   endianess. */
173
 
174
static unsigned long int
175
ext_read (unsigned long int  addr,
176
          unsigned long int  mask)
177
{
178
  return config.ext.read_up (config.ext.class_ptr, addr, mask);
179
 
180
}                               /* ext_callback() */
181
 
182
 
183
/* Generic read and write upcall routines. Note the address here is absolute,
184
   not relative to the device. The mask and value use host endianess, not
185
   Or1ksim endianess. */
186
 
187
static void
188
ext_write (unsigned long int  addr,
189
           unsigned long int  mask,
190
           unsigned long int  value)
191
{
192
  config.ext.write_up (config.ext.class_ptr, addr, mask, value);
193
 
194
}                               /* ext_callback() */
195
 
196
 
197
/* I/O routines. Note that address is relative to start of address space. */
198
 
199
static uint8_t
200
generic_read_byte (oraddr_t addr, void *dat)
201
{
202
  struct dev_generic *dev = (struct dev_generic *) dat;
203
 
204
  if (!config.ext.class_ptr)
205
    {
206
      fprintf (stderr, "Byte read from disabled generic device\n");
207
      return 0;
208
    }
209
  else if (addr >= dev->size)
210
    {
211
      fprintf (stderr, "Byte read  out of range for generic device %s "
212
               "(addr %" PRIxADDR ")\n", dev->name, addr);
213
      return 0;
214
    }
215
  else
216
    {
217
      unsigned long  fulladdr = (unsigned long int) (addr + dev->baseaddr);
218
      unsigned long  wordaddr = fulladdr & 0xfffffffc;
219
      unsigned long  bytenum  = fulladdr & 0x00000003;
220
 
221
      uint8_t        mask_array[4];
222
      unsigned long  res;
223
      uint8_t       *res_array;
224
 
225
      /* This works whatever the host endianess */
226
      memset (mask_array, 0, 4);
227
      mask_array[bytenum] = 0xff;
228
 
229
      res       = ext_read (wordaddr, *((unsigned int *)mask_array));
230
      res_array = (uint8_t *)(&res);
231
 
232
      return  res_array[bytenum];
233
    }
234
}                               /* generic_read_byte() */
235
 
236
 
237
static void
238
generic_write_byte (oraddr_t addr, uint8_t value, void *dat)
239
{
240
  struct dev_generic *dev = (struct dev_generic *) dat;
241
 
242
  if (!config.ext.class_ptr)
243
    {
244
      fprintf (stderr, "Byte write to disabled generic device\n");
245
    }
246
  else if (addr >= dev->size)
247
    {
248
      fprintf (stderr, "Byte written out of range for generic device %s "
249
               "(addr %" PRIxADDR ")\n", dev->name, addr);
250
    }
251
  else
252
    {
253
      unsigned long  fulladdr = (unsigned long int) (addr + dev->baseaddr);
254
      unsigned long  wordaddr = fulladdr & 0xfffffffc;
255
 
256
      unsigned long  bytenum  = fulladdr & 0x00000003;
257
      uint8_t        mask_array[4];
258
      uint8_t        value_array[4];
259
 
260
      /* This works whatever the host endianess */
261
      memset (mask_array, 0, 4);
262
      mask_array[bytenum] = 0xff;
263
      memset (value_array, 0, 4);
264
      value_array[bytenum] = value;
265
 
266
      ext_write (wordaddr, *((unsigned long int *)mask_array),
267
                 *((unsigned long int *)value_array));
268
    }
269
}                               /* generic_write_byte() */
270
 
271
 
272
/* Result is in model endianess */
273
static uint16_t
274
generic_read_hw (oraddr_t addr, void *dat)
275
{
276
  struct dev_generic *dev = (struct dev_generic *) dat;
277
 
278
  if (!config.ext.class_ptr)
279
    {
280
      fprintf (stderr, "Half word read from disabled generic device\n");
281
      return 0;
282
    }
283
  else if (addr >= dev->size)
284
    {
285
      fprintf (stderr, "Half-word read  out of range for generic device %s "
286
               "(addr %" PRIxADDR ")\n", dev->name, addr);
287
      return 0;
288
    }
289
  else if (addr & 0x1)
290
    {
291
      fprintf (stderr,
292
               "Unaligned half word read from 0x%" PRIxADDR " ignored\n",
293
               addr);
294
      return 0;
295
    }
296
  else
297
    {
298
      unsigned long   fulladdr = (unsigned long int) (addr + dev->baseaddr);
299
      unsigned long   wordaddr = fulladdr & 0xfffffffc;
300
      unsigned long   bytenum  = fulladdr & 0x00000002;
301
 
302
      uint8_t         mask_array[4];
303
      unsigned long   res;
304
      uint8_t        *res_array;
305
      uint8_t         hwres_array[2];
306
 
307
      /* This works whatever the host endianess */
308
      memset (mask_array, 0, 4);
309
      mask_array[bytenum]     = 0xff;
310
      mask_array[bytenum + 1] = 0xff;
311
 
312
      res       = ext_read (wordaddr, *((unsigned int *)mask_array));
313
      res_array = (uint8_t *)(&res);
314
 
315
      hwres_array[0] = res_array[bytenum];
316
      hwres_array[1] = res_array[bytenum + 1];
317
 
318
      return htoms (*((uint16_t *)hwres_array));
319
    }
320
}                               /* generic_read_hw() */
321
 
322
 
323
/* Value is in model endianness */
324
static void
325
generic_write_hw (oraddr_t addr, uint16_t value, void *dat)
326
{
327
  struct dev_generic *dev = (struct dev_generic *) dat;
328
 
329
  if (!config.ext.class_ptr)
330
    {
331
      fprintf (stderr, "Half word write to disabled generic device\n");
332
    }
333
  else if (addr >= dev->size)
334
    {
335
      fprintf (stderr, "Half-word written  out of range for generic device %s "
336
               "(addr %" PRIxADDR ")\n", dev->name, addr);
337
    }
338
  else if (addr & 0x1)
339
    {
340
      fprintf (stderr,
341
               "Unaligned half word write to 0x%" PRIxADDR " ignored\n", addr);
342
    }
343
  else
344
    {
345
      uint16_t       host_value = mtohs (value);
346
 
347
      unsigned long  fulladdr = (unsigned long int) (addr + dev->baseaddr);
348
      unsigned long  wordaddr = fulladdr & 0xfffffffc;
349
      unsigned long  bytenum  = fulladdr & 0x00000002;
350
 
351
      uint8_t        mask_array[4];
352
      uint8_t        value_array[4];
353
      uint8_t       *hw_value_array;
354
 
355
      /* This works whatever the host endianess */
356
      memset (mask_array, 0, 4);
357
      mask_array[bytenum]     = 0xff;
358
      mask_array[bytenum + 1] = 0xff;
359
 
360
      memset (value_array, 0, 4);
361
      hw_value_array           = (uint8_t *)(&host_value);
362
      value_array[bytenum]     = hw_value_array[0];
363
      value_array[bytenum + 1] = hw_value_array[1];
364
 
365
      ext_write (wordaddr, *((unsigned long int *)mask_array),
366
                 *((unsigned long int *)value_array));
367
    }
368
}                               /* generic_write_hw() */
369
 
370
 
371
static uint32_t
372
generic_read_word (oraddr_t addr, void *dat)
373
{
374
  struct dev_generic *dev = (struct dev_generic *) dat;
375
 
376
  if (!config.ext.class_ptr)
377
    {
378
      fprintf (stderr, "Full word read from disabled generic device\n");
379
      return 0;
380
    }
381
  else if (addr >= dev->size)
382
    {
383
      fprintf (stderr, "Full word read  out of range for generic device %s "
384
               "(addr %" PRIxADDR ")\n", dev->name, addr);
385
      return 0;
386
    }
387
  else if (0 != (addr & 0x3))
388
    {
389
      fprintf (stderr,
390
               "Unaligned full word read from 0x%" PRIxADDR " ignored\n",
391
               addr);
392
      return 0;
393
    }
394
  else
395
    {
396
      unsigned long wordaddr = (unsigned long int) (addr + dev->baseaddr);
397
 
398
      return (uint32_t) htoml (ext_read (wordaddr, 0xffffffff));
399
    }
400
}                               /* generic_read_word() */
401
 
402
 
403
static void
404
generic_write_word (oraddr_t addr, uint32_t value, void *dat)
405
{
406
  struct dev_generic *dev = (struct dev_generic *) dat;
407
 
408
  if (!config.ext.class_ptr)
409
    {
410
      fprintf (stderr, "Full word write to disabled generic device\n");
411
    }
412
  else if (addr >= dev->size)
413
    {
414
      fprintf (stderr, "Full word written  out of range for generic device %s "
415
               "(addr %" PRIxADDR ")\n", dev->name, addr);
416
    }
417
  else if (0 != (addr & 0x3))
418
    {
419
      fprintf (stderr,
420
               "Unaligned full word write to 0x%" PRIxADDR " ignored\n", addr);
421
    }
422
  else
423
    {
424
      unsigned long host_value = mtohl (value);
425
      unsigned long wordaddr   = (unsigned long int) (addr + dev->baseaddr);
426
 
427
      ext_write (wordaddr, 0xffffffff, host_value);
428
    }
429
}                               /* generic_write_word() */
430
 
431
 
432
/* Reset is a null operation */
433
 
434
static void
435
generic_reset (void *dat)
436
{
437
  return;
438
 
439
}                               /* generic_reset() */
440
 
441
 
442
/* Status report can only advise of configuration. */
443
 
444
static void
445
generic_status (void *dat)
446
{
447
  struct dev_generic *dev = (struct dev_generic *) dat;
448
 
449
  PRINTF ("\nGeneric device \"%s\" at 0x%" PRIxADDR ":\n", dev->name,
450
          dev->baseaddr);
451
  PRINTF ("  Size 0x%" PRIx32 "\n", dev->size);
452
 
453
  if (dev->byte_enabled)
454
    {
455
      PRINTF ("  Byte R/W enabled\n");
456
    }
457
 
458
  if (dev->hw_enabled)
459
    {
460
      PRINTF ("  Half word R/W enabled\n");
461
    }
462
 
463
  if (dev->word_enabled)
464
    {
465
      PRINTF ("  Full word R/W enabled\n");
466
    }
467
 
468
  PRINTF ("\n");
469
 
470
}                               /* generic_status() */
471
 
472
 
473
/* Functions to set configuration */
474
 
475
static void
476
generic_enabled (union param_val val, void *dat)
477
{
478
  ((struct dev_generic *) dat)->enabled = val.int_val;
479
 
480
}                               /* generic_enabled() */
481
 
482
 
483
static void
484
generic_byte_enabled (union param_val val, void *dat)
485
{
486
  ((struct dev_generic *) dat)->byte_enabled = val.int_val;
487
 
488
}                               /* generic_byte_enabled() */
489
 
490
 
491
static void
492
generic_hw_enabled (union param_val val, void *dat)
493
{
494
  ((struct dev_generic *) dat)->hw_enabled = val.int_val;
495
 
496
}                               /* generic_hw_enabled() */
497
 
498
 
499
static void
500
generic_word_enabled (union param_val val, void *dat)
501
{
502
  ((struct dev_generic *) dat)->word_enabled = val.int_val;
503
 
504
}                               /* generic_word_enabled() */
505
 
506
 
507
static void
508
generic_name (union param_val val, void *dat)
509
{
510
  ((struct dev_generic *) dat)->name = strdup (val.str_val);
511
 
512
  if (!((struct dev_generic *) dat)->name)
513
    {
514
      fprintf (stderr, "Peripheral 16450: name \"%s\": Run out of memory\n",
515
               val.str_val);
516
      exit (-1);
517
    }
518
}                               /* generic_name() */
519
 
520
 
521
static void
522
generic_baseaddr (union param_val val, void *dat)
523
{
524
  ((struct dev_generic *) dat)->baseaddr = val.addr_val;
525
 
526
}                               /* generic_baseaddr() */
527
 
528
 
529
static void
530
generic_size (union param_val val, void *dat)
531
{
532
  ((struct dev_generic *) dat)->size = val.int_val;
533
 
534
}                               /* generic_size() */
535
 
536
 
537
/* Start of new generic section */
538
 
539
static void *
540
generic_sec_start ()
541
{
542
  struct dev_generic *new =
543
    (struct dev_generic *) malloc (sizeof (struct dev_generic));
544
 
545
  if (0 == new)
546
    {
547
      fprintf (stderr, "Generic peripheral: Run out of memory\n");
548
      exit (-1);
549
    }
550
 
551
  /* Default names */
552
 
553
  new->enabled = 1;
554
  new->byte_enabled = 1;
555
  new->hw_enabled = 1;
556
  new->word_enabled = 1;
557
  new->name = "anonymous external peripheral";
558
  new->baseaddr = 0;
559
  new->size = 0;
560
 
561
  return new;
562
 
563
}                               /* generic_sec_start() */
564
 
565
 
566
/* End of new generic section */
567
 
568
static void
569
generic_sec_end (void *dat)
570
{
571
  struct dev_generic *generic = (struct dev_generic *) dat;
572
  struct mem_ops ops;
573
 
574
  /* Give up if not enabled, or if size is zero, or if no access size is
575
     enabled. */
576
 
577
  if (!generic->enabled)
578
    {
579
      free (dat);
580
      return;
581
    }
582
 
583
  if (0 == generic->size)
584
    {
585
      fprintf (stderr, "Generic peripheral \"%s\" has size 0: ignoring",
586
               generic->name);
587
      free (dat);
588
      return;
589
    }
590
 
591
  if (!generic->byte_enabled &&
592
      !generic->hw_enabled && !generic->word_enabled)
593
    {
594
      fprintf (stderr, "Generic peripheral \"%s\" has no access: ignoring",
595
               generic->name);
596
      free (dat);
597
      return;
598
    }
599
 
600
  /* Zero all the ops, then set the ones we care about. Read/write delays will
601
   * come from the peripheral if desired.
602
   */
603
 
604
  memset (&ops, 0, sizeof (struct mem_ops));
605
 
606
  if (generic->byte_enabled)
607
    {
608
      ops.readfunc8 = generic_read_byte;
609
      ops.writefunc8 = generic_write_byte;
610
      ops.read_dat8 = dat;
611
      ops.write_dat8 = dat;
612
    }
613
 
614
  if (generic->hw_enabled)
615
    {
616
      ops.readfunc16 = generic_read_hw;
617
      ops.writefunc16 = generic_write_hw;
618
      ops.read_dat16 = dat;
619
      ops.write_dat16 = dat;
620
    }
621
 
622
  if (generic->word_enabled)
623
    {
624
      ops.readfunc32 = generic_read_word;
625
      ops.writefunc32 = generic_write_word;
626
      ops.read_dat32 = dat;
627
      ops.write_dat32 = dat;
628
    }
629
 
630
  /* Register everything */
631
 
632
  reg_mem_area (generic->baseaddr, generic->size, 0, &ops);
633
 
634
  reg_sim_reset (generic_reset, dat);
635
  reg_sim_stat (generic_status, dat);
636
 
637
}                               /* generic_sec_end() */
638
 
639
 
640
/* Register a generic section. */
641
 
642
void
643
reg_generic_sec (void)
644
{
645
  struct config_section *sec = reg_config_sec ("generic",
646
                                               generic_sec_start,
647
                                               generic_sec_end);
648
 
649
  reg_config_param (sec, "enabled", paramt_int, generic_enabled);
650
  reg_config_param (sec, "byte_enabled", paramt_int, generic_byte_enabled);
651
  reg_config_param (sec, "hw_enabled", paramt_int, generic_hw_enabled);
652
  reg_config_param (sec, "word_enabled", paramt_int, generic_word_enabled);
653
  reg_config_param (sec, "name", paramt_str, generic_name);
654
  reg_config_param (sec, "baseaddr", paramt_addr, generic_baseaddr);
655
  reg_config_param (sec, "size", paramt_int, generic_size);
656
 
657
}                               /* reg_generic_sec */

powered by: WebSVN 2.1.0

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