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

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc2/] [or1ksim/] [cpu/] [common/] [abstract.c] - Rev 1557

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

/* abstract.c -- Abstract entities
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* Abstract memory and routines that go with this. I need to
add all sorts of other abstract entities. Currently we have
only memory. */
 
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
 
#include "config.h"
 
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
 
#include "port.h"
 
#include "arch.h"
#include "parse.h"
#include "abstract.h"
#include "sim-config.h"
#include "labels.h"
#include "except.h"
#include "debug_unit.h"
#include "opcode/or32.h"
#include "spr_defs.h"
#include "execute.h"
#include "sprs.h"
#include "support/profile.h"
#include "dmmu.h"
#include "immu.h"
#include "dcache_model.h"
#include "icache_model.h"
#include "debug.h"
#include "stats.h"
 
#if DYNAMIC_EXECUTION
#include "dyn_rec.h"
#endif
 
extern char *disassembled;
 
/* Pointer to memory area descriptions that are assigned to individual
   peripheral devices. */
struct dev_memarea *dev_list;
 
/* Temporary variable to increase speed.  */
struct dev_memarea *cur_area;
 
/* Pointer to memory controller device descriptor.  */
struct dev_memarea *mc_area = NULL;
 
/* These are set by mmu if cache inhibit bit is set for current acces.  */
int data_ci, insn_ci;
 
/* Virtual address of current access. */
static oraddr_t cur_vadd;
 
/* Read functions */
uint32_t eval_mem_32_inv(oraddr_t, void *);
uint16_t eval_mem_16_inv(oraddr_t, void *);
uint8_t eval_mem_8_inv(oraddr_t, void *);
uint32_t eval_mem_32_inv_direct(oraddr_t, void *);
uint16_t eval_mem_16_inv_direct(oraddr_t, void *);
uint8_t eval_mem_8_inv_direct(oraddr_t, void *);
 
/* Write functions */
void set_mem_32_inv(oraddr_t, uint32_t, void *);
void set_mem_16_inv(oraddr_t, uint16_t, void *);
void set_mem_8_inv(oraddr_t, uint8_t, void *);
void set_mem_32_inv_direct(oraddr_t, uint32_t, void *);
void set_mem_16_inv_direct(oraddr_t, uint16_t, void *);
void set_mem_8_inv_direct(oraddr_t, uint8_t, void *);
 
/* Calculates bit mask to fit the data */
static unsigned int bit_mask (uint32_t data) {
  int i = 0;
  data--;
  while (data >> i)
    data |= 1 << i++;
  return data;
}
 
/* Register read and write function for a memory area.
   addr is inside the area, if addr & addr_mask == addr_compare
   (used also by peripheral devices like 16450 UART etc.) */
struct dev_memarea *register_memoryarea_mask(oraddr_t addr_mask,
                                             oraddr_t addr_compare,
                                             uint32_t size, unsigned mc_dev)
{
  struct dev_memarea **pptmp;
  unsigned int size_mask = bit_mask (size);
  int found_error = 0;
  addr_compare &= addr_mask;
 
  debug(5, "addr & %"PRIxADDR" == %"PRIxADDR" to %"PRIxADDR", size %08"PRIx32"\n",
        addr_mask, addr_compare, addr_compare | bit_mask (size), size);
  /* Go to the end of the list. */
  for(pptmp = &dev_list; *pptmp; pptmp = &(*pptmp)->next)
    if (((addr_compare >= (*pptmp)->addr_compare) &&
         (addr_compare < (*pptmp)->addr_compare + (*pptmp)->size)) ||
        ((addr_compare + size > (*pptmp)->addr_compare) &&
         (addr_compare < (*pptmp)->addr_compare + (*pptmp)->size))) {
      if (!found_error) {
        fprintf (stderr, "ERROR: Overlapping memory area(s):\n");
        fprintf (stderr, "\taddr & %"PRIxADDR" == %"PRIxADDR" to %"PRIxADDR
                         ", size %08"PRIx32"\n",
                 addr_mask, addr_compare, addr_compare | bit_mask (size), size);
      }
      found_error = 1;
      fprintf (stderr, "and\taddr & %"PRIxADDR" == %"PRIxADDR" to %"PRIxADDR
                       ", size %08"PRIx32"\n",
               (*pptmp)->addr_mask, (*pptmp)->addr_compare,
               (*pptmp)->addr_compare | (*pptmp)->size_mask, (*pptmp)->size);
    }
 
  if (found_error)
    exit (-1);
 
  cur_area = *pptmp = (struct dev_memarea *)malloc(sizeof(struct dev_memarea));
 
  if (mc_dev)
    mc_area = *pptmp;
 
  (*pptmp)->addr_mask = addr_mask;
  (*pptmp)->addr_compare = addr_compare;
  (*pptmp)->size = size;
  (*pptmp)->size_mask = size_mask;
  (*pptmp)->log = NULL;
  (*pptmp)->valid = 1;
  (*pptmp)->next = NULL;
 
  return *pptmp;
}
 
