Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

memory.c

/*
 * $Id: memory.c,v 1.70 2009-02-13 10:47:46 vrsieh Exp $
 *
 * Copyright (C) 2003-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include "config.h"

/* Define it to get debug output of any access to that page range. */
#if 0
#define DEBUG_START     0xc0000
#define DEBUG_LENGTH    0x10000
#else
#undef DEBUG_START
#undef DEBUG_LENGTH
#endif

/*
 * Configure options
 */
/* Number of possible simultaneous faults. */
#define NFAULTS               16

#include <sys/types.h>
#include <sys/mman.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "glue-main.h"
#include "glue-shm.h"
#include "system.h"

#include "memory.h"

#define COMP "memory"

/*
 * Types
 */
struct cpssp {
      uint32_t *haddr[2];

      unsigned long mem_size[2];

      struct sig_cs *cs[2];

      struct fault {
            enum type {
                  UNUSED,
                  FLIP,
                  STUCK_AT_0,
                  STUCK_AT_1,
                  COUPLING
            } type;
            int active;
            unsigned int side;
            unsigned long addr;
            unsigned int bit;
            unsigned long addr2;
            unsigned int bit2;

            struct sig_boolean *sig;
      } fault[NFAULTS];

      /* eeprom component */
      #define NAME      spd_eeprom
      #define STATE
      #include "arch_philips_pcx8582X-2.c"
      #undef STATE
      #undef NAME
};


#define NAME            spd_eeprom
#define NAME_(x)  spd_eeprom_ ## x
#define BEHAVIOR
#include "arch_philips_pcx8582X-2.c"
#undef BEHAVIOR
#undef NAME_
#undef NAME

static unsigned char *
memory_access(struct cpssp *cpssp, unsigned int side, unsigned long addr)
{
      addr &= ~0xfffUL;
      assert(/* 0 <= addr && */ addr < cpssp->mem_size[side]);

00094       return (unsigned char *) cpssp->haddr[side] + addr;
}
00096 
static int
memory_readl(
00099       void *_cpssp,
      unsigned int side,
      uint32_t *valp,
      unsigned long addr
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned char *va;
      uint32_t lval;
      uint32_t lval2;
      unsigned int bit;
      unsigned int i;

      assert((addr & 3) == 0);

      /*
       * Check whether side is available.
       */
      if (cpssp->mem_size[side] == 0) {
            return -1;
      }

      addr &= cpssp->mem_size[side] - 1;

      assert(/* 0 <= addr && */ addr < cpssp->mem_size[side]);

      /*
       * Read word.
       */
      va = memory_access(cpssp, side, addr);

      lval = *(uint32_t *) (va + addr - (addr & ~0xfffUL));

      /*
       * Do fault injection.
       */
      for (i = 0; i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]); i++) {
            if (cpssp->fault[i].type != UNUSED
             && cpssp->fault[i].active
             && cpssp->fault[i].side == side
             && cpssp->fault[i].addr == addr) {
                  switch (cpssp->fault[i].type) {
                  case STUCK_AT_0:
                        /* Clear faulty bit. */
                        lval &= ~(1 << cpssp->fault[i].bit);
                        break;
                  case STUCK_AT_1:
                        /* Set faulty bit. */
                        lval |=  (1 << cpssp->fault[i].bit);
                        break;
                  case COUPLING:
                        /* Read faulty bit from coupled cell. */
                        memory_readl(cpssp, side, &lval2, cpssp->fault[i].addr2);
                        bit = (lval2 >> cpssp->fault[i].bit2) & 1;

                        lval &= ~(1 << cpssp->fault[i].bit);
                        lval |= bit << cpssp->fault[i].bit;
                        break;
                  default:
                        assert(0);
                  }
            }
      }

#ifdef DEBUG_START
      if (loglevel) {
            fprintf(stderr, "Reading %08lx from memory at %08lx\n",
                        (unsigned long) lval, 
                        (unsigned long) addr);
      }
#endif

      *valp = lval;
      return 0;
}

