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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [common/] [hw-base.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*  This file is part of the program psim.
2
 
3
    Copyright (C) 1994-1996, 1998, Andrew Cagney <cagney@highland.com.au>
4
 
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
 
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
 
15
    You should have received a copy of the GNU General Public License
16
    along with this program; if not, write to the Free Software
17
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 
19
    */
20
 
21
 
22
#include "hw-main.h"
23
#include "hw-base.h"
24
 
25
 
26
#ifdef HAVE_STRING_H
27
#include <string.h>
28
#else
29
#ifdef HAVE_STRINGS_H
30
#include <strings.h>
31
#endif
32
#endif
33
 
34
#if HAVE_STDLIB_H
35
#include <stdlib.h>
36
#endif
37
 
38
#include <ctype.h>
39
 
40
#include "hw-config.h"
41
 
42
struct hw_base_data {
43
  int finished_p;
44
  const struct hw_descriptor *descriptor;
45
  hw_delete_callback *to_delete;
46
};
47
 
48
static int
49
generic_hw_unit_decode (struct hw *bus,
50
                        const char *unit,
51
                        hw_unit *phys)
52
{
53
  memset (phys, 0, sizeof (*phys));
54
  if (unit == NULL)
55
    return 0;
56
  else
57
    {
58
      int nr_cells = 0;
59
      const int max_nr_cells = hw_unit_nr_address_cells (bus);
60
      while (1)
61
        {
62
          char *end = NULL;
63
          unsigned long val;
64
          val = strtoul (unit, &end, 0);
65
          /* parse error? */
66
          if (unit == end)
67
            return -1;
68
          /* two many cells? */
69
          if (nr_cells >= max_nr_cells)
70
            return -1;
71
          /* save it */
72
          phys->cells[nr_cells] = val;
73
          nr_cells++;
74
          unit = end;
75
          /* more to follow? */
76
          if (isspace (*unit) || *unit == '\0')
77
            break;
78
          if (*unit != ',')
79
            return -1;
80
          unit++;
81
        }
82
      if (nr_cells < max_nr_cells) {
83
        /* shift everything to correct position */
84
        int i;
85
        for (i = 1; i <= nr_cells; i++)
86
          phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
87
        for (i = 0; i < (max_nr_cells - nr_cells); i++)
88
          phys->cells[i] = 0;
89
      }
90
      phys->nr_cells = max_nr_cells;
91
      return max_nr_cells;
92
  }
93
}
94
 
95
static int
96
generic_hw_unit_encode (struct hw *bus,
97
                        const hw_unit *phys,
98
                        char *buf,
99
                        int sizeof_buf)
100
{
101
  int i;
102
  int len;
103
  char *pos = buf;
104
  /* skip leading zero's */
105
  for (i = 0; i < phys->nr_cells; i++)
106
    {
107
      if (phys->cells[i] != 0)
108
        break;
109
    }
110
  /* don't output anything if empty */
111
  if (phys->nr_cells == 0)
112
    {
113
      strcpy(pos, "");
114
      len = 0;
115
    }
116
  else if (i == phys->nr_cells)
117
    {
118
      /* all zero */
119
      strcpy(pos, "0");
120
      len = 1;
121
    }
122
  else
123
    {
124
      for (; i < phys->nr_cells; i++)
125
        {
126
          if (pos != buf) {
127
            strcat(pos, ",");
128
            pos = strchr(pos, '\0');
129
          }
130
          if (phys->cells[i] < 10)
131
            sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
132
          else
133
            sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
134
          pos = strchr(pos, '\0');
135
        }
136
      len = pos - buf;
137
    }
138
  if (len >= sizeof_buf)
139
    hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
140
  return len;
141
}
142
 
143
static int
144
generic_hw_unit_address_to_attach_address (struct hw *me,
145
                                           const hw_unit *address,
146
                                           int *attach_space,
147
                                           unsigned_word *attach_address,
148
                                           struct hw *client)
149
{
150
  int i;
151
  for (i = 0; i < address->nr_cells - 2; i++)
152
    {
153
      if (address->cells[i] != 0)
154
        hw_abort (me, "Only 32bit addresses supported");
155
    }
156
  if (address->nr_cells >= 2)
157
    *attach_space = address->cells[address->nr_cells - 2];
158
  else
159
    *attach_space = 0;
160
  *attach_address = address->cells[address->nr_cells - 1];
161
  return 1;
162
}
163
 
164
static int
165
generic_hw_unit_size_to_attach_size (struct hw *me,
166
                                     const hw_unit *size,
167
                                     unsigned *nr_bytes,
168
                                     struct hw *client)
169
{
170
  int i;
171
  for (i = 0; i < size->nr_cells - 1; i++)
172
    {
173
      if (size->cells[i] != 0)
174
        hw_abort (me, "Only 32bit sizes supported");
175
    }
176
  *nr_bytes = size->cells[0];
177
  return *nr_bytes;
178
}
179
 
180
 
181
/* ignore/passthrough versions of each function */
182
 
183
static void
184
passthrough_hw_attach_address (struct hw *me,
185
                               int level,
186
                               int space,
187
                               address_word addr,
188
                               address_word nr_bytes,
189
                               struct hw *client) /*callback/default*/
190
{
191
  if (hw_parent (me) == NULL)
192
    hw_abort (client, "hw_attach_address: no parent attach method");
193
  hw_attach_address (hw_parent (me), level,
194
                     space, addr, nr_bytes,
195
                     client);
196
}
197
 
198
static void
199
passthrough_hw_detach_address (struct hw *me,
200
                               int level,
201
                               int space,
202
                               address_word addr,
203
                               address_word nr_bytes,
204
                               struct hw *client) /*callback/default*/
205
{
206
  if (hw_parent (me) == NULL)
207
    hw_abort (client, "hw_attach_address: no parent attach method");
208
  hw_detach_address (hw_parent (me), level,
209
                     space, addr, nr_bytes,
210
                     client);
211
}
212
 
213
static unsigned
214
panic_hw_io_read_buffer (struct hw *me,
215
                         void *dest,
216
                         int space,
217
                         unsigned_word addr,
218
                         unsigned nr_bytes)
219
{
220
  hw_abort (me, "no io-read method");
221
  return 0;
222
}
223
 
224
static unsigned
225
panic_hw_io_write_buffer (struct hw *me,
226
                          const void *source,
227
                          int space,
228
                          unsigned_word addr,
229
                          unsigned nr_bytes)
230
{
231
  hw_abort (me, "no io-write method");
232
  return 0;
233
}
234
 
235
static unsigned
236
passthrough_hw_dma_read_buffer (struct hw *me,
237
                                void *dest,
238
                                int space,
239
                                unsigned_word addr,
240
                                unsigned nr_bytes)
241
{
242
  if (hw_parent (me) == NULL)
243
    hw_abort (me, "no parent dma-read method");
244
  return hw_dma_read_buffer (hw_parent (me), dest,
245
                             space, addr, nr_bytes);
246
}
247
 
248
static unsigned
249
passthrough_hw_dma_write_buffer (struct hw *me,
250
                                 const void *source,
251
                                 int space,
252
                                 unsigned_word addr,
253
                                 unsigned nr_bytes,
254
                                 int violate_read_only_section)
255
{
256
  if (hw_parent (me) == NULL)
257
    hw_abort (me, "no parent dma-write method");
258
  return hw_dma_write_buffer (hw_parent (me), source,
259
                              space, addr,
260
                              nr_bytes,
261
                              violate_read_only_section);
262
}
263
 
264
static void
265
ignore_hw_delete (struct hw *me)
266
{
267
  /* NOP */
268
}
269
 
270
 
271
 
272
 
273
static const char *
274
full_name_of_hw (struct hw *leaf,
275
                 char *buf,
276
                 unsigned sizeof_buf)
277
{
278
  /* get a buffer */
279
  char full_name[1024];
280
  if (buf == (char*)0)
281
    {
282
      buf = full_name;
283
      sizeof_buf = sizeof (full_name);
284
    }
285
 
286
  /* use head recursion to construct the path */
287
 
288
  if (hw_parent (leaf) == NULL)
289
    /* root */
290
    {
291
      if (sizeof_buf < 1)
292
        hw_abort (leaf, "buffer overflow");
293
      *buf = '\0';
294
    }
295
  else
296
    /* sub node */
297
    {
298
      char unit[1024];
299
      full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
300
      if (hw_unit_encode (hw_parent (leaf),
301
                          hw_unit_address (leaf),
302
                          unit + 1,
303
                          sizeof (unit) - 1)
304
          > 0)
305
        unit[0] = '@';
306
      else
307
        unit[0] = '\0';
308
      if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
309
          >= sizeof_buf)
310
        hw_abort (leaf, "buffer overflow");
311
      strcat (buf, "/");
312
      strcat (buf, hw_name (leaf));
313
      strcat (buf, unit);
314
    }
315
 
316
  /* return it usefully */
317
  if (buf == full_name)
318
    buf = hw_strdup (leaf, full_name);
319
  return buf;
320
}
321
 
