/*
 * Memory location handled specially by a hw element
 */

/*cl_memloc::cl_memloc(t_addr addr):
  cl_base()
{
  address= addr;
  hws= new cl_list(2, 2);
  hws->init();
}*/

/*cl_memloc::~cl_memloc(void)
{
  hws->disconn_all();
  delete hws;
}*/

/*ulong
cl_memloc::read(class cl_mem *mem)
{
  uchar ret= 0;
  class cl_hw *hw;

  if (!hws ||
      hws->count == 0)
    return(ret);
  if ((hw= (class cl_hw *)(hws->at(0))))
    ret= hw->read(mem, address);
  return(ret);
}*/

/*void
cl_memloc::write(class cl_mem *mem, t_addr addr, t_mem *val)
{
  class cl_hw *hw;
  int i;

  if (!hws)
    return;
  for (i= 0; i < hws->count; i++)
    {
      hw= (class cl_hw *)hws->at(0);
      hw->write(mem, addr, val);
    }
}*/


/* Sorted collection of memory locations */

/*cl_memloc_coll::cl_memloc_coll(void):
  cl_sorted_list(2, 2)
{
  Duplicates= false;
}*/

/*const void *
cl_memloc_coll::key_of(const void *item)
{
  return(&(((class cl_memloc *)item)->address));
}*/

/*int
cl_memloc_coll::compare(void *key1, void *key2)
{
  if (*(long*)key1 > *(long*)key2)
    return(1);
  else
    if (*(long*)key1 < *(long*)key2)
      return(-1);
    else
      return(0);
}*/

/*class cl_memloc *
cl_memloc_coll::get_loc(t_addr address)
{
  t_index i;

  if (search(&address, i))
    return((class cl_memloc*)(at(i)));
  return(0);
}*/


/*
 * Memory
 ******************************************************************************
 */

/*
 * Bitmap
 */

/*cl_bitmap::cl_bitmap(t_addr asize):
  cl_base()
{
  map= (uchar*)malloc(size= asize/(8*SIZEOF_CHAR));
  memset(map, 0, size);
}

cl_bitmap::~cl_bitmap(void)
{
  free(map);
}

void
cl_bitmap::set(t_addr pos)
{
  int i;

  if ((i= pos/(8*SIZEOF_CHAR)) < size)
    map[i]|= (1 << (pos & ((8*SIZEOF_CHAR)-1)));
}

void
cl_bitmap::clear(t_addr pos)
{
  int i;

  if ((i= pos/(8*SIZEOF_CHAR)) < size)
    map[i]&= ~(1 << (pos & ((8*SIZEOF_CHAR)-1)));
}

bool
cl_bitmap::get(t_addr pos)
{
  return(map[pos/(8*SIZEOF_CHAR)] & (1 << (pos & ((8*SIZEOF_CHAR)-1))));
}

bool
cl_bitmap::empty(void)
{
  int i;

  for (i= 0; i < size && map[i] == 0; i++) ;
  return(i == size);
}*/

/*
 * Special memory for code (ROM)
 */

/*cl_rom::cl_rom(t_addr asize, int awidth, class cl_uc *auc):
  cl_mem(MEM_ROM, get_id_string(mem_classes, MEM_ROM), asize, awidth, auc)
{
  bp_map= new cl_bitmap(asize);
  inst_map= new cl_bitmap(asize);
}

cl_rom::~cl_rom(void)
{
  delete bp_map;
  delete inst_map;
}*/


cl_mem::cl_mem(enum mem_class atype, char *aclass_name,
	       t_addr asize, int awidth, class cl_uc *auc):
  cl_guiobj()
{
  int i;
  
  uc= auc;
  type= atype;
  class_name= aclass_name;
  width= awidth;
  size= asize;
  mem= 0;
  for (i= width, mask= 0; i; i--)
    mask= (mask<<1) | 1;
  if (width == 0 ||
      size == 0)
    mem= 0;
  else if (width <= 8)
    mem= (TYPE_UBYTE *)malloc(size);
  else if (width <= 16)
    mem= (TYPE_UWORD *)malloc(size*sizeof(TYPE_WORD));
  else
    mem= (TYPE_UDWORD *)malloc(size*sizeof(TYPE_DWORD));
  //read_locs= new cl_memloc_coll();
  //write_locs= new cl_memloc_coll();
  dump_finished= 0;
  addr_format= data_format= 0;
}