/* Register read and write function for a memory area.   
   Memory areas should be aligned. Memory area is rounded up to
   fit the nearest 2^n aligment.
   (used also by peripheral devices like 16450 UART etc.) 
   If mc_dev is 1, this device will be checked first for a match
   and will be accessed in case of overlaping memory areas.
   Only one device can have this set to 1 (used for memory controller) */
struct dev_memarea *reg_mem_area(oraddr_t addr, uint32_t size, unsigned mc_dev,
                                 struct mem_ops *ops)
{
  unsigned int size_mask = bit_mask (size);
  unsigned int addr_mask = ~size_mask;
  struct dev_memarea *mem;
 
  mem = register_memoryarea_mask(addr_mask, addr & addr_mask, size_mask + 1,
                                 mc_dev);
 
  memcpy(&mem->ops, ops, sizeof(struct mem_ops));
  memcpy(&mem->direct_ops, ops, sizeof(struct mem_ops));
 
  if(!ops->readfunc32) {
    mem->ops.readfunc32 = eval_mem_32_inv;
    mem->direct_ops.readfunc32 = eval_mem_32_inv_direct;
    mem->direct_ops.read_dat32 = mem;
  }
  if(!ops->readfunc16) {
    mem->ops.readfunc16 = eval_mem_16_inv;
    mem->direct_ops.readfunc16 = eval_mem_16_inv_direct;
    mem->direct_ops.read_dat16 = mem;
  }
  if(!ops->readfunc8) {
    mem->ops.readfunc8 = eval_mem_8_inv;
    mem->direct_ops.readfunc8 = eval_mem_8_inv_direct;
    mem->direct_ops.read_dat8 = mem;
  }
 
  if(!ops->writefunc32) {
    mem->ops.writefunc32 = set_mem_32_inv;
    mem->direct_ops.writefunc32 = set_mem_32_inv_direct;
    mem->direct_ops.write_dat32 = mem;
  }
  if(!ops->writefunc16) {
    mem->ops.writefunc16 = set_mem_16_inv;
    mem->direct_ops.writefunc16 = set_mem_16_inv_direct;
    mem->direct_ops.write_dat16 = mem;
  }
  if(!ops->writefunc8) {
    mem->ops.writefunc8 = set_mem_8_inv;
    mem->direct_ops.writefunc8 = set_mem_8_inv_direct;
    mem->direct_ops.write_dat8 = mem;
  }
 
  if(!ops->writeprog8) {
    mem->ops.writeprog8 = mem->ops.writefunc8;
    mem->ops.writeprog8_dat = mem->ops.write_dat8;
  }
 
  if(!ops->writeprog32) {
    mem->ops.writeprog32 = mem->ops.writefunc32;
    mem->ops.writeprog32_dat = mem->ops.write_dat32;
  }
 
  if(ops->log) {
    if(!(mem->log = fopen(ops->log, "w")))
      PRINTF("ERR: Unable to open %s to log memory acesses to\n", ops->log);
  }
 
  return mem;
}
 
/* Check if access is to registered area of memory. */
inline struct dev_memarea *verify_memoryarea(oraddr_t addr)
{
  struct dev_memarea *ptmp;
 
  /* Check memory controller space first */
  if (mc_area && (addr & mc_area->addr_mask) == (mc_area->addr_compare & mc_area->addr_mask))
    return cur_area = mc_area;
 
  /* Check cached value */
  if (cur_area && (addr & cur_area->addr_mask) == (cur_area->addr_compare & cur_area->addr_mask))
    return cur_area;
 
  /* When mc is enabled, we must check valid also, otherwise we assume it is nonzero */
  /* Check list of registered devices. */
  for(ptmp = dev_list; ptmp; ptmp = ptmp->next)
    if ((addr & ptmp->addr_mask) == (ptmp->addr_compare & ptmp->addr_mask) && ptmp->valid)
      return cur_area = ptmp;
  return cur_area = NULL;
}
 