322
struct hw *
323
hw_create (struct sim_state *sd,
324
           struct hw *parent,
325
           const char *family,
326
           const char *name,
327
           const char *unit,
328
           const char *args)
329
{
330
 /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
331
  struct hw *hw = ZALLOC (struct hw);
332
 
333
  /* our identity */
334
  hw->family_of_hw = hw_strdup (hw, family);
335
  hw->name_of_hw = hw_strdup (hw, name);
336
  hw->args_of_hw = hw_strdup (hw, args);
337
 
338
  /* a hook into the system */
339
  if (sd != NULL)
340
    hw->system_of_hw = sd;
341
  else if (parent != NULL)
342
    hw->system_of_hw = hw_system (parent);
343
  else
344
    hw_abort (parent, "No system found");
345
 
346
  /* in a tree */
347
  if (parent != NULL)
348
    {
349
      struct hw **sibling = &parent->child_of_hw;
350
      while ((*sibling) != NULL)
351
        sibling = &(*sibling)->sibling_of_hw;
352
      *sibling = hw;
353
      hw->parent_of_hw = parent;
354
    }
355
 
356
  /* top of tree */
357
  if (parent != NULL)
358
    {
359
      struct hw *root = parent;
360
      while (root->parent_of_hw != NULL)
361
        root = root->parent_of_hw;
362
      hw->root_of_hw = root;
363
    }
364
 
365
  /* a unique identifier for the device on the parents bus */
366
  if (parent != NULL)
367
    {
368
      hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
369
    }
370
 
371
  /* Determine our path */
372
  if (parent != NULL)
373
    hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
374
  else
375
    hw->path_of_hw = "/";
376
 
377
  /* create our base type */
378
  hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
379
  hw->base_of_hw->finished_p = 0;
380
 
381
  /* our callbacks */
382
  set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
383
  set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
384
  set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
385
  set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
386
  set_hw_unit_decode (hw, generic_hw_unit_decode);
387
  set_hw_unit_encode (hw, generic_hw_unit_encode);
388
  set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
389
  set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
390
  set_hw_attach_address (hw, passthrough_hw_attach_address);
391
  set_hw_detach_address (hw, passthrough_hw_detach_address);
392
  set_hw_delete (hw, ignore_hw_delete);
393
 
394
  /* locate a descriptor */
395
  {
396
    const struct hw_descriptor **table;
397
    for (table = hw_descriptors;
398
         *table != NULL;
399
         table++)
400
      {
401
        const struct hw_descriptor *entry;
402
        for (entry = *table;
403
             entry->family != NULL;
404
             entry++)
405
          {
406
            if (strcmp (family, entry->family) == 0)
407
              {
408
                hw->base_of_hw->descriptor = entry;
409
                break;
410
              }
411
          }
412
      }
413
    if (hw->base_of_hw->descriptor == NULL)
414
      {
415
        hw_abort (parent, "Unknown device `%s'", family);
416
      }
417
  }
418
 
419
  /* Attach dummy ports */
420
  create_hw_alloc_data (hw);
421
  create_hw_property_data (hw);
422
  create_hw_port_data (hw);
423
  create_hw_event_data (hw);
424
  create_hw_handle_data (hw);
425
  create_hw_instance_data (hw);
426
 
427
  return hw;
428
}
429
 
