OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [sim/] [ppc/] [hw_memory.c] - Diff between revs 24 and 157

Only display areas with differences | Details | Blame | View Log

Rev 24 Rev 157
/*  This file is part of the program psim.
/*  This file is part of the program psim.
 
 
    Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
    Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    (at your option) any later version.
 
 
    This program is distributed in the hope that it will be useful,
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    GNU General Public License for more details.
 
 
    You should have received a copy of the GNU General Public License
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 
    */
    */
 
 
 
 
#ifndef _HW_MEMORY_C_
#ifndef _HW_MEMORY_C_
#define _HW_MEMORY_C_
#define _HW_MEMORY_C_
 
 
#ifndef STATIC_INLINE_HW_MEMORY
#ifndef STATIC_INLINE_HW_MEMORY
#define STATIC_INLINE_HW_MEMORY STATIC_INLINE
#define STATIC_INLINE_HW_MEMORY STATIC_INLINE
#endif
#endif
 
 
#include "device_table.h"
#include "device_table.h"
 
 
/* DEVICE
/* DEVICE
 
 
 
 
   memory - description of system memory
   memory - description of system memory
 
 
 
 
   DESCRIPTION
   DESCRIPTION
 
 
 
 
   This device describes the size and location of the banks of
   This device describes the size and location of the banks of
   physical memory within the simulation.
   physical memory within the simulation.
 
 
   In addition, this device supports the "claim" and "release" methods
   In addition, this device supports the "claim" and "release" methods
   that can be used by OpenBoot client programs to manage the
   that can be used by OpenBoot client programs to manage the
   allocation of physical memory.
   allocation of physical memory.
 
 
 
 
   PROPERTIES
   PROPERTIES
 
 
 
 
   reg = { <address> <size> } (required)
   reg = { <address> <size> } (required)
 
 
   Each pair specify one bank of memory.
   Each pair specify one bank of memory.
 
 
   available = { <address> <size> } (automatic)
   available = { <address> <size> } (automatic)
 
 
   Each pair specifies a block of memory that is currently unallocated.
   Each pair specifies a block of memory that is currently unallocated.
 
 
 
 
   BUGS
   BUGS
 
 
 
 
   OpenFirmware doesn't make it clear if, when releasing memory the
   OpenFirmware doesn't make it clear if, when releasing memory the
   same address + size pair as was used during the claim should be
   same address + size pair as was used during the claim should be
   specified.
   specified.
 
 
   It is assumed that #size-cells and #address-cells for the parent
   It is assumed that #size-cells and #address-cells for the parent
   node of this device are both one i.e. an address or size can be
   node of this device are both one i.e. an address or size can be
   specified using a single memory cell (word).
   specified using a single memory cell (word).
 
 
   Significant work will be required before the <<memory>> device can
   Significant work will be required before the <<memory>> device can
   support 64bit addresses (#address-cells equal two).
   support 64bit addresses (#address-cells equal two).
 
 
   */
   */
 
 
