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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [sim/] [ppc/] [hw_memory.c] - Blame information for rev 1773

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

Line No. Rev Author Line
1 1181 sfurman
/*  This file is part of the program psim.
2
 
3
    Copyright (C) 1994-1997, 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
#ifndef _HW_MEMORY_C_
23
#define _HW_MEMORY_C_
24
 
25
#ifndef STATIC_INLINE_HW_MEMORY
26
#define STATIC_INLINE_HW_MEMORY STATIC_INLINE
27
#endif
28
 
29
#include "device_table.h"
30
 
31
/* DEVICE
32
 
33
 
34
   memory - description of system memory
35
 
36
 
37
   DESCRIPTION
38
 
39
 
40
   This device describes the size and location of the banks of
41
   physical memory within the simulation.
42
 
43
   In addition, this device supports the "claim" and "release" methods
44
   that can be used by OpenBoot client programs to manage the
45
   allocation of physical memory.
46
 
47
 
48
   PROPERTIES
49
 
50
 
51
   reg = { <address> <size> } (required)
52
 
53
   Each pair specify one bank of memory.
54
 
55
   available = { <address> <size> } (automatic)
56
 
57
   Each pair specifies a block of memory that is currently unallocated.
58
 
59
 
60
   BUGS
61
 
62
 
63
   OpenFirmware doesn't make it clear if, when releasing memory the
64
   same address + size pair as was used during the claim should be
65
   specified.
66
 
67
   It is assumed that #size-cells and #address-cells for the parent
68
   node of this device are both one i.e. an address or size can be
69
   specified using a single memory cell (word).
70
 
71
   Significant work will be required before the <<memory>> device can
72
   support 64bit addresses (#address-cells equal two).
73
 
74
   */
75
 
76
typedef struct _memory_reg_spec {
77
  unsigned_cell base;
78
  unsigned_cell size;
79
} memory_reg_spec;
80
 
81
typedef struct _hw_memory_chunk hw_memory_chunk;
82
struct _hw_memory_chunk {
83
  unsigned_word address;
84
  unsigned_word size;
85
  int available;
86
  hw_memory_chunk *next;
87
};
88
 
89
typedef struct _hw_memory_device {
90
  hw_memory_chunk *heap;
91
} hw_memory_device;
92
 
93
 
94
static void *
95
hw_memory_create(const char *name,
96
                 const device_unit *unit_address,
97
                 const char *args)
98
{
99
  hw_memory_device *hw_memory = ZALLOC(hw_memory_device);
100
  return hw_memory;
101
}
102
 
103
 
104
static void
105
hw_memory_set_available(device *me,
106
                        hw_memory_device *hw_memory)
107
{
108
  hw_memory_chunk *chunk = NULL;
109
  memory_reg_spec *available = NULL;
110
  int nr_available = 0;
111
  int curr = 0;
112
  int sizeof_available = 0;
113
  /* determine the nr of available chunks */
114
  chunk = hw_memory->heap;
115
  nr_available = 0;
116
  while (chunk != NULL) {
117
    if (chunk->available)
118
      nr_available += 1;
119
    ASSERT(chunk->next == NULL
120
           || chunk->address < chunk->next->address);
121
    ASSERT(chunk->next == NULL
122
           || chunk->address + chunk->size == chunk->next->address);
123
    chunk = chunk->next;
124
  }
125
  /* now create the available struct */
126
  ASSERT(nr_available > 0);
127
  sizeof_available = sizeof(memory_reg_spec) * nr_available;
128
  available = zalloc(sizeof_available);
129
  chunk = hw_memory->heap;
130
  curr = 0;
131
  while (chunk != NULL) {
132
    if (chunk->available) {
133
      available[curr].base = H2BE_cell(chunk->address);
134
      available[curr].size = H2BE_cell(chunk->size);
135
      curr += 1;
136
    }
137
    chunk = chunk->next;
138
  }
139
  /* update */
140
  device_set_array_property(me, "available", available, sizeof_available);
141
  zfree(available);
142
}
143
 
144
 