430
 
431
int
432
hw_finished_p (struct hw *me)
433
{
434
  return (me->base_of_hw->finished_p);
435
}
436
 
437
void
438
hw_finish (struct hw *me)
439
{
440
  if (hw_finished_p (me))
441
    hw_abort (me, "Attempt to finish finished device");
442
 
443
  /* Fill in the (hopefully) defined address/size cells values */
444
  if (hw_find_property (me, "#address-cells") != NULL)
445
    me->nr_address_cells_of_hw_unit =
446
      hw_find_integer_property (me, "#address-cells");
447
  else
448
    me->nr_address_cells_of_hw_unit = 2;
449
  if (hw_find_property (me, "#size-cells") != NULL)
450
    me->nr_size_cells_of_hw_unit =
451
      hw_find_integer_property (me, "#size-cells");
452
  else
453
    me->nr_size_cells_of_hw_unit = 1;
454
 
455
  /* Fill in the (hopefully) defined trace variable */
456
  if (hw_find_property (me, "trace?") != NULL)
457
    me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
458
  /* allow global variable to define default tracing */
459
  else if (! hw_trace_p (me)
460
           && hw_find_property (hw_root (me), "global-trace?") != NULL
461
           && hw_find_boolean_property (hw_root (me), "global-trace?"))
462
    me->trace_of_hw_p = 1;
463
 
464
 
465
  /* Allow the real device to override any methods */
466
  me->base_of_hw->descriptor->to_finish (me);
467
  me->base_of_hw->finished_p = 1;
468
}
469
 