/* Sets the valid bit (Used only by memory controllers) */
void set_mem_valid(struct dev_memarea *mem, int valid)
{
  mem->valid = valid;
}
 
/* Adjusts the read and write delays for the memory area pointed to by mem. */
void adjust_rw_delay(struct dev_memarea *mem, int delayr, int delayw)
{
  mem->ops.delayr = delayr;
  mem->ops.delayw = delayw;
}
 
uint8_t eval_mem_8_inv(oraddr_t memaddr, void *dat)
{
  except_handle(EXCEPT_BUSERR, cur_vadd);
  return 0;
}
 
uint16_t eval_mem_16_inv(oraddr_t memaddr, void *dat)
{
  except_handle(EXCEPT_BUSERR, cur_vadd);
  return 0;
}
 
uint32_t eval_mem_32_inv(oraddr_t memaddr, void *dat)
{
  except_handle(EXCEPT_BUSERR, cur_vadd);
  return 0;
}
 
void set_mem_8_inv(oraddr_t memaddr, uint8_t val, void *dat)
{
  except_handle(EXCEPT_BUSERR, cur_vadd);
}
 
void set_mem_16_inv(oraddr_t memaddr, uint16_t val, void *dat)
{
  except_handle(EXCEPT_BUSERR, cur_vadd);
}
 
void set_mem_32_inv(oraddr_t memaddr, uint32_t val, void *dat)
{
  except_handle(EXCEPT_BUSERR, cur_vadd);
}
 
uint8_t eval_mem_8_inv_direct(oraddr_t memaddr, void *dat)
{
  struct dev_memarea *mem = dat;
 
  PRINTF("ERROR: Invalid 8-bit direct read from memory %"PRIxADDR"\n",
         mem->addr_compare | memaddr);
  return 0;
}
 
uint16_t eval_mem_16_inv_direct(oraddr_t memaddr, void *dat)
{
  struct dev_memarea *mem = dat;
 
  PRINTF("ERROR: Invalid 16-bit direct read from memory %"PRIxADDR"\n",
         mem->addr_compare | memaddr);
  return 0;
}
 
uint32_t eval_mem_32_inv_direct(oraddr_t memaddr, void *dat)
{
  struct dev_memarea *mem = dat;
 
  PRINTF("ERROR: Invalid 32-bit direct read from memory %"PRIxADDR"\n",
         mem->addr_compare | memaddr);
  return 0;
}
 
void set_mem_8_inv_direct(oraddr_t memaddr, uint8_t val, void *dat)
{
  struct dev_memarea *mem = dat;
 
  PRINTF("ERROR: Invalid 32-bit direct write to memory %"PRIxADDR"\n",
         mem->addr_compare | memaddr);
}
 
void set_mem_16_inv_direct(oraddr_t memaddr, uint16_t val, void *dat)
{
  struct dev_memarea *mem = dat;
 
  PRINTF("ERROR: Invalid 16-bit direct write to memory %"PRIxADDR"\n",
         mem->addr_compare | memaddr);
}
 
void set_mem_32_inv_direct(oraddr_t memaddr, uint32_t val, void *dat)
{
  struct dev_memarea *mem = dat;
 
  PRINTF("ERROR: Invalid 32-bit direct write to memory %"PRIxADDR"\n",
         mem->addr_compare | memaddr);
}
 
/* For cpu accesses
 *
 * NOTE: This function _is_ only called from eval_mem32 below and
 * {i,d}c_simulate_read.  _Don't_ call it from anywere else.
 */
inline uint32_t evalsim_mem32(oraddr_t memaddr, oraddr_t vaddr)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    runtime.sim.mem_cycles += mem->ops.delayr;
    return mem->ops.readfunc32(memaddr & mem->size_mask, mem->ops.read_dat32);
  } else {
    PRINTF("EXCEPTION: read out of memory (32-bit access to %"PRIxADDR")\n",
           memaddr);
    except_handle(EXCEPT_BUSERR, vaddr);
  }
 
  return 0;
}
 
/* For cpu accesses
 *
 * NOTE: This function _is_ only called from eval_mem16 below and
 * {i,d}c_simulate_read.  _Don't_ call it from anywere else.
 */