145
static void
146
hw_memory_init_address(device *me)
147
{
148
  hw_memory_device *hw_memory = (hw_memory_device*)device_data(me);
149
 
150
  /* free up any previous structures */
151
  {
152
    hw_memory_chunk *curr_chunk = hw_memory->heap;
153
    hw_memory->heap = NULL;
154
    while (curr_chunk != NULL) {
155
      hw_memory_chunk *dead_chunk = curr_chunk;
156
      curr_chunk = dead_chunk->next;
157
      dead_chunk->next = NULL;
158
      zfree(dead_chunk);
159
    }
160
  }
161
 
162
  /* attach memory regions according to the "reg" property */
163
  {
164
    int reg_nr;
165
    reg_property_spec reg;
166
    for (reg_nr = 0;
167
         device_find_reg_array_property(me, "reg", reg_nr, &reg);
168
         reg_nr++) {
169
      int i;
170
      /* check that the entry meets restrictions */
171
      for (i = 0; i < reg.address.nr_cells - 1; i++)
172
        if (reg.address.cells[i] != 0)
173
          device_error(me, "Only single celled addresses supported");
174
      for (i = 0; i < reg.size.nr_cells - 1; i++)
175
        if (reg.size.cells[i] != 0)
176
          device_error(me, "Only single celled sizes supported");
177
      /* attach the range */
178
      device_attach_address(device_parent(me),
179
                            attach_raw_memory,
180
 
181
                            reg.address.cells[reg.address.nr_cells - 1],
182
                            reg.size.cells[reg.size.nr_cells - 1],
183
                            access_read_write_exec,
184
                            me);
185
    }
186
  }
187
 
188
  /* create the initial `available memory' data structure */
189
  if (device_find_property(me, "available") != NULL) {
190
    hw_memory_chunk **curr_chunk = &hw_memory->heap;
191
    int cell_nr;
192
    unsigned_cell dummy;
193
    int nr_cells = device_find_integer_array_property(me, "available", 0, &dummy);
194
    if ((nr_cells % 2) != 0)
195
      device_error(me, "property \"available\" invalid - contains an odd number of cells");
196
    for (cell_nr = 0;
197
         cell_nr < nr_cells;
198
         cell_nr += 2) {
199
      hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk);
200
      device_find_integer_array_property(me, "available", cell_nr,
201
                                         &new_chunk->address);
202
      device_find_integer_array_property(me, "available", cell_nr + 1,
203
                                         &new_chunk->size);
204
      new_chunk->available = 1;
205
      *curr_chunk = new_chunk;
206
      curr_chunk = &new_chunk->next;
207
    }
208
  }
209
  else {
210
    hw_memory_chunk **curr_chunk = &hw_memory->heap;
211
    int reg_nr;
212
    reg_property_spec reg;
213
    for (reg_nr = 0;
214
         device_find_reg_array_property(me, "reg", reg_nr, &reg);
215
         reg_nr++) {
216
      hw_memory_chunk *new_chunk;
217
      new_chunk = ZALLOC(hw_memory_chunk);
218
      new_chunk->address = reg.address.cells[reg.address.nr_cells - 1];
219
      new_chunk->size = reg.size.cells[reg.size.nr_cells - 1];
220
      new_chunk->available = 1;
221
      *curr_chunk = new_chunk;
222
      curr_chunk = &new_chunk->next;
223
    }
224
  }
225
 
226
  /* initialize the alloc property for this device */
227
  hw_memory_set_available(me, hw_memory);
228
}
229
 
230
static void
231
hw_memory_instance_delete(device_instance *instance)
232
{
233
  return;
234
}
235
 
236
static int
237
hw_memory_instance_claim(device_instance *instance,
238
                         int n_stack_args,
239
                         unsigned_cell stack_args[/*n_stack_args*/],
240
                         int n_stack_returns,
241
                         unsigned_cell stack_returns[/*n_stack_returns*/])