470
 
471
void
472
hw_delete (struct hw *me)
473
{
474
  /* give the object a chance to tidy up */
475
  me->base_of_hw->to_delete (me);
476
 
477
  delete_hw_instance_data (me);
478
  delete_hw_handle_data (me);
479
  delete_hw_event_data (me);
480
  delete_hw_port_data (me);
481
  delete_hw_property_data (me);
482
 
483
  /* now unlink us from the tree */
484
  if (hw_parent (me))
485
    {
486
      struct hw **sibling = &hw_parent (me)->child_of_hw;
487
      while (*sibling != NULL)
488
        {
489
          if (*sibling == me)
490
            {
491
              *sibling = me->sibling_of_hw;
492
              me->sibling_of_hw = NULL;
493
              me->parent_of_hw = NULL;
494
              break;
495
            }
496
        }
497
    }
498
 
499
  /* some sanity checks */
500
  if (hw_child (me) != NULL)
501
    {
502
      hw_abort (me, "attempt to delete device with children");
503
    }
504
  if (hw_sibling (me) != NULL)
505
    {
506
      hw_abort (me, "attempt to delete device with siblings");
507
    }
508
 
509
  /* blow away all memory belonging to the device */
510
  delete_hw_alloc_data (me);
511
 
512
  /* finally */
513
  zfree (me);
514
}
515
 
516
void
517
set_hw_delete (struct hw *hw, hw_delete_callback method)
518
{
519
  hw->base_of_hw->to_delete = method;
520
}
521
 
522
 
523
/* Go through the devices various reg properties for those that
524
   specify attach addresses */
525
 
526
 
527
void
528
do_hw_attach_regs (struct hw *hw)
529
{
530
  static const char *(reg_property_names[]) = {
531
    "attach-addresses",
532
    "assigned-addresses",
533
    "reg",
534
    "alternate-reg" ,
535
    NULL
536
  };
537
  const char **reg_property_name;
538
  int nr_valid_reg_properties = 0;
539
  for (reg_property_name = reg_property_names;
540
       *reg_property_name != NULL;
541
       reg_property_name++)
542
    {
543
      if (hw_find_property (hw, *reg_property_name) != NULL)
544
        {
545
          reg_property_spec reg;
546
          int reg_entry;
547
          for (reg_entry = 0;
548
               hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
549
                                           &reg);
550
               reg_entry++)
551
            {
552
              unsigned_word attach_address;
553
              int attach_space;
554
              unsigned attach_size;
555
              if (!hw_unit_address_to_attach_address (hw_parent (hw),
556
                                                      &reg.address,
557
                                                      &attach_space,
558
                                                      &attach_address,
559
                                                      hw))
560
                continue;
561
              if (!hw_unit_size_to_attach_size (hw_parent (hw),
562
                                                &reg.size,
563
                                                &attach_size, hw))
564
                continue;
565
              hw_attach_address (hw_parent (hw),
566
                                 0,
567
                                 attach_space, attach_address, attach_size,
568
                                 hw);
569
              nr_valid_reg_properties++;
570
            }
571
          /* if first option matches don't try for any others */
572
          if (reg_property_name == reg_property_names)
573
            break;
574
        }
575
    }
576
}

powered by: WebSVN 2.1.0

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