cl_mem::~cl_mem(void)
{
  if (mem)
    free(mem);
  if (addr_format)
    free(addr_format);
  if (data_format)
    free(data_format);
  //delete read_locs;
  //delete write_locs;
}

int
cl_mem::init(void)
{
  t_addr i;

  addr_format= (char *)malloc(10);
  sprintf(addr_format, "0x%%0%dx",
	  size-1<=0xf?1:
	  (size-1<=0xff?2:
	   (size-1<=0xfff?3:
	    (size-1<=0xffff?4:
	     (size-1<=0xfffff?5:
	      (size-1<=0xffffff?6:12))))));
  data_format= (char *)malloc(10);
  sprintf(data_format, "%%0%dx", width/4+((width%4)?1:0));

  for (i= 0; i < size; i++)
    set(i, (type==MEM_ROM)?(-1):0);
  return(0);
}

const char *
cl_mem::id_string(void)
{
  const char *s= get_id_string(mem_ids, type);

  return(s?s:"NONE");
}

t_mem
cl_mem::read(t_addr addr)
{
  //class cl_memloc *loc;

  if (addr >= size)
    {
      //FIXME
      fprintf(stderr, "Address 0x%06x is over 0x%06x\n",
	      (int)addr, (int)size);
      return(0);
    }
  /*if ((loc= read_locs->get_loc(addr)))
    return(loc->read(this));*/
  if (width <= 8)
    return((((TYPE_UBYTE*)mem)[addr])&mask);
  else if (width <= 16)
    return((((TYPE_UWORD*)mem)[addr])&mask);
  else
    return((((TYPE_UDWORD*)mem)[addr])&mask);
}

t_mem
cl_mem::get(t_addr addr)
{
  if (addr >= size)
    return(0);
  if (width <= 8)
    return((((TYPE_UBYTE*)mem)[addr])&mask);
  else if (width <= 16)
    return((((TYPE_UWORD*)mem)[addr])&mask);
  else
    return((((TYPE_UDWORD*)mem)[addr])&mask);
}


/*
 * Modify memory location
 */

/* Write calls callbacks of HW elements */

t_mem
cl_mem::write(t_addr addr, t_mem val)
{
  /*  class cl_memloc *loc;

  if (addr >= size)
    return;
  if ((loc= write_locs->get_loc(addr)))
    loc->write(this, addr, val);
  if (width <= 8)
    ((TYPE_UBYTE*)mem)[addr]= (*val)&mask;
  else if (width <= 16)
    ((TYPE_UWORD*)mem)[addr]= (*val)&mask;
  else
  ((TYPE_UDWORD*)mem)[addr]= (*val)&mask;*/
  fprintf(stderr, "FIXME cl_mem::write(0x%06x, 0x%04x)\n",
	  (int)addr, (int)val);
  return(0);
}

/* Set doesn't call callbacks */

void
cl_mem::set(t_addr addr, t_mem val)
{
  if (addr >= size)
    return;
  if (width <= 8)
    ((TYPE_UBYTE*)mem)[addr]= val&mask;
  else if (width <= 16)
    ((TYPE_UWORD*)mem)[addr]= val&mask;
  else
    ((TYPE_UDWORD*)mem)[addr]= val&mask;
}

t_mem
cl_mem::add(t_addr addr, long what)
{
  if (addr >= size)
    return(0);
  if (width <= 8)
    {
      ((TYPE_UBYTE*)mem)[addr]= ((TYPE_UBYTE*)mem)[addr] + what;
      return(((TYPE_UBYTE*)mem)[addr]);
    }
  else if (width <= 16)
    {
      ((TYPE_UWORD*)mem)[addr]= ((TYPE_UWORD*)mem)[addr] + what;
      return(((TYPE_UWORD*)mem)[addr]);
    }
  else
    {
      ((TYPE_UDWORD*)mem)[addr]= ((TYPE_UDWORD*)mem)[addr] + what;
      return(((TYPE_UDWORD*)mem)[addr]);
    }
}