242
{
243
  hw_memory_device *hw_memory = device_instance_data(instance);
244
  device *me = device_instance_device(instance);
245
  int stackp = 0;
246
  unsigned_word alignment;
247
  unsigned_cell size;
248
  unsigned_cell address;
249
  hw_memory_chunk *chunk = NULL;
250
 
251
  /* get the alignment from the stack */
252
  if (n_stack_args < stackp + 1)
253
    device_error(me, "claim - incorrect number of arguments (alignment missing)");
254
  alignment = stack_args[stackp];
255
  stackp++;
256
 
257
  /* get the size from the stack */
258
  {
259
    int i;
260
    int nr_cells = device_nr_size_cells(device_parent(me));
261
    if (n_stack_args < stackp + nr_cells)
262
      device_error(me, "claim - incorrect number of arguments (size missing)");
263
    for (i = 0; i < nr_cells - 1; i++) {
264
      if (stack_args[stackp] != 0)
265
        device_error(me, "claim - multi-cell sizes not supported");
266
      stackp++;
267
    }
268
    size = stack_args[stackp];
269
    stackp++;
270
  }
271
 
272
  /* get the address from the stack */
273
  {
274
    int nr_cells = device_nr_address_cells(device_parent(me));
275
    if (alignment != 0) {
276
      if (n_stack_args != stackp) {
277
        if (n_stack_args == stackp + nr_cells)
278
          DTRACE(memory, ("claim - extra address argument ignored\n"));
279
        else
280
          device_error(me, "claim - incorrect number of arguments (optional addr)");
281
      }
282
      address = 0;
283
    }
284
    else {
285
      int i;
286
      if (n_stack_args != stackp + nr_cells)
287
        device_error(me, "claim - incorrect number of arguments (addr missing)");
288
      for (i = 0; i < nr_cells - 1; i++) {
289
        if (stack_args[stackp] != 0)
290
          device_error(me, "claim - multi-cell addresses not supported");
291
        stackp++;
292
      }
293
      address = stack_args[stackp];
294
    }
295
  }
296
 
297
  /* check that there is space for the result */
298
  if (n_stack_returns != 0
299
      && n_stack_returns != device_nr_address_cells(device_parent(me)))
300
    device_error(me, "claim - invalid number of return arguments");
301
 
302
  /* find a chunk candidate, either according to address or alignment */
303
  if (alignment == 0) {
304
    chunk = hw_memory->heap;
305
    while (chunk != NULL) {
306
      if ((address + size) <= (chunk->address + chunk->size))
307
        break;
308
      chunk = chunk->next;
309
    }
310
    if (chunk == NULL || address < chunk->address || !chunk->available)
311
      device_error(me, "failed to allocate %ld bytes at 0x%lx",
312
                   (unsigned long)size, (unsigned long)address);
313
    DTRACE(memory, ("claim - address=0x%lx size=0x%lx\n",
314
                    (unsigned long)address,
315
                    (unsigned long)size));
316
  }
317
  else {
318
    /* adjust the alignment so that it is a power of two */
319
    unsigned_word align_mask = 1;
320
    while (align_mask < alignment && align_mask != 0)
321
      align_mask <<= 1;
322
    if (align_mask == 0)
323
      device_error(me, "alignment 0x%lx is to large", (unsigned long)alignment);
324
    align_mask -= 1;
325
    /* now find an aligned chunk that fits */
326
    chunk = hw_memory->heap;
327
    while (chunk != NULL) {
328
      address = ((chunk->address + align_mask) & ~align_mask);
329
      if ((chunk->available)
330
          && (chunk->address + chunk->size >= address + size))
331
        break;
332
      chunk = chunk->next;
333
    }
334
    if (chunk == NULL)
335
      device_error(me, "failed to allocate %ld bytes with alignment %ld",
336
                   (unsigned long)size, (unsigned long)alignment);
337
    DTRACE(memory, ("claim - size=0x%lx alignment=%ld (0x%lx), address=0x%lx\n",
338
                    (unsigned long)size,
339
                    (unsigned long)alignment,
340
                    (unsigned long)alignment,
341
                    (unsigned long)address));
342
  }
343
 
344
  /* break off a bit before this chunk if needed */
345
  ASSERT(address >= chunk->address);
346
  if (address > chunk->address) {
347
    hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
348
    /* insert a new chunk */
349
    next_chunk->next = chunk->next;
350
    chunk->next = next_chunk;
351
    /* adjust the address/size */
352
    next_chunk->address = address;
353
    next_chunk->size = chunk->address + chunk->size - next_chunk->address;
354
    next_chunk->available = 1;
355
    chunk->size = next_chunk->address - chunk->address;
356
    /* make this new chunk the one to allocate */
357
    chunk = next_chunk;
358
  }
359
  ASSERT(address == chunk->address);
360
 
361
  /* break off a bit after this chunk if needed */
362
  ASSERT(address + size <= chunk->address + chunk->size);
363
  if (address + size < chunk->address + chunk->size) {
364
    hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
365
    /* insert it in to the list */
366
    next_chunk->next = chunk->next;
367
    chunk->next = next_chunk;
368
    /* adjust the address/size */
369
    next_chunk->address = address + size;
370
    next_chunk->size = chunk->address + chunk->size - next_chunk->address;
371
    next_chunk->available = 1;
372
    chunk->size = next_chunk->address - chunk->address;
373
  }
374
  ASSERT(address + size == chunk->address + chunk->size);
375
 
376
  /* now allocate/return it */
377
  chunk->available = 0;
378
  hw_memory_set_available(device_instance_device(instance), hw_memory);
379
  if (n_stack_returns > 0) {
380
    int i;
381
    for (i = 0; i < n_stack_returns - 1; i++)
382
      stack_returns[i] = 0;
383
    stack_returns[n_stack_returns - 1] = address;
384
  }
385
 
386
  return 0;
387
}
388
 
389
 
390
static int
391
hw_memory_instance_release(device_instance *instance,
392
                           int n_stack_args,
393
                           unsigned_cell stack_args[/*n_stack_args*/],
394
                           int n_stack_returns,
395
                           unsigned_cell stack_returns[/*n_stack_returns*/])