static int
memory_writel(
      void *_cpssp,
      unsigned int side,
      uint32_t val,
      unsigned long addr
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned char *va;
      unsigned int bit;
      uint32_t val2;
      unsigned int i;

      assert((addr & 3) == 0);

      /*
       * Check whether side is available.
       */
      if (cpssp->mem_size[side] == 0) {
            return -1;
      }

      addr &= cpssp->mem_size[side] - 1;

      assert(/* 0 <= addr && */ addr < cpssp->mem_size[side]);

      /*
       * Write word.
       */
      va = memory_access(cpssp, side, addr);

      *(uint32_t *) (va + addr - (addr & ~0xfffUL)) = val;

      /*
       * Do fault injection.
       */
      for (i = 0; i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]); i++) {
            if (cpssp->fault[i].type != UNUSED
             && cpssp->fault[i].active
             && cpssp->fault[i].side == side
             && cpssp->fault[i].addr == addr) {
                  switch (cpssp->fault[i].type) {
                  case STUCK_AT_0:
                  case STUCK_AT_1:
                        /* Nothing to do. */
                        break;
                  case COUPLING:
                        /* Change bit in coupled cell, too. */
                        bit = (val >> cpssp->fault[i].bit) & 1;

                        memory_readl(cpssp, side, &val2, cpssp->fault[i].addr2);
                        val2 &= ~(1 << cpssp->fault[i].bit2);
                        val2 |= bit << cpssp->fault[i].bit2;
                        memory_writel(cpssp, side, val2, cpssp->fault[i].addr2);
                        break;
                  default:
                        assert(0);
                  }
            }
      }

#ifdef DEBUG_START
      if (loglevel) {
            fprintf(stderr, "Writing %08lx to memory at %08lx\n",
                        (unsigned long) val, 
                        (unsigned long) addr);
      }
#endif

      return 0;
}

static int
memory_port(
      struct cpssp *cpssp,
      const char *port,
      enum type *typep,
      unsigned int *sidep,
      unsigned long *addrp,
      unsigned int *bitp,
      unsigned long *addr2p,
      unsigned int *bit2p
)
{
      char *port2;

      /* Get Fault Type */
      if (strncmp(port, "bitflip", strlen("bitflip")) == 0) {
            *typep = FLIP;
            port += strlen("bitflip");
      } else if (strncmp(port, "stuck_at_0", strlen("stuck_at_0")) == 0) {
            *typep = STUCK_AT_0;
            port += strlen("stuck_at_0");
      } else if (strncmp(port, "stuck_at_1", strlen("stuck_at_1")) == 0) {
            *typep = STUCK_AT_1;
            port += strlen("stuck_at_1");
      } else if (strncmp(port, "coupling", strlen("coupling")) == 0) {
            *typep = COUPLING;
            port += strlen("coupling");
      } else {
            return 1;
      }

      /* Skip / */
      if (*port == '/') {
            port++;
      } else {
            return 1;
      }

      /* Get Address */
      *addrp = strtoul(port, &port2, 0);
      port = port2;

      /* Skip / */
      if (*port == '/') {
            port++;
      } else {
            return 1;
      }

      /* Get Bit Number */
      *bitp = strtoul(port, &port2, 0);
      port = port2;

      *bitp += (*addrp & 3) * 8;
      *addrp &= ~3;

      if (*typep == COUPLING) {
            /* Skip / */
            if (*port == '/') {
                  port++;
            } else {
                  return 1;
            }

            /* Get Address */
            *addr2p = strtoul(port, &port2, 0);
            port = port2;

            /* Skip / */
            if (*port == '/') {
                  port++;
            } else {
                  return 1;
            }

            /* Get Bit Number */
            *bit2p = strtoul(port, &port2, 0);
            port = port2;

            *bit2p += (*addr2p & 3) * 8;
            *addr2p &= ~3;
      }

      if (*port != '\0') {
            return 1;
      }

      /* Get Side - FIXME */
      *sidep = *addrp / cpssp->mem_size[0];
      *addrp %= cpssp->mem_size[0];

      return 0;
}