inline uint16_t evalsim_mem16(oraddr_t memaddr, oraddr_t vaddr)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    runtime.sim.mem_cycles += mem->ops.delayr;
    return mem->ops.readfunc16(memaddr & mem->size_mask, mem->ops.read_dat16);
  } else {
    PRINTF("EXCEPTION: read out of memory (16-bit access to %"PRIxADDR")\n",
           memaddr);
    except_handle(EXCEPT_BUSERR, vaddr);
  }
 
  return 0;
}
 
/* For cpu accesses
 *
 * NOTE: This function _is_ only called from eval_mem8 below and
 * {i,d}c_simulate_read.  _Don't_ call it from anywere else.
 */
inline uint8_t evalsim_mem8(oraddr_t memaddr, oraddr_t vaddr)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    runtime.sim.mem_cycles += mem->ops.delayr;
    return mem->ops.readfunc8(memaddr & mem->size_mask, mem->ops.read_dat8);
  } else {
    PRINTF("EXCEPTION: read out of memory (8-bit access to %"PRIxADDR")\n",
           memaddr);
    except_handle(EXCEPT_BUSERR, vaddr);
  }
 
  return 0;
}
 
/* Returns 32-bit values from mem array. Big endian version.
 *
 * STATISTICS OK (only used for cpu_access, that is architectural access)
 */
uint32_t eval_mem32(oraddr_t memaddr,int* breakpoint)
{
  uint32_t temp;
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_32 | MPROF_READ);
 
  if (memaddr & 3) {
    except_handle (EXCEPT_ALIGN, memaddr);
    return 0;
  }
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */
 
  phys_memaddr = dmmu_translate(memaddr, 0);
  if (except_pending)
    return 0;
 
  if (config.dc.enabled) 
    temp = dc_simulate_read(phys_memaddr, memaddr, 4);
  else
    temp = evalsim_mem32(phys_memaddr, memaddr);
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadData,temp);  /* MM170901 */
 
  return temp;
}
 
/* for simulator accesses, the ones that cpu wouldn't do
 *
 * STATISTICS OK
 */
uint32_t eval_direct32(oraddr_t memaddr, int through_mmu, int through_dc)
{
  oraddr_t phys_memaddr;
  struct dev_memarea *mem;
 
  if (memaddr & 3) {
    PRINTF("%s:%d %s(): ERR unaligned access\n", __FILE__, __LINE__, __FUNCTION__); 
    return 0;
  }
 
  phys_memaddr = memaddr;
 
  if (through_mmu)
    phys_memaddr = peek_into_dtlb(memaddr, 0, through_dc);
 
  if (through_dc) 
    return dc_simulate_read(phys_memaddr, memaddr, 4);
  else {
    if((mem = verify_memoryarea(phys_memaddr)))
      return mem->direct_ops.readfunc32(phys_memaddr & mem->size_mask,
                                        mem->direct_ops.read_dat32);
    else
      PRINTF("ERR: 32-bit read out of memory area: %"PRIxADDR" (physical: %"
             PRIxADDR"\n", memaddr, phys_memaddr);
  }
 
  return 0;
}
 
 
/* Returns 32-bit values from mem array. Big endian version.
 *
 * STATISTICS OK (only used for cpu_access, that is architectural access)
 */
uint32_t eval_insn(oraddr_t memaddr, int* breakpoint)
{
  uint32_t temp;
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_32 | MPROF_FETCH);
//  memaddr = simulate_ic_mmu_fetch(memaddr);
 
  phys_memaddr = memaddr;
#if !(DYNAMIC_EXECUTION)
  phys_memaddr = immu_translate(memaddr);
 
  if (except_pending)
    return 0;
#endif
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr);
 
  if (config.ic.enabled) 
    temp = ic_simulate_fetch(phys_memaddr, memaddr);
  else
    temp = evalsim_mem32(phys_memaddr, memaddr);
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadData,temp);
  return temp;
}
 
/* Returns 32-bit values from mem array. Big endian version.
 *
 * STATISTICS OK
 */
uint32_t eval_insn_direct(oraddr_t memaddr, int through_mmu)
{
  if(through_mmu)
    memaddr = peek_into_itlb(memaddr);
 
  return eval_direct32(memaddr, 0, 0);
}
 
 
/* Returns 16-bit values from mem array. Big endian version.
 *
 * STATISTICS OK (only used for cpu_access, that is architectural access)
 */