396
{
397
  hw_memory_device *hw_memory = device_instance_data(instance);
398
  device *me = device_instance_device(instance);
399
  unsigned_word length;
400
  unsigned_word address;
401
  int stackp = 0;
402
  hw_memory_chunk *chunk;
403
 
404
  /* get the length from the stack */
405
  {
406
    int i;
407
    int nr_cells = device_nr_size_cells(device_parent(me));
408
    if (n_stack_args < stackp + nr_cells)
409
      device_error(me, "release - incorrect number of arguments (length missing)");
410
    for (i = 0; i < nr_cells - 1; i++) {
411
      if (stack_args[stackp] != 0)
412
        device_error(me, "release - multi-cell length not supported");
413
      stackp++;
414
    }
415
    length = stack_args[stackp];
416
    stackp++;
417
  }
418
 
419
  /* get the address from the stack */
420
  {
421
    int i;
422
    int nr_cells = device_nr_address_cells(device_parent(me));
423
    if (n_stack_args != stackp + nr_cells)
424
      device_error(me, "release - incorrect number of arguments (addr missing)");
425
    for (i = 0; i < nr_cells - 1; i++) {
426
      if (stack_args[stackp] != 0)
427
        device_error(me, "release - multi-cell addresses not supported");
428
      stackp++;
429
    }
430
    address = stack_args[stackp];
431
  }
432
 
433
  /* returns ok */
434
  if (n_stack_returns != 0)
435
    device_error(me, "release - nonzero number of results");
436
 
437
  /* try to free the corresponding memory chunk */
438
  chunk = hw_memory->heap;
439
  while (chunk != NULL) {
440
    if (chunk->address == address
441
        && chunk->size == length) {
442
      /* an exact match */
443
      if (chunk->available)
444
        device_error(me, "memory chunk 0x%lx (size 0x%lx) already available",
445
                     (unsigned long)address,
446
                     (unsigned long)length);
447
      else {
448
        /* free this chunk */
449
        DTRACE(memory, ("release - address=0x%lx, length=0x%lx\n",
450
                        (unsigned long) address,
451
                        (unsigned long) length));
452
        chunk->available = 1;
453
        break;
454
      }
455
    }
456
    else if (chunk->address >= address
457
             && chunk->address + chunk->size <= address + length) {
458
      /* a sub region */
459
      if (!chunk->available) {
460
        DTRACE(memory, ("release - address=0x%lx, size=0x%lx within region 0x%lx length 0x%lx\n",
461
                        (unsigned long) chunk->address,
462
                        (unsigned long) chunk->size,
463
                        (unsigned long) address,
464
                        (unsigned long) length));
465
        chunk->available = 1;
466
      }
467
    }
468
    chunk = chunk->next;
469
  }
470
  if (chunk == NULL) {
471
    printf_filtered("warning: released chunks within region 0x%lx..0x%lx\n",
472
                    (unsigned long)address,
473
                    (unsigned long)(address + length - 1));
474
  }
475
 
476
  /* check for the chance to merge two adjacent available memory chunks */
477
  chunk = hw_memory->heap;
478
  while (chunk != NULL) {
479
    if (chunk->available
480
        && chunk->next != NULL && chunk->next->available) {
481
      /* adjacent */
482
      hw_memory_chunk *delete = chunk->next;
483
      ASSERT(chunk->address + chunk->size == delete->address);
484
      chunk->size += delete->size;
485
      chunk->next = delete->next;
486
      zfree(delete);
487
    }
488
    else {
489
      chunk = chunk->next;
490
    }
491
  }
492
 
493
  /* update the corresponding property */
494
  hw_memory_set_available(device_instance_device(instance), hw_memory);
495
 
496
  return 0;
497
}
498
 
499
 
500
static device_instance_methods hw_memory_instance_methods[] = {
501
  { "claim", hw_memory_instance_claim },
502
  { "release", hw_memory_instance_release },
503
  { NULL, },
504
};
505
 
506
static device_instance_callbacks const hw_memory_instance_callbacks = {
507
  hw_memory_instance_delete,
508
  NULL /*read*/, NULL /*write*/, NULL /*seek*/,
509
  hw_memory_instance_methods
510
};
511
 
512
static device_instance *
513
hw_memory_create_instance(device *me,
514
                          const char *path,
515
                          const char *args)
516
{
517
  return device_create_instance_from(me, NULL,
518
                                     device_data(me), /* nothing better */
519
                                     path, args,
520
                                     &hw_memory_instance_callbacks);
521
}
522
 
523
static device_callbacks const hw_memory_callbacks = {
524
  { hw_memory_init_address, },
525
  { NULL, }, /* address */
526
  { NULL, }, /* IO */
527
  { NULL, }, /* DMA */
528
  { NULL, }, /* interrupt */
529
  { NULL, }, /* unit */
530
  hw_memory_create_instance,
531
};
532
 
533
const device_descriptor hw_memory_device_descriptor[] = {
534
  { "memory", hw_memory_create, &hw_memory_callbacks },
535
  { NULL },
536
};
537
 
538
#endif /* _HW_MEMORY_C_ */

powered by: WebSVN 2.1.0

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