static void
memory_fault_set(void *_cpssp, unsigned int i, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned int side;
      unsigned long addr;
      unsigned int bit;
      unsigned long addr2;
      unsigned int bit2;

      assert(cpssp->fault[i].type != UNUSED);

      side = cpssp->fault[i].side;
      addr = cpssp->fault[i].addr;
      bit = cpssp->fault[i].bit;
      addr2 = cpssp->fault[i].addr2;
      bit2 = cpssp->fault[i].bit2;

      if (cpssp->fault[i].type == FLIP) {
            if (val) {
                  uint32_t data;

                  memory_readl(cpssp, side, &data, addr);
                  data ^= 1 << bit;
                  memory_writel(cpssp, side, data, addr);
            }

      } else {
            cpssp->fault[i].active = val;

            sig_cs_unmap(cpssp->cs[side], cpssp, addr, 4);
            if (cpssp->fault[i].type == COUPLING
             && addr != addr2) {
                  sig_cs_unmap(cpssp->cs[side], cpssp, addr2, 4);
            }
      }
}

static void
memory_fault_set0(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 0, val);
}

static void
memory_fault_set1(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 1, val);
}

static void
memory_fault_set2(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 2, val);
}

static void
memory_fault_set3(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 3, val);
}

static void
memory_fault_set4(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 4, val);
}

static void
memory_fault_set5(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 5, val);
}

static void
memory_fault_set6(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 6, val);
}

static void
memory_fault_set7(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 7, val);
}

static void
memory_fault_set8(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 8, val);
}

static void
memory_fault_set9(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 9, val);
}

static void
memory_fault_set10(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 10, val);
}

static void
memory_fault_set11(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 11, val);
}

static void
memory_fault_set12(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 12, val);
}

static void
memory_fault_set13(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 13, val);
}

static void
memory_fault_set14(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 14, val);
}

static void
memory_fault_set15(void *_cpssp, unsigned int val)
{
      memory_fault_set(_cpssp, 15, val);
}
      
static void
memory_connect(void *_cpssp, const char *port, void *_sig)
{
      static const struct sig_boolean_funcs fault_funcs[] = {
            { .set = memory_fault_set0, },
            { .set = memory_fault_set1, },
            { .set = memory_fault_set2, },
            { .set = memory_fault_set3, },
            { .set = memory_fault_set4, },
            { .set = memory_fault_set5, },
            { .set = memory_fault_set6, },
            { .set = memory_fault_set7, },
            { .set = memory_fault_set8, },
            { .set = memory_fault_set9, },
            { .set = memory_fault_set10, },
            { .set = memory_fault_set11, },
            { .set = memory_fault_set12, },
            { .set = memory_fault_set13, },
            { .set = memory_fault_set14, },
            { .set = memory_fault_set15, },
      };
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      struct sig_boolean *sig = (struct sig_boolean *) _sig;
      enum type type;
      unsigned int side;
      unsigned long addr;
      unsigned int bit;
      unsigned long addr2;
      unsigned int bit2;
      unsigned int i;

      assert(sizeof(fault_funcs) / sizeof(fault_funcs[0])
                  == sizeof(cpssp->fault) / sizeof(cpssp->fault[0]));

      if (memory_port(_cpssp, port, &type,
                  &side, &addr, &bit, &addr2, &bit2)) {
            return;
      }

      /* Lookup Unused Entry */
      for (i = 0; ; i++) {
            assert(i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]));
            if (cpssp->fault[i].type == UNUSED) {
                  break;
            }
      }

      /* Add Entry */
      cpssp->fault[i].type = type;
      cpssp->fault[i].active = 0;
      cpssp->fault[i].side = side;
      cpssp->fault[i].addr = addr & ~0x3UL;
      cpssp->fault[i].bit = bit + (addr & 3) * 8;
      cpssp->fault[i].addr2 = addr2 & ~0x3UL;
      cpssp->fault[i].bit2 = bit2 + (addr2 & 3) * 8;

      cpssp->fault[i].sig = sig;

      sig_boolean_connect_in(cpssp->fault[i].sig, cpssp, &fault_funcs[i]);
}

