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

Subversion Repositories or1k

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

Go to most recent revision | 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
 
23
/* This is functional simulation of any external peripheral. It's job is to
24
 * trap accesses in a specific range, so that the simulator can drive an
25
 * external device.
26
 */
27
 
28
#include <stdlib.h>
29
#include <stdio.h>
30
#include <string.h>
31
 
32
#include "config.h"
33
 
34
#ifdef HAVE_INTTYPES_H
35
#include <inttypes.h>
36
#endif
37
 
38
#include "or1ksim.h"
39
#include "port.h"
40
#include "arch.h"
41
#include "abstract.h"
42
#include "sim-config.h"
43
#include "pic.h"
44
#include "vapi.h"
45
#include "sched.h"
46
#include "channel.h"
47
#include "debug.h"
48
 
49
#include "generic.h"
50
 
51
 
52
DEFAULT_DEBUG_CHANNEL( generic );
53
 
54
 
55
/* Generic read and write upcall routines. Note the address here is absolute,
56
   not relative to the device. */
57
 
58
static unsigned long int  ext_read( unsigned long int  addr,
59
                                    unsigned long int  mask )
60
{
61
  return config.ext.read_up( config.ext.class_ptr, addr, mask );
62
 
63
}       /* ext_callback() */
64
 
65
 
66
/* Generic read and write upcall routines. Note the address here is absolute,
67
   not relative to the device. */
68
 
69
static void  ext_write( unsigned long int  addr,
70
                        unsigned long int  mask,
71
                        unsigned long int  value )
72
{
73
  config.ext.write_up( config.ext.class_ptr, addr, mask, value );
74
 
75
}       /* ext_callback() */
76
 
77
 
78
/* I/O routines. Note that address is relative to start of address space. */
79
 
80
static uint8_t  generic_read_byte( oraddr_t  addr,
81
                                   void     *dat )
82
{
83
  struct dev_generic *dev = (struct dev_generic *)dat;
84
 
85
  if( !config.ext.class_ptr ) {
86
    fprintf( stderr, "Byte read from disabled generic device\n" );
87
    return 0;
88
  }
89
  else if( addr >= dev->size ) {
90
    TRACE( "Generic device \"%s\": Byte read out of range (addr %"
91
           PRIxADDR ")\n", dev->name, addr );
92
    return 0;
93
  }
94
  else {
95
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
96
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
97
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
98
 
99
#ifdef WORDS_BIGENDIAN
100
    unsigned long  mask     = 0x000000ff << (24 - bitoff);
101
    unsigned long  res      = ext_read( wordaddr, mask );
102
 
103
    return (uint8_t)((res >> (24 - bitoff)) & 0x000000ff);
104
#else
105
    unsigned long  mask     = 0x000000ff << bitoff;
106
    unsigned long  res      = ext_read( wordaddr, mask );
107
 
108
    return (uint8_t)((res >> bitoff) & 0x00000ff);
109
#endif      
110
  }
111
}       /* generic_read_byte() */
112
 
113
 
114
static void  generic_write_byte( oraddr_t  addr,
115
                                 uint8_t   value,
116
                                 void     *dat )
117
{
118
  struct dev_generic *dev = (struct dev_generic *)dat;
119
 
120
  if( !config.ext.class_ptr ) {
121
    fprintf( stderr, "Byte write to disabled generic device\n" );
122
  }
123
  else if( addr >= dev->size ) {
124
    TRACE( "Generic device \"%s\": Byte write out of range (addr %"
125
           PRIxADDR ")\n", dev->name, addr );
126
  }
127
  else {
128
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
129
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
130
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
131
 
132
#ifdef WORDS_BIGENDIAN
133
    unsigned long  mask     = 0x000000ff << (24 - bitoff);
134
    unsigned long  wordval  = ((unsigned long int)value) << (24 - bitoff);
135
#else
136
    unsigned long  mask     = 0x000000ff << bitoff;
137
    unsigned long  wordval  = ((unsigned long int)value) << bitoff;
138
#endif      
139
 
140
    ext_write( wordaddr, mask, wordval );
141
  }
142
}       /* generic_write_byte() */
143
 