t_addr
cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con)
{
  int i;

  while ((start <= stop) &&
	 (start < size))
    {
      con->dd_printf(addr_format, start); con->dd_printf(" ");
      for (i= 0;
	   (i < bpl) &&
	     (start+i < size) &&
	     (start+i <= stop);
	   i++)
	{
	  con->dd_printf(data_format, /*read*/get(start+i)); con->dd_printf(" ");
	}
      while (i < bpl)
	{
	  int j;
	  j= width/4 + ((width%4)?1:0) + 1;
	  while (j)
	    {
	      con->dd_printf(" ");
	      j--;
	    }
	  i++;
	}
      for (i= 0; (i < bpl) &&
	     (start+i < size) &&
	     (start+i <= stop);
	   i++)
	{
	  long c= get(start+i);
	  con->dd_printf("%c", isprint(255&c)?(255&c):'.');
	  if (width > 8)
	    con->dd_printf("%c", isprint(255&(c>>8))?(255&(c>>8)):'.');
	  if (width > 16)
	    con->dd_printf("%c", isprint(255&(c>>16))?(255&(c>>16)):'.');
	  if (width > 24)
	    con->dd_printf("%c", isprint(255&(c>>24))?(255&(c>>24)):'.');
	}
      con->dd_printf("\n");
      dump_finished= start+i;
      start+= bpl;
    }
  return(dump_finished);
}

t_addr
cl_mem::dump(class cl_console *con)
{
  return(dump(dump_finished, dump_finished+10*8-1, 8, con));
}



/*
 */
/*
cl_mapped_cell::cl_mapped_cell(class cl_cell *realcell)
{
  real_cell= realcell;
}

cl_mapped_cell::~cl_mapped_cell(void)
{}

t_mem
cl_mapped_cell::read(void)
{
  return(real_cell->read());
}

t_mem
cl_mapped_cell::read(enum hw_cath skip)
{
  return(real_cell->read(skip));
}

t_mem
cl_mapped_cell::get(void)
{
  return(real_cell->get());
}

t_mem
cl_mapped_cell::write(t_mem val)
{
  return(real_cell->write(val));
}

t_mem
cl_mapped_cell::set(t_mem val)
{
  return(real_cell->set(val));
}

t_mem
cl_mapped_cell::add(long what)
{
  return(real_cell->add(what));
}

t_mem
cl_mapped_cell::wadd(long what)
{
  return(real_cell->wadd(what));
}

void
cl_mapped_cell::set_bit1(t_mem bits)
{
  return(real_cell->set_bit1(bits));
}

void
cl_mapped_cell::set_bit0(t_mem bits)
{
  return(real_cell->set_bit0(bits));
}

class cl_cell *
cl_mapped_cell::add_hw(class cl_hw *hw, int *ith)
{
  return(real_cell->add_hw(hw, ith));
}

class cl_hw *
cl_mapped_cell::get_hw(int ith)
{
  return(real_cell->get_hw(ith));
}

class cl_event_handler *
cl_mapped_cell::get_event_handler(void)
{
  return(real_cell->get_event_handler());
}
*/

/*
 */

cl_m::cl_m(enum mem_class atype, char *aclass_name, t_addr asize, int awidth,
	   class cl_uc *auc):
  cl_memory(aclass_name, asize, awidth)
  //cl_mem(atype, aclass_name, 0, awidth, auc)
{
  t_addr a;

  //size= asize;
  width= awidth;
  set_name(aclass_name);
  uc= auc;
  type= atype;

  array= (class cl_cell **)calloc(size, sizeof(class cl_cell *));
  for (a= 0; a < size; a++)
    array[a]= new cl_normal_cell(width);
  bus_mask= 0;
  t_addr i;
  for (i= 1; i < size; i<<=1)
    bus_mask= (bus_mask<<1)|1;
  dummy= new cl_normal_cell(width);
  //mk_cell(size, 0);
}