static void
memory_disconnect(void *_cpssp, const char *port)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      enum type type;
      unsigned int side;
      unsigned long addr;
      unsigned int bit;
      unsigned long addr2;
      unsigned int bit2;
      unsigned int i;

      if (memory_port(_cpssp, port, &type,
                  &side, &addr, &bit, &addr2, &bit2)) {
            return;
      }

      /* Lookup Entry */
      for (i = 0; ; i++) {
            assert(i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]));
            if (cpssp->fault[i].type == type
             && cpssp->fault[i].side == side
             && cpssp->fault[i].addr == (addr & ~0x3UL)
             && cpssp->fault[i].bit == bit + (addr & 3) * 8
             && cpssp->fault[i].addr2 == (addr2 & ~0x3UL)
             && cpssp->fault[i].bit2 == bit2 + (addr2 & 3) * 8) {
                  /* Entry found. */
                  break;
            }
      }

      // sig_boolean_disconnect_in(cpssp->fault[i].sig, cpssp);

      /* Disable Entry */
      cpssp->fault[i].type = UNUSED;
}

static int
memory_read(
      void *_cpssp,
      unsigned int side,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      assert(! (addr & 3));

      return memory_readl(cpssp, side, valp, addr);
}

static int
memory_write(
      void *_cpssp,
      unsigned int side,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      uint32_t lval;

      assert(! (addr & 3));

      if (bs == 0xf) {
            lval = val;

      } else {
            if (memory_readl(cpssp, side, &lval, addr) < 0) {
                  return -1;
            }

            if ((bs >> 0) & 1) {
                  lval &= ~(0xff << 0);
                  lval |= val & (0xff << 0);
            }
            if ((bs >> 1) & 1) {
                  lval &= ~(0xff << 8);
                  lval |= val & (0xff << 8);
            }
            if ((bs >> 2) & 1) {
                  lval &= ~(0xff << 16);
                  lval |= val & (0xff << 16);
            }
            if ((bs >> 3) & 1) {
                  lval &= ~(0xff << 24);
                  lval |= val & (0xff << 24);
            }
      }

      if (memory_writel(cpssp, side, lval, addr & ~0x3UL) < 0) {
            return -1;
      }

      return 0;
}

static int
memory_map(
      void *_cpssp,
      unsigned int side,
      unsigned long addr,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned long haddr;
      unsigned long laddr;
      unsigned long start;
      unsigned long end;
      unsigned int i;

      /*
       * Check whether side is available.
       */
      if (cpssp->mem_size[side] == 0) {
            return -1;
      }

      laddr = addr & ~0xfffUL & (cpssp->mem_size[side] - 1);
      haddr = addr & ~0xfffUL & ~(cpssp->mem_size[side] - 1);

      assert(/* 0 <= laddr && */ laddr < cpssp->mem_size[side]);

      /*
       * Check for debug/faulty pages.
       */
      start = 0;
      end = cpssp->mem_size[side];

#ifdef DEBUG_START
      /* Check for debug pages. */
      if (laddr < DEBUG_START) {
            if (DEBUG_START < end) {
                  /* Addressing range below debug page. */
                  end = DEBUG_START;
            }
      } else if (DEBUG_START + DEBUG_LENGTH <= laddr) {
            if (start <= DEBUG_START) {
                  /* Addressing range above debug page. */
                  start = DEBUG_START + DEBUG_LENGTH;
            }
      } else {
            /* Addressing debug page. */
            *haddr_mr_p =
            *haddr_mw_p = NULL;
            return 0;
      }
#endif

      /* Check for faulty pages. */
      for (i = 0; i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]); i++) {
            unsigned long badpage;

            if (cpssp->fault[i].type == UNUSED
             || ! cpssp->fault[i].active
             || cpssp->fault[i].side != side) {
                  continue;
            }

            badpage = cpssp->fault[i].addr & ~0xfffUL;

            if (laddr < badpage) {
                  if (badpage < end) {
                        /* Addressing range below bad page. */
                        end = badpage;
                  }
            } else if (badpage + 0x1000 <= laddr) {
                  if (start <= badpage) {
                        /* Addressing range above bad page. */
                        start = badpage + 0x1000;
                  }
            } else {
                  /* Addressing bad page. */
                  *haddr_mr_p = NULL;
                  *haddr_mw_p = NULL;
                  return 0;
            }
      }

      *haddr_mr_p =
      *haddr_mw_p = ((char *) cpssp->haddr[side] + laddr);
      return 0;
}