144
 
145
static uint16_t  generic_read_hw( oraddr_t  addr,
146
                                  void     *dat )
147
{
148
  struct dev_generic *dev = (struct dev_generic *)dat;
149
 
150
  if( !config.ext.class_ptr ) {
151
    fprintf( stderr, "Half word read from disabled generic device\n" );
152
    return 0;
153
  }
154
  else if( addr >= dev->size ) {
155
    TRACE( "Generic device \"%s\": Half word read out of range (addr %"
156
           PRIxADDR ")\n", dev->name, addr );
157
    return 0;
158
  }
159
  else if( addr & 0x1 ) {
160
    fprintf( stderr, "Unaligned half word read from 0x" PRIxADDR " ignored\n",
161
             addr );
162
    return 0;
163
  }
164
  else {
165
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
166
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
167
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
168
 
169
#ifdef WORDS_BIGENDIAN
170
    unsigned long  mask     = 0x0000ffff << (16 - bitoff);
171
    unsigned long  res      = ext_read( wordaddr, mask );
172
 
173
    return (uint16_t)((res >> (16 - bitoff)) & 0x0000ffff);
174
#else
175
    unsigned long  mask     = 0x0000ffff << bitoff;
176
    unsigned long  res      = ext_read( wordaddr, mask );
177
 
178
    return (uint16_t)((res >> bitoff) & 0x0000ffff);
179
#endif      
180
  }
181
}       /* generic_read_hw() */
182
 
183
 
184
static void  generic_write_hw( oraddr_t  addr,
185
                               uint16_t  value,
186
                               void     *dat )
187
{
188
  struct dev_generic *dev = (struct dev_generic *)dat;
189
 
190
  if( !config.ext.class_ptr ) {
191
    fprintf( stderr, "Half word write to disabled generic device\n" );
192
  }
193
  else if( addr >= dev->size ) {
194
    TRACE( "Generic device \"%s\": Half word write out of range (addr %"
195
           PRIxADDR ")\n", dev->name, addr );
196
  }
197
  else if( addr & 0x1 ) {
198
    fprintf( stderr, "Unaligned half word write to 0x" PRIxADDR " ignored\n",
199
             addr );
200
  }
201
  else{
202
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
203
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
204
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
205
 
206
#ifdef WORDS_BIGENDIAN
207
    unsigned long  mask     = 0x0000ffff << (16 - bitoff);
208
    unsigned long  wordval  = ((unsigned long int)value) << (16 - bitoff);
209
#else
210
    unsigned long  mask     = 0x0000ffff << bitoff;
211
    unsigned long  wordval  = ((unsigned long int)value) << bitoff;
212
#endif      
213
 
214
    ext_write( wordaddr, mask, wordval );
215
  }
216
}       /* generic_write_hw() */
217
 
218
 
219
static uint32_t  generic_read_word( oraddr_t  addr,
220
                                    void     *dat )
221
{
222
  struct dev_generic *dev = (struct dev_generic *)dat;
223
 
224
  if( !config.ext.class_ptr ) {
225
    fprintf( stderr, "Full word read from disabled generic device\n" );
226
    return 0;
227
  }
228
  else if( addr >= dev->size ) {
229
    TRACE( "Generic device \"%s\": Full word read out of range (addr %"
230
           PRIxADDR ")\n", dev->name, addr );
231
    return 0;
232
  }
233
  else if( 0 != (addr & 0x3) ) {
234
    fprintf( stderr, "Unaligned full word read from 0x" PRIxADDR " ignored\n",
235
             addr );
236
    return 0;
237
  }
238
  else {
239
    unsigned long  wordaddr = (unsigned long int)(addr + dev->baseaddr);
240
 
241
    return (uint32_t) ext_read( wordaddr, 0xffffffff );
242
  }
243
}       /* generic_read_word() */
244
 
245
 