cl_m::~cl_m(void)
{
  t_addr a;

  for (a= 0; a < size; a++)
    delete array[a];
  free(array);
  delete dummy;
}

int
cl_m::init(void)
{
  t_addr i;

  cl_memory::init();

  for (i= 0; i < size; i++)
    set(i, (type==MEM_ROM)?(-1):0);
  return(0);
}

const char *
cl_m::id_string(void)
{
  const char *s= get_id_string(mem_ids, type);

  return(s?s:"NONE");
}

/*void
cl_m::mk_cell(t_addr addr, class cl_cell *cell)
{
  if (!cell)
    cell= new cl_cell(width);
  class cl_cell *p;
  if (addr >= size)
    p= dummy;
  else
    p= array[addr];
  if (p == 0)
    {
      p= (class cl_cell *)calloc(1, sizeof(*cell));
    }
  else
    {
      p->destroy();
      p= (class cl_cell *)realloc(p, sizeof(cell));
    }
  memcpy(p, cell, sizeof(*cell));
  cell->destroy();
  delete cell;
}*/

t_mem
cl_m::read(t_addr addr)
{
  //addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy->read());
    }
  return(array[addr]->read());
}

t_mem
cl_m::read(t_addr addr, enum hw_cath skip)
{
  //addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy->read(skip));
    }
  return(array[addr]->read(skip));
}

t_mem
cl_m::get(t_addr addr)
{
  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy->get());
    }
  return(array[addr]->get());
}

t_mem
cl_m::write(t_addr addr, t_mem val)
{
  //addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy->write(val));
    }
  return(array[addr]->write(val));
}

void
cl_m::set(t_addr addr, t_mem val)
{
  if (addr >= size)
    {
      err_inv_addr(addr);
      //addr&= bus_mask;
      dummy->set(val);
      return;
    }
  //addr&= bus_mask;
  array[addr]->set(val);
}

class cl_cell *
cl_m::get_cell(t_addr addr)
{
  //addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy);
    }
  return(array[addr]);
}


/* Set or clear bits, without callbacks */

void
cl_m::set_bit1(t_addr addr, t_mem bits)
{
  class cl_cell *cell;

  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      cell= dummy;
    }
  else
    cell= array[addr];
  bits&= cell->get_mask();
  cell->set(cell->get() | bits);
}

void
cl_m::write_bit1(t_addr addr, t_mem bits)
{
  class cl_cell *cell;

  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      cell= dummy;
    }
  else
    cell= array[addr];
  bits&= cell->get_mask();
  cell->write(cell->get() | bits);
}

void
cl_m::set_bit0(t_addr addr, t_mem bits)
{
  class cl_cell *cell;

  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      cell= dummy;
    }
  else
    cell= array[addr];
  bits&= cell->get_mask();
  cell->set(cell->get() & ~bits);
}

void
cl_m::write_bit0(t_addr addr, t_mem bits)
{
  class cl_cell *cell;

  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      cell =dummy;
    }
  else
    cell= array[addr];
  bits&= cell->get_mask();
  cell->write(cell->get() & ~bits);
}

t_mem
cl_m::add(t_addr addr, long what)
{
  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy->add(what));
    }
  return(array[addr]->add(what));
}

t_mem
cl_m::wadd(t_addr addr, long what)
{
  addr&= bus_mask;
  if (addr >= size)
    {
      err_inv_addr(addr);
      return(dummy->wadd(what));
    }
  return(array[addr]->wadd(what));
}