static int
memory_0_read(void *_cpssp, uint32_t addr, unsigned int bs, uint32_t *valp)
{
      return memory_read(_cpssp, 0, addr, bs, valp);
}

static int
memory_0_write(void *_cpssp, uint32_t addr, unsigned int bs, uint32_t val)
{
      return memory_write(_cpssp, 0, addr, bs, val);
}

static int
memory_0_map(
      void *_cpssp,
      unsigned long addr,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p
)
{
      return memory_map(_cpssp, 0, addr, len, haddr_mr_p, haddr_mw_p);
}

static int
memory_1_read(void *_cpssp, uint32_t addr, unsigned int bs, uint32_t *valp)
{
      return memory_read(_cpssp, 1, addr, bs, valp);
}

static int
memory_1_write(void *_cpssp, uint32_t addr, unsigned int bs, uint32_t val)
{
      return memory_write(_cpssp, 1, addr, bs, val);
}

static int
memory_1_map(
      void *_cpssp,
      unsigned long addr,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p
)
{
      return memory_map(_cpssp, 1, addr, len, haddr_mr_p, haddr_mw_p);
}

static void
memory_id0_set(void *_cpssp, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      spd_eeprom_a0_set(cpssp, val);
}

static void
memory_id1_set(void *_cpssp, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      spd_eeprom_a1_set(cpssp, val);
}

static void
memory_id2_set(void *_cpssp, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      spd_eeprom_a2_set(cpssp, val);
}

static unsigned long
sim_log2(unsigned long x)
{
      unsigned int res;

      assert(x != 0);

      for (res = 0; x != 1; res++) {
            x >>= 1;
      }

      return res;
}

static void
memory_generic_fault(
      struct cpssp *cpssp,
      unsigned int active,
      enum type type,
      unsigned int side,
      unsigned long addr,
      unsigned int bit,
      unsigned long addr2,
      unsigned int bit2
)
{
      unsigned int i;

      if (active) {
            /* Lookup Unused Entry */
            for (i = 0; ; i++) {
                  assert(i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]));
                  if (cpssp->fault[i].type == UNUSED) {
                        break;
                  }
            }

            /* Add new entry. */
            cpssp->fault[i].type = type;
            cpssp->fault[i].active = 1;
            cpssp->fault[i].side = side;
            cpssp->fault[i].addr = addr & ~0x3UL;
            cpssp->fault[i].bit = bit + (addr & 3) * 8;
            cpssp->fault[i].addr2 = addr2 & ~0x3UL;
            cpssp->fault[i].bit2 = bit2 + (addr2 & 3) * 8;

            /* Must re-map page(s). */
            sig_cs_unmap(cpssp->cs[side], cpssp, addr & ~0x3UL, 4);
            if (type == COUPLING
             && (addr & ~0x3UL) != (addr2 & ~0x3UL)) {
                  sig_cs_unmap(cpssp->cs[side], cpssp, addr2 & ~0x3UL, 4);
            }

      } else {
            /* Lookup Entry */
            for (i = 0; ; i++) {
                  assert(i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]));
                  if (cpssp->fault[i].type == type
                   && cpssp->fault[i].active
                   && cpssp->fault[i].side == side
                   && cpssp->fault[i].addr == (addr & ~0x3UL)
                   && cpssp->fault[i].bit == bit + (addr & 3) * 8
                   && cpssp->fault[i].addr2 == (addr2 & ~0x3UL)
                   && cpssp->fault[i].bit2 == bit2 + (addr2 & 3) * 8) {
                        /* Entry found. */
                        break;
                  }
            }

            cpssp->fault[i].type = UNUSED;

            /* Must re-map page(s). */
            sig_cs_unmap(cpssp->cs[side], cpssp, addr & ~0x3UL, 4);
            if (type == COUPLING
             && (addr & ~0x3UL) != (addr2 & ~0x3UL)) {
                  sig_cs_unmap(cpssp->cs[side], cpssp, addr2 & ~0x3UL, 4);
            }
      }
}