uint16_t eval_mem16(oraddr_t memaddr,int* breakpoint)
{
  uint16_t temp;
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_16 | MPROF_READ);
 
  if (memaddr & 1) {
    except_handle (EXCEPT_ALIGN, memaddr);
    return 0;
  }
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */
 
  phys_memaddr = dmmu_translate(memaddr, 0);
  if (except_pending)
    return 0;
 
  if (config.dc.enabled) 
    temp = dc_simulate_read(phys_memaddr, memaddr, 2);
  else
    temp = evalsim_mem16(phys_memaddr, memaddr);
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadData,temp);  /* MM170901 */
 
  return temp;
}
 
/* for simulator accesses, the ones that cpu wouldn't do
 * 
 * STATISTICS OK.
 */
uint16_t eval_direct16(oraddr_t memaddr, int through_mmu, int through_dc)
{
  oraddr_t phys_memaddr;
  struct dev_memarea *mem;
 
  if (memaddr & 1) {
    PRINTF("%s:%d %s(): ERR unaligned access\n", __FILE__, __LINE__, __FUNCTION__); 
    return 0;
  }
 
  phys_memaddr = memaddr;
 
  if (through_mmu)
    phys_memaddr = peek_into_dtlb(memaddr, 0, through_dc);
 
  if (through_dc) 
    return dc_simulate_read(phys_memaddr, memaddr, 2);
  else {
    if((mem = verify_memoryarea(phys_memaddr)))
      return mem->direct_ops.readfunc16(phys_memaddr & mem->size_mask,
                                        mem->direct_ops.read_dat16);
    else
      PRINTF("ERR: 16-bit read out of memory area: %"PRIxADDR" (physical: %"
             PRIxADDR"\n", memaddr, phys_memaddr);
  }
 
  return 0;
}
 
/* Returns 8-bit values from mem array. 
 *
 * STATISTICS OK (only used for cpu_access, that is architectural access)
 */
uint8_t eval_mem8(oraddr_t memaddr,int* breakpoint)
{
  uint8_t temp;
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_8 | MPROF_READ);
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr);  /* 28/05/01 CZ */
 
  phys_memaddr = dmmu_translate(memaddr, 0);
  if (except_pending)
    return 0;
 
  if (config.dc.enabled) 
    temp = dc_simulate_read(phys_memaddr, memaddr, 1);
  else
    temp = evalsim_mem8(phys_memaddr, memaddr);
 
  if (config.debug.enabled)
    *breakpoint += CheckDebugUnit(DebugLoadData,temp);  /* MM170901 */
  return temp;
}
 
/* for simulator accesses, the ones that cpu wouldn't do
 *
 * STATISTICS OK.
 */
uint8_t eval_direct8(oraddr_t memaddr, int through_mmu, int through_dc)
{
  oraddr_t phys_memaddr;
  struct dev_memarea *mem;
 
  phys_memaddr = memaddr;
 
  if (through_mmu)
    phys_memaddr = peek_into_dtlb(memaddr, 0, through_dc);
 
  if (through_dc) 
    return dc_simulate_read(phys_memaddr, memaddr, 1);
  else {
    if((mem = verify_memoryarea(phys_memaddr)))
      return mem->direct_ops.readfunc8(phys_memaddr & mem->size_mask,
                                       mem->direct_ops.read_dat8);
    else
      PRINTF("ERR: 8-bit read out of memory area: %"PRIxADDR" (physical: %"
             PRIxADDR"\n", memaddr, phys_memaddr);
  }
 
  return 0;
}
 
/* For cpu accesses
 *
 * NOTE: This function _is_ only called from set_mem32 below and
 * dc_simulate_write.  _Don't_ call it from anywere else.
 */
inline void setsim_mem32(oraddr_t memaddr, oraddr_t vaddr, uint32_t value)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    cur_vadd = vaddr;
    runtime.sim.mem_cycles += mem->ops.delayw;
    mem->ops.writefunc32(memaddr & mem->size_mask, value, mem->ops.write_dat32);
#if DYNAMIC_EXECUTION
    dyn_checkwrite(memaddr);
#endif
  } else {
    PRINTF("EXCEPTION: write out of memory (32-bit access to %"PRIxADDR")\n",
           memaddr);
    except_handle(EXCEPT_BUSERR, vaddr);
  }
}
 