bool
cl_m::search_next(bool case_sensitive, t_mem *array, int len, t_addr *addr)
{
  t_addr a;
  int i;
  bool found;

  if (addr == NULL)
    a= 0;
  else
    a= *addr;
  
  if (a+len > size)
    return(false);

  found= false;
  while (!found &&
	 a+len <= size)
    {
      bool match= true;
      for (i= 0; i < len && match; i++)
	{
	  t_mem d1, d2;
	  d1= get(a+i);
	  d2= array[i];
	  if (!case_sensitive)
	    {
	      if (/*d1 < 128*/isalpha(d1))
		d1= toupper(d1);
	      if (/*d2 < 128*/isalpha(d2))
		d2= toupper(d2);
	    }
	  match= d1 == d2;
	}
      found= match;
      if (!found)
	a++;
    }

  if (addr)
    *addr= a;
  return(found);
}

class cl_cell *
cl_m::register_hw(t_addr addr, class cl_hw *hw, int *ith, bool announce)
{
  class cl_cell *cell, *nc;

  addr&= bus_mask;
  if (addr >= size)
    cell= dummy;
  else
    cell= array[addr];

  if (cell->get_type() & (CELL_HW_READ | CELL_HW_WRITE))
    {
      /* Already registered */
      return(cell->add_hw(hw, ith));
    }
  else if (cell->get_type() & (CELL_READ_BRK | CELL_WRITE_BRK))
    {
      /* Event break is set on it, now register hw */
      nc= new cl_ev_reg_cell(width, uc);
      nc->set(cell->get());
      nc->set_type(nc->get_type() &
		   ~(CELL_GENERAL|CELL_READ_BRK|CELL_WRITE_BRK));
      nc->set_type(nc->get_type() | (cell->get_type() & CELL_GENERAL));
      class cl_event_handler *eh= nc->get_event_handler();
      if (eh)
	nc->set_type(nc->get_type() | eh->copy_from(cell->get_event_handler()));
      nc->add_hw(hw, ith);
    }
  else
    {
      /* Normal cell, register hw */
      nc= new cl_registered_cell(width);
      nc->set(cell->get());
      nc->set_type(nc->get_type() & ~CELL_GENERAL);
      nc->set_type(nc->get_type() | (cell->get_type() & CELL_GENERAL));
      nc->add_hw(hw, ith);
    }

  if (addr >= size)
    {
      delete dummy;
      dummy= nc;  
    }
  else
    {
      delete array[addr];
      array[addr]= nc;
    }
  if (announce)
    uc->sim->/*app->*/mem_cell_changed(this, addr);
  return(nc);
}

void
cl_m::set_brk(t_addr addr, class cl_brk *brk)
{
  class cl_cell *cell, *nc;
  char e= '_';

  addr&= bus_mask;
  if (addr >= size)
    cell= dummy;
  else
    cell= array[addr];

  switch (brk->get_event())
    {
    case brkWRITE: case brkWXRAM: case brkWIRAM: case brkWSFR:
      e= 'W';
      break;
    case brkREAD: case brkRXRAM: case brkRCODE: case brkRIRAM: case brkRSFR:
      e= 'R';
      break;
    case brkNONE:
      set_cell_flag(addr, true, CELL_FETCH_BRK);
      return;
      break;
    default: e= '.'; break;	  
    }
  
  if (cell->get_type() & (CELL_HW_READ | CELL_HW_WRITE))
    {
      /* Hw is registered on it, now set event break */
      nc= new cl_ev_reg_cell(width, uc);
      nc->set(cell->get());
      nc->set_type(nc->get_type() & ~CELL_GENERAL);
      nc->set_type(nc->get_type() | (cell->get_type() & CELL_GENERAL));
      int i= 0;
      class cl_hw *hw;
      while ((hw= cell->get_hw(i)) != 0)
	{
	  nc->add_hw(hw, 0);
	  i++;
	}
      if (((class cl_registered_cell *)cell)->hardwares)
	{
	  free(((class cl_registered_cell *)cell)->hardwares);
	  ((class cl_registered_cell *)cell)->hardwares= 0;
	}
      class cl_event_handler *eh;
      if ((eh= nc->get_event_handler()))
	nc->set_type(nc->get_type() | eh->add_bp(brk));
    }
  else if (cell->get_type() & (CELL_READ_BRK | CELL_WRITE_BRK))
    {
      /* Break is already set on it */
      class cl_event_handler *eh;
      if ((eh= cell->get_event_handler()))
	cell->set_type(cell->get_type() | eh->add_bp(brk));
      return;
    }
  else
    {
      /* Normal cell, set event break */
      nc= new cl_event_cell(width, uc);
      nc->set(cell->get());
      nc->set_type(nc->get_type() & ~CELL_GENERAL);
      nc->set_type(nc->get_type() | (cell->get_type() & CELL_GENERAL));
      class cl_event_handler *eh;
      if ((eh= nc->get_event_handler()))
	nc->set_type(nc->get_type() | eh->add_bp(brk));
    }

  if (addr >= size)
    {
      delete dummy;
      dummy= nc;
    }
  else
    {
      delete array[addr];
      array[addr]= nc;
    }
  uc->sim->/*app->*/mem_cell_changed(this, addr);
}

