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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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