/* For cpu accesses
 *
 * NOTE: This function _is_ only called from set_mem16 below and
 * dc_simulate_write.  _Don't_ call it from anywere else.
 */
inline void setsim_mem16(oraddr_t memaddr, oraddr_t vaddr, uint16_t value)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    cur_vadd = vaddr;
    runtime.sim.mem_cycles += mem->ops.delayw;
    mem->ops.writefunc16(memaddr & mem->size_mask, value, mem->ops.write_dat16);
#if DYNAMIC_EXECUTION
    dyn_checkwrite(memaddr);
#endif
  } else {
    PRINTF("EXCEPTION: write out of memory (16-bit access to %"PRIxADDR")\n",
           memaddr);
    except_handle(EXCEPT_BUSERR, vaddr);
  }
}
 
/* For cpu accesses
 *
 * NOTE: This function _is_ only called from set_mem8 below and
 * dc_simulate_write.  _Don't_ call it from anywere else.
 */
inline void setsim_mem8(oraddr_t memaddr, oraddr_t vaddr, uint8_t value)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    cur_vadd = vaddr;
    runtime.sim.mem_cycles += mem->ops.delayw;
    mem->ops.writefunc8(memaddr & mem->size_mask, value, mem->ops.write_dat8);
#if DYNAMIC_EXECUTION
    dyn_checkwrite(memaddr);
#endif
  } else {
    PRINTF("EXCEPTION: write out of memory (8-bit access to %"PRIxADDR")\n",
           memaddr);
    except_handle(EXCEPT_BUSERR, vaddr);
  }
}
 
/* Set mem, 32-bit. Big endian version. 
 *
 * STATISTICS OK. (the only suspicious usage is in sim-cmd.c,
 *                 where this instruction is used for patching memory,
 *                 wether this is cpu or architectual access is yet to 
 *                 be decided)
 */
void set_mem32(oraddr_t memaddr, uint32_t value, int* breakpoint)
{
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_32 | MPROF_WRITE);
 
  if (memaddr & 3) {
    except_handle (EXCEPT_ALIGN, memaddr);
    return;
  }
 
  phys_memaddr = dmmu_translate(memaddr, 1);;
  /* If we produced exception don't set anything */
  if (except_pending)
    return;
 
  if (config.debug.enabled) {
    *breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr);  /* 28/05/01 CZ */
    *breakpoint += CheckDebugUnit(DebugStoreData,value);
  }
 
  if(config.dc.enabled)
    dc_simulate_write(phys_memaddr, memaddr, value, 4); 
  else
    setsim_mem32(phys_memaddr, memaddr, value);
 
  if (cur_area && cur_area->log)
    fprintf (cur_area->log, "[%"PRIxADDR"] -> write %08"PRIx32"\n", memaddr,
             value);
}
 
/* 
 * STATISTICS NOT OK.
 */
void set_direct32(oraddr_t memaddr, uint32_t value, int through_mmu,
                  int through_dc)
{
  oraddr_t phys_memaddr;
  struct dev_memarea *mem;
 
  if (memaddr & 3) {
    PRINTF("%s:%d %s(): ERR unaligned access\n", __FILE__, __LINE__, __FUNCTION__);
    return;
  }
 
  phys_memaddr = memaddr;
 
  if (through_mmu) {
    /* 0 - no write access, we do not want a DPF exception do we ;)
     */
    phys_memaddr = peek_into_dtlb(memaddr, 1, through_dc);
  }
 
  if(through_dc)
    dc_simulate_write(memaddr, memaddr, value, 4); 
  else {
    if((mem = verify_memoryarea(phys_memaddr)))
      mem->direct_ops.writefunc32(phys_memaddr & mem->size_mask, value,
                                  mem->direct_ops.write_dat32);
    else
      PRINTF("ERR: 32-bit write out of memory area: %"PRIxADDR" (physical: %"
             PRIxADDR")\n", memaddr, phys_memaddr);
  }
 
  if (cur_area && cur_area->log)
    fprintf (cur_area->log, "[%"PRIxADDR"] -> DIRECT write %08"PRIx32"\n",
             memaddr, value);
}
 
 
/* Set mem, 16-bit. Big endian version. */
 