void
cl_m::del_brk(t_addr addr, class cl_brk *brk)
{
  class cl_cell *cell, *nc;
  char e= '_';

  addr&= bus_mask;
  if (addr >= size)
    cell= dummy;
  else
    cell= array[addr];

  switch (brk->get_event())
    {
    case brkWRITE: case brkWXRAM: case brkWIRAM: case brkWSFR: e= 'W'; break;
    case brkREAD: case brkRXRAM: case brkRCODE: case brkRIRAM: case brkRSFR:
      e= 'R';
      break;
    case brkNONE:
      set_cell_flag(addr, false, CELL_FETCH_BRK);
      return;
      break;
    default: e= '.'; break;
    }
  
  if (cell->get_type() & (CELL_HW_READ | CELL_HW_WRITE))
    {
      /* Hw is registered on it, delete event break */
      class cl_event_handler *eh;
      int t= CELL_NORMAL;
      if ((eh= cell->get_event_handler()))
	t= eh->del_bp(brk);
      if (t & (CELL_READ_BRK|CELL_WRITE_BRK))
	{
	  cell->set_type(cell->get_type() & ~(CELL_READ_BRK|CELL_WRITE_BRK));
	  cell->set_type(cell->get_type() | t);
	  return;
	}
      nc= new cl_registered_cell(width);
      nc->set(cell->get());
      nc->set_type(cell->get_type() & ~CELL_GENERAL);
      nc->set_type(cell->get_type() | (cell->get_type() & CELL_GENERAL));
      int i= 0;
      class cl_hw *hw;
      while ((hw= cell->get_hw(i)) != 0)
	{
	  nc->add_hw(hw, 0);
	  i++;
	}
      if (((class cl_registered_cell *)cell)->hardwares)
	free(((class cl_registered_cell *)cell)->hardwares);
    }
  else if (cell->get_type() & (CELL_READ_BRK | CELL_WRITE_BRK))
    {
      /* Break already set on it, delete brk */
      class cl_event_handler *eh;
      int t= CELL_NORMAL;
      if ((eh= cell->get_event_handler()))
	t= eh->del_bp(brk);
      if (t & (CELL_READ_BRK|CELL_WRITE_BRK))
	{
	  cell->set_type(cell->get_type() & ~(CELL_READ_BRK|CELL_WRITE_BRK));
	  cell->set_type(cell->get_type() | t);
	  return;
	}
      nc= new cl_normal_cell(width);
      nc->set(cell->get());
      nc->set_type(cell->get_type() & ~CELL_GENERAL);
      nc->set_type(cell->get_type() | (cell->get_type() & CELL_GENERAL));
      return;
    }
  else
    {
      /* Normal cell */
      return;
    }

  if (addr >= size)
    {
      delete dummy;
      dummy= nc;
    }
  else
    {
      delete array[addr];
      array[addr]= nc;
    }
  uc->sim->/*app->*/mem_cell_changed(this, addr);
}


#ifdef STATISTIC
unsigned long
cl_m::get_nuof_reads(void)
{
  unsigned long res= 0;
  t_addr i;
  for (i= 0; i < size; i++)
    res+= array[i]->nuof_reads;
  return(res);
}