246
static void  generic_write_word( oraddr_t  addr,
247
                                 uint32_t   value,
248
                                 void     *dat )
249
{
250
  struct dev_generic *dev = (struct dev_generic *)dat;
251
 
252
  if( !config.ext.class_ptr ) {
253
    fprintf( stderr, "Full word write to disabled generic device\n" );
254
  }
255
  else if( addr >= dev->size ) {
256
    TRACE( "Generic device \"%s\": Full word write out of range (addr %"
257
           PRIxADDR ")\n", dev->name, addr );
258
  }
259
  else if( 0 != (addr & 0x3) ) {
260
    fprintf( stderr, "Unaligned full word write to 0x" PRIxADDR " ignored\n",
261
             addr );
262
  }
263
  else{
264
    unsigned long  wordaddr = (unsigned long int)(addr + dev->baseaddr);
265
 
266
    ext_write( wordaddr, 0xffffffff, value );
267
  }
268
}       /* generic_write_word() */
269
 
270
 
271
/* Reset is a null operation */
272
 
273
static void  generic_reset( void *dat )
274
{
275
  return;
276
 
277
}       /* generic_reset() */
278
 
279
 
280
/* Status report can only advise of configuration. */
281
 
282
static void  generic_status( void *dat )
283
{
284
  struct dev_generic *dev = (struct dev_generic *)dat;
285
 
286
  PRINTF( "\nGeneric device \"%s\" at 0x%" PRIxADDR ":\n", dev->name,
287
          dev->baseaddr );
288
  PRINTF( "  Size 0x%" PRIx32 "\n", dev->size );
289
 
290
  if( dev->byte_enabled ) {
291
    PRINTF( "  Byte R/W enabled\n" );
292
  }
293
 
294
  if( dev->hw_enabled ) {
295
    PRINTF( "  Half word R/W enabled\n" );
296
  }
297
 
298
  if( dev->word_enabled ) {
299
    PRINTF( "  Full word R/W enabled\n" );
300
  }
301
 
302
  PRINTF( "\n" );
303
 
304
}       /* generic_status() */
305
 
306
 
307
/* Functions to set configuration */
308
 
309
static void  generic_enabled( union param_val  val,
310
                              void            *dat )
311
{
312
  ((struct dev_generic *)dat)->enabled = val.int_val;
313
 
314
}       /* generic_enabled() */
315
 
316
 
317
static void  generic_byte_enabled( union param_val  val,
318
                                   void            *dat )
319
{
320
  ((struct dev_generic *)dat)->byte_enabled = val.int_val;
321
 
322
}       /* generic_byte_enabled() */
323
 
324
 
325
static void  generic_hw_enabled( union param_val  val,
326
                                 void            *dat )
327
{
328
  ((struct dev_generic *)dat)->hw_enabled = val.int_val;
329
 
330
}       /* generic_hw_enabled() */
331
 
332
 
333
static void  generic_word_enabled( union param_val  val,
334
                                   void            *dat )
335
{
336
  ((struct dev_generic *)dat)->word_enabled = val.int_val;
337
 
338
}       /* generic_word_enabled() */
339
 
340
 
341
static void  generic_name( union param_val  val,
342
                           void            *dat )
343
{
344
  ((struct dev_generic *)dat)->name = strdup( val.str_val );
345
 
346
  if( !((struct dev_generic *)dat)->name ) {
347
    fprintf(stderr, "Peripheral 16450: name \"%s\": Run out of memory\n",
348
            val.str_val );
349
    exit(-1);
350
  }
351
}       /* generic_name() */
352
 
353
 
354
static void  generic_baseaddr( union param_val  val,
355
                               void            *dat )
356
{
357
  ((struct dev_generic *)dat)->baseaddr = val.addr_val;
358
 
359
}       /* generic_baseaddr() */
360
 
361
 
362
static void  generic_size( union param_val  val,
363
                              void            *dat )
364
{
365
  ((struct dev_generic *)dat)->size = val.int_val;
366
 
367
}       /* generic_size() */
368
 
369
 