void set_mem16(oraddr_t memaddr, uint16_t value, int* breakpoint)
{
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_16 | MPROF_WRITE);
 
  if (memaddr & 1) {
    except_handle (EXCEPT_ALIGN, memaddr);
    return;
  }
 
  phys_memaddr = dmmu_translate(memaddr, 1);;
  /* If we produced exception don't set anything */
  if (except_pending)
    return;
 
  if (config.debug.enabled) {
    *breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr);  /* 28/05/01 CZ */
    *breakpoint += CheckDebugUnit(DebugStoreData,value);
  }
 
  if(config.dc.enabled)
    dc_simulate_write(phys_memaddr, memaddr, value, 2);
  else
    setsim_mem16(phys_memaddr, memaddr, value);
 
  if (cur_area && cur_area->log)
    fprintf (cur_area->log, "[%"PRIxADDR"] -> write %04"PRIx16"\n", memaddr,
             value);
}
 
/*
 * STATISTICS NOT OK.
 */
void set_direct16(oraddr_t memaddr, uint16_t value, int through_mmu,
                  int through_dc)
{
  oraddr_t phys_memaddr;
  struct dev_memarea *mem;
 
  if (memaddr & 1) {
    PRINTF("%s:%d %s(): ERR unaligned access\n", __FILE__, __LINE__, __FUNCTION__);
    return;
  }
 
  phys_memaddr = memaddr;
 
  if (through_mmu) {
    /* 0 - no write access, we do not want a DPF exception do we ;)
     */
    phys_memaddr = peek_into_dtlb(memaddr, 0, through_dc);
  }
 
  if(through_dc)
    dc_simulate_write(memaddr, memaddr, value, 2);
  else {
    if((mem = verify_memoryarea(phys_memaddr)))
      mem->direct_ops.writefunc16(phys_memaddr & mem->size_mask, value,
                                  mem->direct_ops.write_dat16);
    else
      PRINTF("ERR: 16-bit write out of memory area: %"PRIxADDR" (physical: %"
             PRIxADDR"\n", memaddr, phys_memaddr);
  }
 
  if (cur_area && cur_area->log)
    fprintf (cur_area->log, "[%"PRIxADDR"] -> DIRECT write %04"PRIx16"\n",
             memaddr, value);
}
 
/* Set mem, 8-bit. */
void set_mem8(oraddr_t memaddr, uint8_t value, int* breakpoint)
{
  oraddr_t phys_memaddr;
 
  if (config.sim.mprofile)
    mprofile (memaddr, MPROF_8 | MPROF_WRITE);
 
  phys_memaddr = memaddr;
 
  phys_memaddr = dmmu_translate(memaddr, 1);;
  /* If we produced exception don't set anything */
  if (except_pending) return;
 
  if (config.debug.enabled) {
    *breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr);  /* 28/05/01 CZ */
    *breakpoint += CheckDebugUnit(DebugStoreData,value);
  }
 
  if(config.dc.enabled)
    dc_simulate_write(phys_memaddr, memaddr, value, 1); 
  else
    setsim_mem8(phys_memaddr, memaddr, value);
 
  if (cur_area && cur_area->log)
    fprintf (cur_area->log, "[%"PRIxADDR"] -> write %02"PRIx8"\n", memaddr,
             value);
}
 
/*
 * STATISTICS NOT OK.
 */
void set_direct8(oraddr_t memaddr, uint8_t value, int through_mmu,
                 int through_dc)
{
  oraddr_t phys_memaddr;
  struct dev_memarea *mem;
 
  phys_memaddr = memaddr;
 
  if (through_mmu) {
    /* 0 - no write access, we do not want a DPF exception do we ;)
     */
    phys_memaddr = peek_into_dtlb(memaddr, 0, through_dc);
  }
 
  if(through_dc)
    dc_simulate_write(phys_memaddr, memaddr, value, 1);
  else {
    if((mem = verify_memoryarea(phys_memaddr)))
      mem->direct_ops.writefunc8(phys_memaddr & mem->size_mask, value,
                                 mem->direct_ops.write_dat8);
    else
      PRINTF("ERR: 8-bit write out of memory area: %"PRIxADDR" (physical: %"
             PRIxADDR"\n", memaddr, phys_memaddr);
  }
 
  if (cur_area && cur_area->log)
    fprintf (cur_area->log, "[%"PRIxADDR"] -> DIRECT write %02"PRIx8"\n",
             memaddr, value);
}
 
 
/* set_program32 - same as set_direct32, but it also writes to memory that is
 *                 non-writeable to the rest of the sim.  Used to do program
 *                 loading.
 */