unsigned long
cl_m::get_nuof_writes(void)
{
  unsigned long res= 0;
  t_addr i;
  for (i= 0; i < size; i++)
    res+= array[i]->nuof_writes;
  return(res);
}

void
cl_m::set_nuof_reads(unsigned long value)
{
  t_addr i;
  for (i= 0; i < size; i++)
    array[i]->nuof_reads= value;
  dummy->nuof_reads= value;
}

void
cl_m::set_nuof_writes(unsigned long value)
{
  t_addr i;
  for (i= 0; i < size; i++)
    array[i]->nuof_writes= value;
  dummy->nuof_writes= value;
}
#endif


cl_normal_cell::cl_normal_cell(uchar awidth):
  cl_cell()
{
  type= CELL_NORMAL;
  data= 0;
  mask= 1;
  width= awidth;
  for (--awidth; awidth; awidth--)
    {
      mask<<= 1;
      mask|= 1;
    }
}

t_mem
cl_normal_cell::add(long what)
{
  t_mem d;
  
  if (width <= 8)
    d= /*TYPE_BYTE*/i8_t(data) + what;
  else if (width <= 16)
    d= /*TYPE_WORD*/i16_t(data) + what;
  else
    d= /*TYPE_DWORD*/i32_t(data) + what;
  return(data= d & mask);
}

t_mem
cl_normal_cell::wadd(long what)
{
  t_mem d;
  
  if (width <= 8)
    d= TYPE_BYTE(data) + what;
  else if (width <= 16)
    d= TYPE_WORD(data) + what;
  else
    d= TYPE_DWORD(data) + what;
  return(write(d));
}

void
cl_normal_cell::set_bit1(t_mem bits)
{
  bits&= mask;
  data|= bits;
}

void
cl_normal_cell::set_bit0(t_mem bits)
{
  bits&= mask;
  data&= ~bits;
}


/*
 */

cl_registered_cell::cl_registered_cell(uchar awidth):
  cl_normal_cell(awidth)
{
  type= CELL_HW_READ | CELL_HW_WRITE;
  //hws= new cl_list(1, 1);
  hardwares= 0;
  nuof_hws= 0;
}

cl_registered_cell::~cl_registered_cell(void)
{
  if (hardwares)
    free(hardwares);
}

/*void
cl_registered_cell::destroy(void)
{
  hardwares= 0;
  nuof_hws= 0;
}*/

t_mem
cl_registered_cell::read(void)
{
  int i;
  t_mem d= data;

  if (nuof_hws)
    for (i= 0; i < nuof_hws; i++)
      {
	d= hardwares[i]->read(this);
	;
      }
#ifdef STATISTIC
  nuof_reads++;
#endif
  return(d & mask);
}

t_mem
cl_registered_cell::read(enum hw_cath skip)
{
  int i;
  t_mem d= data;

  if (nuof_hws)
    for (i= 0; i < nuof_hws; i++)
      {
	if ((skip & hardwares[i]->category) == 0)
	  d= hardwares[i]->read(this);
	;
      }
#ifdef STATISTIC
  nuof_reads++;
#endif
  return(d & mask);
}

t_mem
cl_registered_cell::write(t_mem val)
{
  int i;

  val&= mask;
  if (nuof_hws)
    for (i= 0; i < nuof_hws; i++)
      {
	hardwares[i]->write(this, &val);
	;
      }
#ifdef STATISTIC
  nuof_writes++;
#endif
  return(data= val & mask);
}

class cl_cell *
cl_registered_cell::add_hw(class cl_hw *hw, int *ith)
{
  if (!hw)
    {
      /* Whatta hell!? */
      return(0);
    }
  if (!hardwares)
    hardwares= (class cl_hw **)malloc(sizeof(class cl_hw *));
  else
    hardwares= (class cl_hw **)realloc(hardwares,
				       sizeof(class c_hw *) * (nuof_hws+1));
  hardwares[nuof_hws]= hw;
  nuof_hws++;
  if (ith)
    *ith= nuof_hws-1;
  return(this);
}