370
/* Start of new generic section */
371
 
372
static void *generic_sec_start()
373
{
374
  struct dev_generic *new =
375
    (struct dev_generic *)malloc( sizeof( struct dev_generic ));
376
 
377
  if( 0 == new) {
378
    fprintf( stderr, "Generic peripheral: Run out of memory\n" );
379
    exit( -1 );
380
  }
381
 
382
  /* Default names */
383
 
384
  new->enabled      = 1;
385
  new->byte_enabled = 1;
386
  new->hw_enabled   = 1;
387
  new->word_enabled = 1;
388
  new->name         = "anonymous external peripheral";
389
  new->baseaddr     = 0;
390
  new->size         = 0;
391
 
392
  return  new;
393
 
394
}       /* generic_sec_start() */
395
 
396
 
397
/* End of new generic section */
398
 
399
static void  generic_sec_end( void *dat)
400
{
401
  struct dev_generic *generic = (struct dev_generic *)dat;
402
  struct mem_ops      ops;
403
 
404
  /* Give up if not enabled, or if size is zero, or if no access size is
405
     enabled. */
406
 
407
  if( !generic->enabled ) {
408
    free( dat );
409
    return;
410
  }
411
 
412
  if( 0 == generic->size ) {
413
    fprintf( stderr, "Generic peripheral \"%s\" has size 0: ignoring",
414
             generic->name );
415
    free( dat );
416
    return;
417
  }
418
 
419
  if( !generic->byte_enabled &&
420
      !generic->hw_enabled   &&
421
      !generic->word_enabled ) {
422
    fprintf( stderr, "Generic peripheral \"%s\" has no access: ignoring",
423
             generic->name );
424
    free( dat );
425
    return;
426
  }
427
 
428
  /* Zero all the ops, then set the ones we care about. Read/write delays will
429
   * come from the peripheral if desired.
430
   */
431
 
432
  memset( &ops, 0, sizeof( struct mem_ops ));
433
 
434
  if( generic->byte_enabled ) {
435
    ops.readfunc8 = generic_read_byte;
436
    ops.writefunc8 = generic_write_byte;
437
    ops.read_dat8 = dat;
438
    ops.write_dat8 = dat;
439
  }
440
 
441
  if( generic->hw_enabled ) {
442
    ops.readfunc16 = generic_read_hw;
443
    ops.writefunc16 = generic_write_hw;
444
    ops.read_dat16 = dat;
445
    ops.write_dat16 = dat;
446
  }
447
 
448
  if( generic->word_enabled ) {
449
    ops.readfunc32 = generic_read_word;
450
    ops.writefunc32 = generic_write_word;
451
    ops.read_dat32 = dat;
452
    ops.write_dat32 = dat;
453
  }
454
 
455
  /* Register everything */
456
 
457
  reg_mem_area( generic->baseaddr, generic->size, 0, &ops );
458
 
459
  reg_sim_reset( generic_reset,  dat );
460
  reg_sim_stat(  generic_status, dat );
461
 
462
}       /* generic_sec_end() */
463
 
464
 
465
/* Register a generic section. */
466
 
467
void reg_generic_sec(void)
468
{
469
  struct config_section *sec = reg_config_sec( "generic",
470
                                               generic_sec_start,
471
                                               generic_sec_end );
472
 
473
  reg_config_param( sec, "enabled",      paramt_int,  generic_enabled      );
474
  reg_config_param( sec, "byte_enabled", paramt_int,  generic_byte_enabled );
475
  reg_config_param( sec, "hw_enabled",   paramt_int,  generic_hw_enabled   );
476
  reg_config_param( sec, "word_enabled", paramt_int,  generic_word_enabled );
477
  reg_config_param( sec, "name",         paramt_str,  generic_name         );
478
  reg_config_param( sec, "baseaddr",     paramt_addr, generic_baseaddr     );
479
  reg_config_param( sec, "size",         paramt_int,  generic_size         );
480
 
481
}       /* reg_generic_sec */

powered by: WebSVN 2.1.0

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