void set_program32(oraddr_t memaddr, uint32_t value)
{
  struct dev_memarea *mem;
 
  if(memaddr & 3) {
    PRINTF("%s(): ERR unaligned 32-bit program write\n", __FUNCTION__);
    return;
  }
 
  if((mem = verify_memoryarea(memaddr))) {
    mem->ops.writeprog32(memaddr & mem->size_mask, value,
                         mem->ops.writeprog32_dat);
  } else
    PRINTF("ERR: 32-bit program load out of memory area: %"PRIxADDR"\n",
           memaddr);
}
 
/* set_program8 - same as set_direct8, but it also writes to memory that is
 *                non-writeable to the rest of the sim.  Used to do program
 *                loading.
 */
void set_program8(oraddr_t memaddr, uint8_t value)
{
  struct dev_memarea *mem;
 
  if((mem = verify_memoryarea(memaddr))) {
    mem->ops.writeprog8(memaddr & mem->size_mask, value,
                        mem->ops.writeprog8_dat);
  } else
    PRINTF("ERR: 8-bit program load out of memory area: %"PRIxADDR"\n",
           memaddr);
}
 
void dumpmemory(oraddr_t from, oraddr_t to, int disasm, int nl)
{
  oraddr_t i, j;
  struct label_entry *tmp;
  int ilen = disasm ? 4 : 16;
 
  for(i = from; i < to; i += ilen) {
    PRINTF("%"PRIxADDR": ", i);
    for (j = 0; j < ilen;) {
      if (!disasm) {
        tmp = NULL;
        if (verify_memoryarea(i + j)) {
          struct label_entry *entry;
          entry = get_label(i + j);
          if (entry)
            PRINTF("(%s)", entry->name);
          PRINTF("%02"PRIx8" ", eval_direct8(i + j, 0, 0));
        } else PRINTF("XX ");  
        j++;
      } else {
        uint32_t _insn = eval_direct32(i, 0, 0);
        int index = insn_decode (_insn);
        int len = insn_len (index);
 
        tmp = NULL;
        if (verify_memoryarea(i + j)) {
          struct label_entry *entry;
          entry = get_label(i + j);
          if (entry)
            PRINTF("(%s)", entry->name);
 
          PRINTF(": %08"PRIx32" ", _insn);
          if (index >= 0) {
            disassemble_insn (_insn);
            PRINTF(" %s", disassembled);
          } else
            PRINTF("<invalid>");
        } else PRINTF("XXXXXXXX");
        j += len;
      }
    }
    if (nl)
      PRINTF ("\n");
  }
}
 
/* Closes files, etc. */
 
void done_memory_table (void)
{
  struct dev_memarea *ptmp;
 
  /* Check list of registered devices. */
  for(ptmp = dev_list; ptmp; ptmp = ptmp->next) {
    if (ptmp->log)
      fclose (ptmp->log);
  }
}
 
/* Displays current memory configuration */
 
void memory_table_status (void)
{
  struct dev_memarea *ptmp;
 
  /* Check list of registered devices. */
  for(ptmp = dev_list; ptmp; ptmp = ptmp->next) {
    PRINTF ("addr & %"PRIxADDR" == %"PRIxADDR" to %"PRIxADDR", size %"PRIx32"\n",
      ptmp->addr_mask, ptmp->addr_compare, ptmp->addr_compare | bit_mask (ptmp->size),
      ptmp->size);
    PRINTF ("\t");
    if (ptmp->ops.delayr >= 0)
      PRINTF ("read delay = %i cycles, ", ptmp->ops.delayr);
    else
      PRINTF ("reads not possible, ");
 
    if (ptmp->ops.delayw >= 0)
      PRINTF ("write delay = %i cycles", ptmp->ops.delayw);
    else
      PRINTF ("writes not possible");
 
    if (ptmp->log)
      PRINTF (", (logged)\n");
    else
      PRINTF ("\n");
  }
}
 
/* Outputs time in pretty form to dest string */
 
char *generate_time_pretty (char *dest, long time_ps)
{
  int exp3 = 0;
  if (time_ps) {
    while ((time_ps % 1000) == 0) {
      time_ps /= 1000;
      exp3++;
    }
  }
  sprintf (dest, "%li%cs", time_ps, "pnum"[exp3]);
  return dest;
}
 

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

powered by: WebSVN 2.1.0

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