static void
memory_bitflip(
      void *_cpssp,
      unsigned long long loc0,
      unsigned long long loc1,
      unsigned int val
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned int side;
      unsigned long address;
      unsigned int bit;

      bit = loc0 % 8; loc0 /= 8;
      address = loc0 % cpssp->mem_size[0]; loc0 /= cpssp->mem_size[0];
      side = loc0;

      memory_readl(cpssp, side, &val, address & ~0x3);

      val ^= 1 << ((address & 3) * 8 + bit);

      memory_writel(cpssp, side, val, address & ~0x3);
}

static void
memory_stuck_at_0(
      void *_cpssp,
      unsigned long long loc0,
      unsigned long long loc1,
      unsigned int val
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned int side;
      unsigned long address;
      unsigned int bit;

      bit = loc0 % 8; loc0 /= 8;
      address = loc0 % cpssp->mem_size[0]; loc0 /= cpssp->mem_size[0];
      side = loc0;
      memory_generic_fault(cpssp, val, STUCK_AT_0, side, address, bit, 0, 0);
}

static void
memory_stuck_at_1(
      void *_cpssp,
      unsigned long long loc0,
      unsigned long long loc1,
      unsigned int val
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned int side;
      unsigned long address;
      unsigned int bit;

      bit = loc0 % 8; loc0 /= 8;
      address = loc0 % cpssp->mem_size[0]; loc0 /= cpssp->mem_size[0];
      side = loc0;
      memory_generic_fault(cpssp, val, STUCK_AT_1, side, address, bit, 0, 0);
}

static void
memory_coupling(
      void *_cpssp,
      unsigned long long loc0,
      unsigned long long loc1,
      unsigned int val
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      unsigned int side0;
      unsigned long address0;
      unsigned int bit0;
      unsigned int side1;
      unsigned long address1;
      unsigned int bit1;

      bit0 = loc0 % 8; loc0 /= 8;
      address0 = loc0 % cpssp->mem_size[0]; loc0 /= cpssp->mem_size[0];
      side0 = loc0;
      bit1 = loc1 % 8; loc1 /= 8;
      address1 = loc1 % cpssp->mem_size[0]; loc1 /= cpssp->mem_size[0];
      side1 = loc1;
      assert(side0 == side1);
      memory_generic_fault(cpssp, val, COUPLING,
                  side0, address0, bit0, address1, bit1);
}

static void
memory_stop_transaction(void *_cpssp)
{
        struct cpssp *cpssp = (struct cpssp *) _cpssp;

        spd_eeprom_stop_transaction(cpssp);
}

static void
memory_read_byte(void *_cpssp, unsigned char *val)
{
        struct cpssp *cpssp = (struct cpssp *) _cpssp;

        spd_eeprom_read_byte(cpssp, val);
}

static bool
memory_write_byte(void *_cpssp, unsigned char val)
{
        struct cpssp *cpssp = (struct cpssp *) _cpssp;

        return spd_eeprom_write_byte(cpssp, val);
}

static bool
memory_ack_addr(void *_cpssp, unsigned char addr)
{
        struct cpssp *cpssp = (struct cpssp *) _cpssp;

        return spd_eeprom_ack_addr(cpssp, addr);
}