class cl_hw *
cl_registered_cell::get_hw(int ith)
{
  if (ith >= nuof_hws)
    return(0);
  return(hardwares[ith]);
}


/*
 */

cl_event_cell::cl_event_cell(uchar awidth, class cl_uc *auc):
  cl_normal_cell(awidth)
{
  eh= new cl_event_handler(auc);
}

cl_event_cell::~cl_event_cell(void)
{
  delete eh;
}

t_mem
cl_event_cell::read(void)
{
  if (type & CELL_READ_BRK)
    eh->read();
  return(cl_normal_cell::read());
}

t_mem
cl_event_cell::write(t_mem val)
{
  if (type & CELL_WRITE_BRK)
    eh->write();
  return(cl_normal_cell::write(val));
}


/*
 */

cl_ev_reg_cell::cl_ev_reg_cell(uchar awidth, class cl_uc *auc):
  cl_registered_cell(awidth)
{
  eh= new cl_event_handler(auc);
}

cl_ev_reg_cell::~cl_ev_reg_cell(void)
{}

t_mem
cl_ev_reg_cell::read(void)
{
  if (type & CELL_READ_BRK)
    eh->read();
  return(cl_registered_cell::read());
}

t_mem
cl_ev_reg_cell::write(t_mem val)
{
  if (type & CELL_WRITE_BRK)
    eh->write();
  return(cl_registered_cell::write(val));
}


/*
 */

cl_event_handler::cl_event_handler(class cl_uc *auc):
  cl_base()
{
  uc= auc;
  read_bps= new cl_list(1, 1);
  write_bps= new cl_list(1, 1);
}

cl_event_handler::~cl_event_handler(void)
{
  read_bps->disconn_all();
  write_bps->disconn_all();
  delete read_bps;
  delete write_bps;
}

void
cl_event_handler::write(void)
{
  int i;

  for (i= 0; i < write_bps->count; i++)
    {
      class cl_brk *bp= (class cl_brk *)(write_bps->at(i));
      uc->events->add(bp);
    }
}

void
cl_event_handler::read(void)
{
  int i;

  for (i= 0; i < read_bps->count; i++)
    {
      class cl_brk *bp= (class cl_brk *)(read_bps->at(i));
      uc->events->add(bp);
    }
}

int
cl_event_handler::add_bp(class cl_brk *bp)
{
  int t= CELL_NORMAL;

  if (!bp)
    return(CELL_NORMAL);
  switch (bp->get_event())
    {
    case brkWRITE: case brkWXRAM: case brkWIRAM: case brkWSFR:
      t|= CELL_WRITE_BRK;
      write_bps->add(bp);
      break;
    case brkREAD: case brkRXRAM: case brkRCODE: case brkRIRAM: case brkRSFR:
      t|= CELL_READ_BRK;
      read_bps->add(bp);
      break;
    default:
      t|= CELL_READ_BRK | CELL_WRITE_BRK;
      read_bps->add(bp);
      write_bps->add(bp);
      break;
    }
  return(t);
}

int
cl_event_handler::copy_from(class cl_event_handler *eh)
{
  int i, t= CELL_NORMAL;
  
  if (!eh)
    return(t);
  for (i= 0; i < eh->read_bps->count; i++)
    {
      class cl_brk *bp= (class cl_brk *)(eh->read_bps->at(i));
      t|= add_bp(bp);
    }
  for (i= 0; i < eh->write_bps->count; i++)
    {
      class cl_brk *bp= (class cl_brk *)(eh->write_bps->at(i));
      t|= add_bp(bp);
    }
  return(t);
}

int
cl_event_handler::del_bp(class cl_brk *bp)
{
  int t= CELL_NORMAL;

  write_bps->disconn(bp);
  read_bps->disconn(bp);
  if (write_bps->count)
    t|= CELL_WRITE_BRK;
  if (read_bps->count)
    t|= CELL_READ_BRK;
  return(t);
}