typedef struct _memory_reg_spec {
typedef struct _memory_reg_spec {
  unsigned_cell base;
  unsigned_cell base;
  unsigned_cell size;
  unsigned_cell size;
} memory_reg_spec;
} memory_reg_spec;
 
 
typedef struct _hw_memory_chunk hw_memory_chunk;
typedef struct _hw_memory_chunk hw_memory_chunk;
struct _hw_memory_chunk {
struct _hw_memory_chunk {
  unsigned_word address;
  unsigned_word address;
  unsigned_word size;
  unsigned_word size;
  int available;
  int available;
  hw_memory_chunk *next;
  hw_memory_chunk *next;
};
};
 
 
typedef struct _hw_memory_device {
typedef struct _hw_memory_device {
  hw_memory_chunk *heap;
  hw_memory_chunk *heap;
} hw_memory_device;
} hw_memory_device;
 
 
 
 
static void *
static void *
hw_memory_create(const char *name,
hw_memory_create(const char *name,
                 const device_unit *unit_address,
                 const device_unit *unit_address,
                 const char *args)
                 const char *args)
{
{
  hw_memory_device *hw_memory = ZALLOC(hw_memory_device);
  hw_memory_device *hw_memory = ZALLOC(hw_memory_device);
  return hw_memory;
  return hw_memory;
}
}
 
 
 
 
static void
static void
hw_memory_set_available(device *me,
hw_memory_set_available(device *me,
                        hw_memory_device *hw_memory)
                        hw_memory_device *hw_memory)
{
{
  hw_memory_chunk *chunk = NULL;
  hw_memory_chunk *chunk = NULL;
  memory_reg_spec *available = NULL;
  memory_reg_spec *available = NULL;
  int nr_available = 0;
  int nr_available = 0;
  int curr = 0;
  int curr = 0;
  int sizeof_available = 0;
  int sizeof_available = 0;
  /* determine the nr of available chunks */
  /* determine the nr of available chunks */
  chunk = hw_memory->heap;
  chunk = hw_memory->heap;
  nr_available = 0;
  nr_available = 0;
  while (chunk != NULL) {
  while (chunk != NULL) {
    if (chunk->available)
    if (chunk->available)
      nr_available += 1;
      nr_available += 1;
    ASSERT(chunk->next == NULL
    ASSERT(chunk->next == NULL
           || chunk->address < chunk->next->address);
           || chunk->address < chunk->next->address);
    ASSERT(chunk->next == NULL
    ASSERT(chunk->next == NULL
           || chunk->address + chunk->size == chunk->next->address);
           || chunk->address + chunk->size == chunk->next->address);
    chunk = chunk->next;
    chunk = chunk->next;
  }
  }
  /* now create the available struct */
  /* now create the available struct */
  ASSERT(nr_available > 0);
  ASSERT(nr_available > 0);
  sizeof_available = sizeof(memory_reg_spec) * nr_available;
  sizeof_available = sizeof(memory_reg_spec) * nr_available;
  available = zalloc(sizeof_available);
  available = zalloc(sizeof_available);
  chunk = hw_memory->heap;
  chunk = hw_memory->heap;
  curr = 0;
  curr = 0;
  while (chunk != NULL) {
  while (chunk != NULL) {
    if (chunk->available) {
    if (chunk->available) {
      available[curr].base = H2BE_cell(chunk->address);
      available[curr].base = H2BE_cell(chunk->address);
      available[curr].size = H2BE_cell(chunk->size);
      available[curr].size = H2BE_cell(chunk->size);
      curr += 1;
      curr += 1;
    }
    }
    chunk = chunk->next;
    chunk = chunk->next;
  }
  }
  /* update */
  /* update */
  device_set_array_property(me, "available", available, sizeof_available);
  device_set_array_property(me, "available", available, sizeof_available);
  zfree(available);
  zfree(available);
}
}
 
 
 
 
static void
static void
hw_memory_init_address(device *me)
hw_memory_init_address(device *me)
{
{
  hw_memory_device *hw_memory = (hw_memory_device*)device_data(me);
  hw_memory_device *hw_memory = (hw_memory_device*)device_data(me);
 
 
  /* free up any previous structures */
  /* free up any previous structures */
  {
  {
    hw_memory_chunk *curr_chunk = hw_memory->heap;
    hw_memory_chunk *curr_chunk = hw_memory->heap;
    hw_memory->heap = NULL;
    hw_memory->heap = NULL;
    while (curr_chunk != NULL) {
    while (curr_chunk != NULL) {
      hw_memory_chunk *dead_chunk = curr_chunk;
      hw_memory_chunk *dead_chunk = curr_chunk;
      curr_chunk = dead_chunk->next;
      curr_chunk = dead_chunk->next;
      dead_chunk->next = NULL;
      dead_chunk->next = NULL;
      zfree(dead_chunk);
      zfree(dead_chunk);
    }
    }
  }
  }
 
 
  /* attach memory regions according to the "reg" property */
  /* attach memory regions according to the "reg" property */
  {
  {
    int reg_nr;
    int reg_nr;
    reg_property_spec reg;
    reg_property_spec reg;
    for (reg_nr = 0;
    for (reg_nr = 0;
         device_find_reg_array_property(me, "reg", reg_nr, &reg);
         device_find_reg_array_property(me, "reg", reg_nr, &reg);
         reg_nr++) {
         reg_nr++) {
      int i;
      int i;
      /* check that the entry meets restrictions */
      /* check that the entry meets restrictions */
      for (i = 0; i < reg.address.nr_cells - 1; i++)
      for (i = 0; i < reg.address.nr_cells - 1; i++)
        if (reg.address.cells[i] != 0)
        if (reg.address.cells[i] != 0)
          device_error(me, "Only single celled addresses supported");
          device_error(me, "Only single celled addresses supported");
      for (i = 0; i < reg.size.nr_cells - 1; i++)
      for (i = 0; i < reg.size.nr_cells - 1; i++)
        if (reg.size.cells[i] != 0)
        if (reg.size.cells[i] != 0)
          device_error(me, "Only single celled sizes supported");
          device_error(me, "Only single celled sizes supported");
      /* attach the range */
      /* attach the range */
      device_attach_address(device_parent(me),
      device_attach_address(device_parent(me),
                            attach_raw_memory,
                            attach_raw_memory,
                            0 /*address space*/,
                            0 /*address space*/,
                            reg.address.cells[reg.address.nr_cells - 1],
                            reg.address.cells[reg.address.nr_cells - 1],
                            reg.size.cells[reg.size.nr_cells - 1],
                            reg.size.cells[reg.size.nr_cells - 1],
                            access_read_write_exec,
                            access_read_write_exec,
                            me);
                            me);
    }
    }
  }
  }
 
 
  /* create the initial `available memory' data structure */
  /* create the initial `available memory' data structure */
  if (device_find_property(me, "available") != NULL) {
  if (device_find_property(me, "available") != NULL) {
    hw_memory_chunk **curr_chunk = &hw_memory->heap;
    hw_memory_chunk **curr_chunk = &hw_memory->heap;
    int cell_nr;
    int cell_nr;
    unsigned_cell dummy;
    unsigned_cell dummy;
    int nr_cells = device_find_integer_array_property(me, "available", 0, &dummy);
    int nr_cells = device_find_integer_array_property(me, "available", 0, &dummy);
    if ((nr_cells % 2) != 0)
    if ((nr_cells % 2) != 0)
      device_error(me, "property \"available\" invalid - contains an odd number of cells");
      device_error(me, "property \"available\" invalid - contains an odd number of cells");
    for (cell_nr = 0;
    for (cell_nr = 0;
         cell_nr < nr_cells;
         cell_nr < nr_cells;
         cell_nr += 2) {
         cell_nr += 2) {
      hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk);
      hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk);
      device_find_integer_array_property(me, "available", cell_nr,
      device_find_integer_array_property(me, "available", cell_nr,
                                         &new_chunk->address);
                                         &new_chunk->address);
      device_find_integer_array_property(me, "available", cell_nr + 1,
      device_find_integer_array_property(me, "available", cell_nr + 1,
                                         &new_chunk->size);
                                         &new_chunk->size);
      new_chunk->available = 1;
      new_chunk->available = 1;
      *curr_chunk = new_chunk;
      *curr_chunk = new_chunk;
      curr_chunk = &new_chunk->next;
      curr_chunk = &new_chunk->next;
    }
    }
  }
  }
  else {
  else {
    hw_memory_chunk **curr_chunk = &hw_memory->heap;
    hw_memory_chunk **curr_chunk = &hw_memory->heap;
    int reg_nr;
    int reg_nr;
    reg_property_spec reg;
    reg_property_spec reg;
    for (reg_nr = 0;
    for (reg_nr = 0;
         device_find_reg_array_property(me, "reg", reg_nr, &reg);
         device_find_reg_array_property(me, "reg", reg_nr, &reg);
         reg_nr++) {
         reg_nr++) {
      hw_memory_chunk *new_chunk;
      hw_memory_chunk *new_chunk;
      new_chunk = ZALLOC(hw_memory_chunk);
      new_chunk = ZALLOC(hw_memory_chunk);
      new_chunk->address = reg.address.cells[reg.address.nr_cells - 1];
      new_chunk->address = reg.address.cells[reg.address.nr_cells - 1];
      new_chunk->size = reg.size.cells[reg.size.nr_cells - 1];
      new_chunk->size = reg.size.cells[reg.size.nr_cells - 1];
      new_chunk->available = 1;
      new_chunk->available = 1;
      *curr_chunk = new_chunk;
      *curr_chunk = new_chunk;
      curr_chunk = &new_chunk->next;
      curr_chunk = &new_chunk->next;
    }
    }
  }
  }
 
 
  /* initialize the alloc property for this device */
  /* initialize the alloc property for this device */
  hw_memory_set_available(me, hw_memory);
  hw_memory_set_available(me, hw_memory);
}
}
 
 
static void
static void
hw_memory_instance_delete(device_instance *instance)
hw_memory_instance_delete(device_instance *instance)
{
{
  return;
  return;
}
}
 
 
static int
static int
hw_memory_instance_claim(device_instance *instance,
hw_memory_instance_claim(device_instance *instance,
                         int n_stack_args,
                         int n_stack_args,
                         unsigned_cell stack_args[/*n_stack_args*/],
                         unsigned_cell stack_args[/*n_stack_args*/],
                         int n_stack_returns,
                         int n_stack_returns,
                         unsigned_cell stack_returns[/*n_stack_returns*/])
                         unsigned_cell stack_returns[/*n_stack_returns*/])
{
{
  hw_memory_device *hw_memory = device_instance_data(instance);
  hw_memory_device *hw_memory = device_instance_data(instance);
  device *me = device_instance_device(instance);
  device *me = device_instance_device(instance);
  int stackp = 0;
  int stackp = 0;
  unsigned_word alignment;
  unsigned_word alignment;
  unsigned_cell size;
  unsigned_cell size;
  unsigned_cell address;
  unsigned_cell address;
  hw_memory_chunk *chunk = NULL;
  hw_memory_chunk *chunk = NULL;
 
 
  /* get the alignment from the stack */
  /* get the alignment from the stack */
  if (n_stack_args < stackp + 1)
  if (n_stack_args < stackp + 1)
    device_error(me, "claim - incorrect number of arguments (alignment missing)");
    device_error(me, "claim - incorrect number of arguments (alignment missing)");
  alignment = stack_args[stackp];
  alignment = stack_args[stackp];
  stackp++;
  stackp++;
 
 
  /* get the size from the stack */
  /* get the size from the stack */
  {
  {
    int i;
    int i;
    int nr_cells = device_nr_size_cells(device_parent(me));
    int nr_cells = device_nr_size_cells(device_parent(me));
    if (n_stack_args < stackp + nr_cells)
    if (n_stack_args < stackp + nr_cells)
      device_error(me, "claim - incorrect number of arguments (size missing)");
      device_error(me, "claim - incorrect number of arguments (size missing)");
    for (i = 0; i < nr_cells - 1; i++) {
    for (i = 0; i < nr_cells - 1; i++) {
      if (stack_args[stackp] != 0)
      if (stack_args[stackp] != 0)
        device_error(me, "claim - multi-cell sizes not supported");
        device_error(me, "claim - multi-cell sizes not supported");
      stackp++;
      stackp++;
    }
    }
    size = stack_args[stackp];
    size = stack_args[stackp];
    stackp++;
    stackp++;
  }
  }
 
 
  /* get the address from the stack */
  /* get the address from the stack */
  {
  {
    int nr_cells = device_nr_address_cells(device_parent(me));
    int nr_cells = device_nr_address_cells(device_parent(me));
    if (alignment != 0) {
    if (alignment != 0) {
      if (n_stack_args != stackp) {
      if (n_stack_args != stackp) {
        if (n_stack_args == stackp + nr_cells)
        if (n_stack_args == stackp + nr_cells)
          DTRACE(memory, ("claim - extra address argument ignored\n"));
          DTRACE(memory, ("claim - extra address argument ignored\n"));
        else
        else
          device_error(me, "claim - incorrect number of arguments (optional addr)");
          device_error(me, "claim - incorrect number of arguments (optional addr)");
      }
      }
      address = 0;
      address = 0;
    }
    }
    else {
    else {
      int i;
      int i;
      if (n_stack_args != stackp + nr_cells)
      if (n_stack_args != stackp + nr_cells)
        device_error(me, "claim - incorrect number of arguments (addr missing)");
        device_error(me, "claim - incorrect number of arguments (addr missing)");
      for (i = 0; i < nr_cells - 1; i++) {
      for (i = 0; i < nr_cells - 1; i++) {
        if (stack_args[stackp] != 0)
        if (stack_args[stackp] != 0)
          device_error(me, "claim - multi-cell addresses not supported");
          device_error(me, "claim - multi-cell addresses not supported");
        stackp++;
        stackp++;
      }
      }
      address = stack_args[stackp];
      address = stack_args[stackp];
    }
    }
  }
  }
 
 
  /* check that there is space for the result */
  /* check that there is space for the result */
  if (n_stack_returns != 0
  if (n_stack_returns != 0
      && n_stack_returns != device_nr_address_cells(device_parent(me)))
      && n_stack_returns != device_nr_address_cells(device_parent(me)))
    device_error(me, "claim - invalid number of return arguments");
    device_error(me, "claim - invalid number of return arguments");
 
 
  /* find a chunk candidate, either according to address or alignment */
  /* find a chunk candidate, either according to address or alignment */
  if (alignment == 0) {
  if (alignment == 0) {
    chunk = hw_memory->heap;
    chunk = hw_memory->heap;
    while (chunk != NULL) {
    while (chunk != NULL) {
      if ((address + size) <= (chunk->address + chunk->size))
      if ((address + size) <= (chunk->address + chunk->size))
        break;
        break;
      chunk = chunk->next;
      chunk = chunk->next;
    }
    }
    if (chunk == NULL || address < chunk->address || !chunk->available)
    if (chunk == NULL || address < chunk->address || !chunk->available)
      device_error(me, "failed to allocate %ld bytes at 0x%lx",
      device_error(me, "failed to allocate %ld bytes at 0x%lx",
                   (unsigned long)size, (unsigned long)address);
                   (unsigned long)size, (unsigned long)address);
    DTRACE(memory, ("claim - address=0x%lx size=0x%lx\n",
    DTRACE(memory, ("claim - address=0x%lx size=0x%lx\n",
                    (unsigned long)address,
                    (unsigned long)address,
                    (unsigned long)size));
                    (unsigned long)size));
  }
  }
  else {
  else {
    /* adjust the alignment so that it is a power of two */
    /* adjust the alignment so that it is a power of two */
    unsigned_word align_mask = 1;
    unsigned_word align_mask = 1;
    while (align_mask < alignment && align_mask != 0)
    while (align_mask < alignment && align_mask != 0)
      align_mask <<= 1;
      align_mask <<= 1;
    if (align_mask == 0)
    if (align_mask == 0)
      device_error(me, "alignment 0x%lx is to large", (unsigned long)alignment);
      device_error(me, "alignment 0x%lx is to large", (unsigned long)alignment);
    align_mask -= 1;
    align_mask -= 1;
    /* now find an aligned chunk that fits */
    /* now find an aligned chunk that fits */
    chunk = hw_memory->heap;
    chunk = hw_memory->heap;
    while (chunk != NULL) {
    while (chunk != NULL) {
      address = ((chunk->address + align_mask) & ~align_mask);
      address = ((chunk->address + align_mask) & ~align_mask);
      if ((chunk->available)
      if ((chunk->available)
          && (chunk->address + chunk->size >= address + size))
          && (chunk->address + chunk->size >= address + size))
        break;
        break;
      chunk = chunk->next;
      chunk = chunk->next;
    }
    }
    if (chunk == NULL)
    if (chunk == NULL)
      device_error(me, "failed to allocate %ld bytes with alignment %ld",
      device_error(me, "failed to allocate %ld bytes with alignment %ld",
                   (unsigned long)size, (unsigned long)alignment);
                   (unsigned long)size, (unsigned long)alignment);
    DTRACE(memory, ("claim - size=0x%lx alignment=%ld (0x%lx), address=0x%lx\n",
    DTRACE(memory, ("claim - size=0x%lx alignment=%ld (0x%lx), address=0x%lx\n",
                    (unsigned long)size,
                    (unsigned long)size,
                    (unsigned long)alignment,
                    (unsigned long)alignment,
                    (unsigned long)alignment,
                    (unsigned long)alignment,
                    (unsigned long)address));
                    (unsigned long)address));
  }
  }
 
 
  /* break off a bit before this chunk if needed */
  /* break off a bit before this chunk if needed */
  ASSERT(address >= chunk->address);
  ASSERT(address >= chunk->address);
  if (address > chunk->address) {
  if (address > chunk->address) {
    hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
    hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
    /* insert a new chunk */
    /* insert a new chunk */
    next_chunk->next = chunk->next;
    next_chunk->next = chunk->next;
    chunk->next = next_chunk;
    chunk->next = next_chunk;
    /* adjust the address/size */
    /* adjust the address/size */
    next_chunk->address = address;
    next_chunk->address = address;
    next_chunk->size = chunk->address + chunk->size - next_chunk->address;
    next_chunk->size = chunk->address + chunk->size - next_chunk->address;
    next_chunk->available = 1;
    next_chunk->available = 1;
    chunk->size = next_chunk->address - chunk->address;
    chunk->size = next_chunk->address - chunk->address;
    /* make this new chunk the one to allocate */
    /* make this new chunk the one to allocate */
    chunk = next_chunk;
    chunk = next_chunk;
  }
  }
  ASSERT(address == chunk->address);
  ASSERT(address == chunk->address);
 
 
  /* break off a bit after this chunk if needed */
  /* break off a bit after this chunk if needed */
  ASSERT(address + size <= chunk->address + chunk->size);
  ASSERT(address + size <= chunk->address + chunk->size);
  if (address + size < chunk->address + chunk->size) {
  if (address + size < chunk->address + chunk->size) {
    hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
    hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
    /* insert it in to the list */
    /* insert it in to the list */
    next_chunk->next = chunk->next;
    next_chunk->next = chunk->next;
    chunk->next = next_chunk;
    chunk->next = next_chunk;
    /* adjust the address/size */
    /* adjust the address/size */
    next_chunk->address = address + size;
    next_chunk->address = address + size;
    next_chunk->size = chunk->address + chunk->size - next_chunk->address;
    next_chunk->size = chunk->address + chunk->size - next_chunk->address;
    next_chunk->available = 1;
    next_chunk->available = 1;
    chunk->size = next_chunk->address - chunk->address;
    chunk->size = next_chunk->address - chunk->address;
  }
  }
  ASSERT(address + size == chunk->address + chunk->size);
  ASSERT(address + size == chunk->address + chunk->size);
 
 
  /* now allocate/return it */
  /* now allocate/return it */
  chunk->available = 0;
  chunk->available = 0;
  hw_memory_set_available(device_instance_device(instance), hw_memory);
  hw_memory_set_available(device_instance_device(instance), hw_memory);
  if (n_stack_returns > 0) {
  if (n_stack_returns > 0) {
    int i;
    int i;
    for (i = 0; i < n_stack_returns - 1; i++)
    for (i = 0; i < n_stack_returns - 1; i++)
      stack_returns[i] = 0;
      stack_returns[i] = 0;
    stack_returns[n_stack_returns - 1] = address;
    stack_returns[n_stack_returns - 1] = address;
  }
  }
 
 
  return 0;
  return 0;
}
}
 
 
 
 
static int
static int
hw_memory_instance_release(device_instance *instance,
hw_memory_instance_release(device_instance *instance,
                           int n_stack_args,
                           int n_stack_args,
                           unsigned_cell stack_args[/*n_stack_args*/],
                           unsigned_cell stack_args[/*n_stack_args*/],
                           int n_stack_returns,
                           int n_stack_returns,
                           unsigned_cell stack_returns[/*n_stack_returns*/])
                           unsigned_cell stack_returns[/*n_stack_returns*/])
{
{
  hw_memory_device *hw_memory = device_instance_data(instance);
  hw_memory_device *hw_memory = device_instance_data(instance);
  device *me = device_instance_device(instance);
  device *me = device_instance_device(instance);
  unsigned_word length;
  unsigned_word length;
  unsigned_word address;
  unsigned_word address;
  int stackp = 0;
  int stackp = 0;
  hw_memory_chunk *chunk;
  hw_memory_chunk *chunk;
 
 
  /* get the length from the stack */
  /* get the length from the stack */
  {
  {
    int i;
    int i;
    int nr_cells = device_nr_size_cells(device_parent(me));
    int nr_cells = device_nr_size_cells(device_parent(me));
    if (n_stack_args < stackp + nr_cells)
    if (n_stack_args < stackp + nr_cells)
      device_error(me, "release - incorrect number of arguments (length missing)");
      device_error(me, "release - incorrect number of arguments (length missing)");
    for (i = 0; i < nr_cells - 1; i++) {
    for (i = 0; i < nr_cells - 1; i++) {
      if (stack_args[stackp] != 0)
      if (stack_args[stackp] != 0)
        device_error(me, "release - multi-cell length not supported");
        device_error(me, "release - multi-cell length not supported");
      stackp++;
      stackp++;
    }
    }
    length = stack_args[stackp];
    length = stack_args[stackp];
    stackp++;
    stackp++;
  }
  }
 
 
  /* get the address from the stack */
  /* get the address from the stack */
  {
  {
    int i;
    int i;
    int nr_cells = device_nr_address_cells(device_parent(me));
    int nr_cells = device_nr_address_cells(device_parent(me));
    if (n_stack_args != stackp + nr_cells)
    if (n_stack_args != stackp + nr_cells)
      device_error(me, "release - incorrect number of arguments (addr missing)");
      device_error(me, "release - incorrect number of arguments (addr missing)");
    for (i = 0; i < nr_cells - 1; i++) {
    for (i = 0; i < nr_cells - 1; i++) {
      if (stack_args[stackp] != 0)
      if (stack_args[stackp] != 0)
        device_error(me, "release - multi-cell addresses not supported");
        device_error(me, "release - multi-cell addresses not supported");
      stackp++;
      stackp++;
    }
    }
    address = stack_args[stackp];
    address = stack_args[stackp];
  }
  }
 
 
  /* returns ok */
  /* returns ok */
  if (n_stack_returns != 0)
  if (n_stack_returns != 0)
    device_error(me, "release - nonzero number of results");
    device_error(me, "release - nonzero number of results");
 
 
  /* try to free the corresponding memory chunk */
  /* try to free the corresponding memory chunk */
  chunk = hw_memory->heap;
  chunk = hw_memory->heap;
  while (chunk != NULL) {
  while (chunk != NULL) {
    if (chunk->address == address
    if (chunk->address == address
        && chunk->size == length) {
        && chunk->size == length) {
      /* an exact match */
      /* an exact match */
      if (chunk->available)
      if (chunk->available)
        device_error(me, "memory chunk 0x%lx (size 0x%lx) already available",
        device_error(me, "memory chunk 0x%lx (size 0x%lx) already available",
                     (unsigned long)address,
                     (unsigned long)address,
                     (unsigned long)length);
                     (unsigned long)length);
      else {
      else {
        /* free this chunk */
        /* free this chunk */
        DTRACE(memory, ("release - address=0x%lx, length=0x%lx\n",
        DTRACE(memory, ("release - address=0x%lx, length=0x%lx\n",
                        (unsigned long) address,
                        (unsigned long) address,
                        (unsigned long) length));
                        (unsigned long) length));
        chunk->available = 1;
        chunk->available = 1;
        break;
        break;
      }
      }
    }
    }
    else if (chunk->address >= address
    else if (chunk->address >= address
             && chunk->address + chunk->size <= address + length) {
             && chunk->address + chunk->size <= address + length) {
      /* a sub region */
      /* a sub region */
      if (!chunk->available) {
      if (!chunk->available) {
        DTRACE(memory, ("release - address=0x%lx, size=0x%lx within region 0x%lx length 0x%lx\n",
        DTRACE(memory, ("release - address=0x%lx, size=0x%lx within region 0x%lx length 0x%lx\n",
                        (unsigned long) chunk->address,
                        (unsigned long) chunk->address,
                        (unsigned long) chunk->size,
                        (unsigned long) chunk->size,
                        (unsigned long) address,
                        (unsigned long) address,
                        (unsigned long) length));
                        (unsigned long) length));
        chunk->available = 1;
        chunk->available = 1;
      }
      }
    }
    }
    chunk = chunk->next;
    chunk = chunk->next;
  }
  }
  if (chunk == NULL) {
  if (chunk == NULL) {
    printf_filtered("warning: released chunks within region 0x%lx..0x%lx\n",
    printf_filtered("warning: released chunks within region 0x%lx..0x%lx\n",
                    (unsigned long)address,
                    (unsigned long)address,
                    (unsigned long)(address + length - 1));
                    (unsigned long)(address + length - 1));
  }
  }
 
 
  /* check for the chance to merge two adjacent available memory chunks */
  /* check for the chance to merge two adjacent available memory chunks */
  chunk = hw_memory->heap;
  chunk = hw_memory->heap;
  while (chunk != NULL) {
  while (chunk != NULL) {
    if (chunk->available
    if (chunk->available
        && chunk->next != NULL && chunk->next->available) {
        && chunk->next != NULL && chunk->next->available) {
      /* adjacent */
      /* adjacent */
      hw_memory_chunk *delete = chunk->next;
      hw_memory_chunk *delete = chunk->next;
      ASSERT(chunk->address + chunk->size == delete->address);
      ASSERT(chunk->address + chunk->size == delete->address);
      chunk->size += delete->size;
      chunk->size += delete->size;
      chunk->next = delete->next;
      chunk->next = delete->next;
      zfree(delete);
      zfree(delete);
    }
    }
    else {
    else {
      chunk = chunk->next;
      chunk = chunk->next;
    }
    }
  }
  }
 
 
  /* update the corresponding property */
  /* update the corresponding property */
  hw_memory_set_available(device_instance_device(instance), hw_memory);
  hw_memory_set_available(device_instance_device(instance), hw_memory);
 
 
  return 0;
  return 0;
}
}
 
 
 
 
static device_instance_methods hw_memory_instance_methods[] = {
static device_instance_methods hw_memory_instance_methods[] = {
  { "claim", hw_memory_instance_claim },
  { "claim", hw_memory_instance_claim },
  { "release", hw_memory_instance_release },
  { "release", hw_memory_instance_release },
  { NULL, },
  { NULL, },
};
};
 
 
static device_instance_callbacks const hw_memory_instance_callbacks = {
static device_instance_callbacks const hw_memory_instance_callbacks = {
  hw_memory_instance_delete,
  hw_memory_instance_delete,
  NULL /*read*/, NULL /*write*/, NULL /*seek*/,
  NULL /*read*/, NULL /*write*/, NULL /*seek*/,
  hw_memory_instance_methods
  hw_memory_instance_methods
};
};
 
 
static device_instance *
static device_instance *
hw_memory_create_instance(device *me,
hw_memory_create_instance(device *me,
                          const char *path,
                          const char *path,
                          const char *args)
                          const char *args)
{
{
  return device_create_instance_from(me, NULL,
  return device_create_instance_from(me, NULL,
                                     device_data(me), /* nothing better */
                                     device_data(me), /* nothing better */
                                     path, args,
                                     path, args,
                                     &hw_memory_instance_callbacks);
                                     &hw_memory_instance_callbacks);
}
}
 
 
static device_callbacks const hw_memory_callbacks = {
static device_callbacks const hw_memory_callbacks = {
  { hw_memory_init_address, },
  { hw_memory_init_address, },
  { NULL, }, /* address */
  { NULL, }, /* address */
  { NULL, }, /* IO */
  { NULL, }, /* IO */
  { NULL, }, /* DMA */
  { NULL, }, /* DMA */
  { NULL, }, /* interrupt */
  { NULL, }, /* interrupt */
  { NULL, }, /* unit */
  { NULL, }, /* unit */
  hw_memory_create_instance,
  hw_memory_create_instance,
};
};
 
 
const device_descriptor hw_memory_device_descriptor[] = {
const device_descriptor hw_memory_device_descriptor[] = {
  { "memory", hw_memory_create, &hw_memory_callbacks },
  { "memory", hw_memory_create, &hw_memory_callbacks },
  { NULL },
  { NULL },
};
};
 
 
#endif /* _HW_MEMORY_C_ */
#endif /* _HW_MEMORY_C_ */
 
 

powered by: WebSVN 2.1.0

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