static void
memory_eeprom_init(
      struct cpssp *cpssp, 
      unsigned int nr, 
      struct sig_i2c_bus *i2cbus
)
{
      static const struct sig_i2c_bus_funcs spd_funcs = {
            .ack_addr = memory_ack_addr,
            .stop_transaction = memory_stop_transaction,
            .read_byte = memory_read_byte,
            .write_byte = memory_write_byte,
      };
      static unsigned char contents[256] = {
            /* 0x00: Number of bytes in SPD EEPROM. */
            0x80, /* -> 128 bytes used */
            /* 0x01: Size of EEPROM in bytes. */
            0x08, /* 256 bytes. */
            /* 0x02: Type of memory. */
            0x02, /* EDO. */
            /* 0x03: Number of address bits for row. */
            0x00,
            /* 0x04: Number of address bits for column. */
            0x00,
            /* 0x05: Number of Module Rows */
            1, /* FIXME VOSSI */
            /* 0x06: Module Data Width (Low Byte) */
            64, /* FIXME VOSSI */
            /* 0x07: Module Data Width (High Byte) */
            0, /* FIXME VOSSI */
            /* 0x08: SDRAM module signal voltage interface */
            0,
            /* 0x09: SDRAM cycle time (highest CAS latency) */
            0,
            /* 0x0a: SDRAM access time from clock */
            0,
            /* 0x0b: Module Configration Type */
            0, /* No parity, no ECC, no ... */
            /* 0x0c */
            0,
            /* 0x0d: SDRAM Width (Primary SDRAM). */
            64,
            /* 0x0e: Error Checking SDRAM Width */
            0, /* Undefined */ /* FIXME VOSSI */
            /* 0x10: SDRAM device attributes, burst length supported */
            0,
            /* 0x11: SDRAM Device Attributes, Number of Banks on 
             *       SDRAM Device*/
            0,
            /* 0x12: SDRAM Device Attributes, CAS Latency */
            0x7f,
            /* 0x13: SDRAM Device Attributes, CS Latency */
            0,
            /* 0x14: SDRAM Device Attributes, WE Latency */
            0,
            /* 0x15: SDRAM Module Attributes */
                  /* bit 7: TBD */
                  /* bit 6: Redundant Row Addr */
                  /* bit 5: Differential Clock Input */
                  /* bit 4: Registered DQMB Inputs */
                  /* bit 3: Buffered DQMB Inputs */
                  /* bit 2: On-Card PLL (Clock) */
                  /* bit 1: Registered Address/Control Inputs */
                  /* bit 0: Buffered Address/Control Inputs */
            0,
            /* 0x16: SDRAM Device Attributes, general */
            0,
            /* 0x17: SDRAM Cycle time (2nd highest CAS latency) */
            (4 << 4) | (5 << 0), /* 4.5ns */
            /* 0x18: SDRAM Access from Clock (2nd highest CAS latency) */
            (4 << 4) | (5 << 0), /* 4.5ns */
            /* ... */
      };

      sig_i2c_bus_connect_cooked(i2cbus, cpssp, &spd_funcs);

      /* sanitize defaults a little bit more */

      /* 0x03: Number of address bits for row. */
      contents[0x03] = sim_log2(cpssp->mem_size[0]) / 2;
      /* 0x04: Number of address bits for column. */
      contents[0x04] = sim_log2(cpssp->mem_size[0]) 
                  - sim_log2(cpssp->mem_size[0]) / 2;
      /* 0x11: SDRAM Device Attributes, Number of Banks on 
       *       SDRAM Device*/
      contents[0x11] = (cpssp->mem_size[1] == 0) ? 1 : 2;

      spd_eeprom_init(cpssp, contents);
}

void
memory_init(
      unsigned int nr,
      struct sig_manage *manage,
      struct sig_mem_bus *port_conn,
      struct sig_fault *fault_bitflip,
      struct sig_fault *fault_stuck_at_0,
      struct sig_fault *fault_stuck_at_1,
      struct sig_fault *fault_coupling
)
{
      static const struct sig_manage_funcs manage_funcs = {
            .connect = memory_connect,
            .disconnect = memory_disconnect,
      };
      static const struct sig_cs_funcs funcs0 = {
            .read = memory_0_read,
            .write      = memory_0_write,
            .map  = memory_0_map,
      };
      static const struct sig_cs_funcs funcs1 = {
            .read = memory_1_read,
            .write      = memory_1_write,
            .map  = memory_1_map,
      };
      static const struct sig_boolean_funcs id0_funcs = {
            .set = memory_id0_set,
      };
      static const struct sig_boolean_funcs id1_funcs = {
            .set = memory_id1_set,
      };
      static const struct sig_boolean_funcs id2_funcs = {
            .set = memory_id2_set,
      };
      static const struct sig_fault_funcs bitflip_funcs = {
            .set = memory_bitflip,
      };
      static const struct sig_fault_funcs stuck_at_0_funcs = {
            .set = memory_stuck_at_0,
      };
      static const struct sig_fault_funcs stuck_at_1_funcs = {
            .set = memory_stuck_at_1,
      };
      static const struct sig_fault_funcs coupling_funcs = {
            .set = memory_coupling,
      };
      struct cpssp *cpssp;
      unsigned int i;

      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      cpssp->haddr[0] = shm_map("memory0.ram", nr, cpssp->mem_size[0], 0);
      cpssp->haddr[1] = shm_map("memory1.ram", nr, cpssp->mem_size[1], 0);

      cpssp->cs[0] = port_conn->cs0;
      cpssp->cs[1] = port_conn->cs1;

      sig_manage_connect(manage, cpssp, &manage_funcs);

      sig_cs_connect(cpssp->cs[0], cpssp, &funcs0);
      sig_cs_connect(cpssp->cs[1], cpssp, &funcs1);

      sig_boolean_connect_in(port_conn->id0, cpssp, &id0_funcs);
      sig_boolean_connect_in(port_conn->id1, cpssp, &id1_funcs);
      sig_boolean_connect_in(port_conn->id2, cpssp, &id2_funcs);

      sig_fault_connect(fault_bitflip, cpssp, &bitflip_funcs);
      sig_fault_connect(fault_stuck_at_0, cpssp, &stuck_at_0_funcs);
      sig_fault_connect(fault_stuck_at_1, cpssp, &stuck_at_1_funcs);
      sig_fault_connect(fault_coupling, cpssp, &coupling_funcs);

      for (i = 0; i < sizeof(cpssp->fault) / sizeof(cpssp->fault[0]); i++) {
            cpssp->fault[i].type = UNUSED;
      }

      memory_eeprom_init(cpssp, nr, port_conn->i2cbus);
}

void
memory_create(unsigned int nr, const char *name, const char *size)
{
      struct cpssp *cpssp;
      unsigned long size0;
      unsigned long size1;

      shm_create(COMP, nr, sizeof(*cpssp));
      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      if (size == NULL) {
            size0 = 32;
      } else {
            size0 = strtoul(size, NULL, 0);
      }
      if (size0 <= 128) {
            size1 = 0;
      } else {
            size0 /= 2;
            size1 = size0;
      }

      size0 *= 1024*1024;
      size1 *= 1024*1024;

      assert(size0 ==   1 * 1024*1024
          || size0 ==   2 * 1024*1024
          || size0 ==   4 * 1024*1024
          || size0 ==   8 * 1024*1024
          || size0 ==  16 * 1024*1024
          || size0 ==  32 * 1024*1024
          || size0 ==  64 * 1024*1024
          || size0 == 128 * 1024*1024);
      assert(size1 == 0
          || size1 == size0);

      cpssp->mem_size[0] = size0;
      cpssp->mem_size[1] = size1;

      shm_create("memory0.ram", nr, size0);
      shm_create("memory1.ram", nr, size1);

      shm_unmap(cpssp, sizeof(*cpssp));
}

void
memory_destroy(unsigned int nr)
{
      struct cpssp *cpssp;

      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      shm_destroy("memory1.ram", nr);
      shm_destroy("memory0.ram", nr);

      shm_unmap(cpssp, sizeof(*cpssp));
      shm_destroy(COMP, nr);
}

Generated by  Doxygen 1.6.0   Back to index