Merge branch ucsim-034-pre3 to main trunk; new version 0.4
[fw/sdcc] / sim / ucsim / sim.src / mem.cc
index e780f4e09dff3971fde26503f76b54a28feab629..12d168692a2fd52df261819a886a8a0f137c45dc 100644 (file)
@@ -34,6 +34,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "utils.h"
 #include "globals.h"
 
+// sim
+#include "simcl.h"
+
 // cmd
 #include "newcmdcl.h"
 
@@ -46,21 +49,21 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  * Memory location handled specially by a hw element
  */
 
-cl_memloc::cl_memloc(long addr):
+/*cl_memloc::cl_memloc(t_addr addr):
   cl_base()
 {
   address= addr;
   hws= new cl_list(2, 2);
   hws->init();
-}
+}*/
 
-cl_memloc::~cl_memloc(void)
+/*cl_memloc::~cl_memloc(void)
 {
   hws->disconn_all();
   delete hws;
-}
+}*/
 
-ulong
+/*ulong
 cl_memloc::read(class cl_mem *mem)
 {
   uchar ret= 0;
@@ -72,10 +75,10 @@ cl_memloc::read(class cl_mem *mem)
   if ((hw= (class cl_hw *)(hws->at(0))))
     ret= hw->read(mem, address);
   return(ret);
-}
+}*/
 
-void
-cl_memloc::write(class cl_mem *mem, long addr, ulong *val)
+/*void
+cl_memloc::write(class cl_mem *mem, t_addr addr, t_mem *val)
 {
   class cl_hw *hw;
   int i;
@@ -87,24 +90,24 @@ cl_memloc::write(class cl_mem *mem, long addr, ulong *val)
       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_memloc_coll::cl_memloc_coll(void):
   cl_sorted_list(2, 2)
 {
-  Duplicates= FALSE;
-}
+  Duplicates= DD_FALSE;
+}*/
 
-void *
+/*void *
 cl_memloc_coll::key_of(void *item)
 {
   return(&(((class cl_memloc *)item)->address));
-}
+}*/
 
-int
+/*int
 cl_memloc_coll::compare(void *key1, void *key2)
 {
   if (*(long*)key1 > *(long*)key2)
@@ -114,17 +117,17 @@ cl_memloc_coll::compare(void *key1, void *key2)
       return(-1);
     else
       return(0);
-}
+}*/
 
-class cl_memloc *
-cl_memloc_coll::get_loc(long address)
+/*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);
-}
+}*/
 
 
 /*
@@ -132,34 +135,45 @@ cl_memloc_coll::get_loc(long address)
  ******************************************************************************
  */
 
-cl_mem::cl_mem(enum mem_class atype, t_addr asize, int awidth):
-  cl_base()
+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 <= 8)
+  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();
+  //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);
-  delete read_locs;
-  delete write_locs;
+  if (addr_format)
+    free(addr_format);
+  if (data_format)
+    free(data_format);
+  //delete read_locs;
+  //delete write_locs;
 }
 
 int
@@ -167,6 +181,17 @@ 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);
@@ -180,19 +205,19 @@ cl_mem::id_string(void)
   return(s?s:(char*)"NONE");
 }
 
-ulong
+t_mem
 cl_mem::read(t_addr addr)
 {
-  class cl_memloc *loc;
+  //class cl_memloc *loc;
 
   if (addr >= size)
     {
       //FIXME
-      fprintf(stderr, "Address 0x%06lx is over 0x%06lx\n", addr, size);
+      fprintf(stderr, "Address 0x%06"_A_"x is over 0x%06"_A_"x\n", addr, size);
       return(0);
     }
-  if ((loc= read_locs->get_loc(addr)))
-    return(loc->read(this));
+  /*if ((loc= read_locs->get_loc(addr)))
+    return(loc->read(this));*/
   if (width <= 8)
     return((((TYPE_UBYTE*)mem)[addr])&mask);
   else if (width <= 16)
@@ -201,7 +226,7 @@ cl_mem::read(t_addr addr)
     return((((TYPE_UDWORD*)mem)[addr])&mask);
 }
 
-ulong
+t_mem
 cl_mem::get(t_addr addr)
 {
   if (addr >= size)
@@ -221,10 +246,10 @@ cl_mem::get(t_addr addr)
 
 /* Write calls callbacks of HW elements */
 
-void
-cl_mem::write(t_addr addr, t_mem *val)
+t_mem
+cl_mem::write(t_addr addr, t_mem val)
 {
-  class cl_memloc *loc;
+  /*  class cl_memloc *loc;
 
   if (addr >= size)
     return;
@@ -235,7 +260,10 @@ cl_mem::write(t_addr addr, t_mem *val)
   else if (width <= 16)
     ((TYPE_UWORD*)mem)[addr]= (*val)&mask;
   else
-    ((TYPE_UDWORD*)mem)[addr]= (*val)&mask;
+  ((TYPE_UDWORD*)mem)[addr]= (*val)&mask;*/
+  fprintf(stderr, "FIXME cl_mem::write(0x%06"_A_"x, 0x%04"_M_"x)\n",
+         addr, val);
+  return(0);
 }
 
 /* Set doesn't call callbacks */
@@ -283,33 +311,54 @@ cl_mem::set_bit0(t_addr addr, t_mem bits)
     ((TYPE_UDWORD*)mem)[addr]&= ~bits;
 }
 
-void
+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;
 
-  if (start < 0)
-    {
-      start= dump_finished;
-      stop= start+stop;
-    }
   while ((start <= stop) &&
         (start < size))
     {
-      con->printf("%06x ", start);
-      for (i= 0; (i < bpl) &&
+      con->dd_printf(addr_format, start); con->dd_printf(" ");
+      for (i= 0;
+          (i < bpl) &&
             (start+i < size) &&
             (start+i <= stop);
           i++)
        {
-         char format[10];
-         sprintf(format, "%%0%dx ", width/4);
-         con->printf(format/*"%02x "*/, get(start+i));
+         con->dd_printf(data_format, /*read*/get(start+i)); con->dd_printf(" ");
        }
       while (i < bpl)
        {
-         //FIXME
-         con->printf("   ");
+         int j;
+         j= width/4 + ((width%4)?1:0) + 1;
+         while (j)
+           {
+             con->dd_printf(" ");
+             j--;
+           }
          i++;
        }
       for (i= 0; (i < bpl) &&
@@ -318,18 +367,69 @@ cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con)
           i++)
        {
          long c= get(start+i);
-         con->printf("%c", isprint(255&c)?(255&c):'.');
+         con->dd_printf("%c", isprint(255&c)?(255&c):'.');
          if (width > 8)
-           con->printf("%c", isprint(255&(c>>8))?(255&(c>>8)):'.');
+           con->dd_printf("%c", isprint(255&(c>>8))?(255&(c>>8)):'.');
          if (width > 16)
-           con->printf("%c", isprint(255&(c>>16))?(255&(c>>16)):'.');
+           con->dd_printf("%c", isprint(255&(c>>16))?(255&(c>>16)):'.');
          if (width > 24)
-           con->printf("%c", isprint(255&(c>>24))?(255&(c>>24)):'.');
+           con->dd_printf("%c", isprint(255&(c>>24))?(255&(c>>24)):'.');
        }
-      con->printf("\n");
+      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));
+}
+
+bool
+cl_mem::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(DD_FALSE);
+
+  found= DD_FALSE;
+  while (!found &&
+        a+len <= size)
+    {
+      bool match= DD_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);
 }
 
 
@@ -337,7 +437,7 @@ cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con)
  * Bitmap
  */
 
-cl_bitmap::cl_bitmap(long asize):
+/*cl_bitmap::cl_bitmap(t_addr asize):
   cl_base()
 {
   map= (uchar*)malloc(size= asize/(8*SIZEOF_CHAR));
@@ -350,7 +450,7 @@ cl_bitmap::~cl_bitmap(void)
 }
 
 void
-cl_bitmap::set(long pos)
+cl_bitmap::set(t_addr pos)
 {
   int i;
 
@@ -359,7 +459,7 @@ cl_bitmap::set(long pos)
 }
 
 void
-cl_bitmap::clear(long pos)
+cl_bitmap::clear(t_addr pos)
 {
   int i;
 
@@ -368,7 +468,7 @@ cl_bitmap::clear(long pos)
 }
 
 bool
-cl_bitmap::get(long pos)
+cl_bitmap::get(t_addr pos)
 {
   return(map[pos/(8*SIZEOF_CHAR)] & (1 << (pos & ((8*SIZEOF_CHAR)-1))));
 }
@@ -380,14 +480,14 @@ cl_bitmap::empty(void)
 
   for (i= 0; i < size && map[i] == 0; i++) ;
   return(i == size);
-}
+}*/
 
 /*
  * Special memory for code (ROM)
  */
 
-cl_rom::cl_rom(long asize, int awidth):
-  cl_mem(MEM_ROM, asize, awidth)
+/*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);
@@ -397,6 +497,934 @@ cl_rom::~cl_rom(void)
 {
   delete bp_map;
   delete inst_map;
+}*/
+
+
+/*
+ * New type of memory simulation
+ */
+
+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(data) + what;
+  else if (width <= 16)
+    d= TYPE_WORD(data) + what;
+  else
+    d= TYPE_DWORD(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);
+       ;
+      }
+  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]->cathegory) == 0)
+         d= hardwares[i]->read(this);
+       ;
+      }
+  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);
+       ;
+      }
+  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_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);
+}
+
+
+/*
+ */
+
+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_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_mem(atype, aclass_name, 0, awidth, auc)
+{
+  t_addr a;
+
+  size= asize;
+  width= awidth;
+  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;
+}
+
+void
+cl_m::err_inv_addr(t_addr addr)
+{
+  if (!uc)
+    return;
+  class cl_error *e= new cl_err_inv_addr(this, addr);
+  uc->error(e);
+}
+
+/*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;
+}*/
+
+int
+cl_m::get_cell_flag(t_addr addr)
+{
+  if (addr >= size)
+    {
+      return(dummy->get_type());
+    }
+  return(array[addr]->get_type());
+}
+
+bool
+cl_m::get_cell_flag(t_addr addr, int flag)
+{
+  if (addr >= size)
+    {
+      return(dummy->get_type() & flag);
+    }
+  return(array[addr]->get_type() & flag);
+}
+
+void
+cl_m::set_cell_flag(t_addr addr, bool set_to, int flag)
+{
+  class cl_cell *cell;
+  
+  if (addr >= size)
+    {
+      cell= dummy;
+    }
+  else
+    cell= array[addr];
+  if (set_to)
+    cell->set_type(cell->get_type() | flag);
+  else
+    cell->set_type(cell->get_type() & ~flag);
+}
+
+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));
+}
+
+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, DD_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, DD_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);
+}
+
+
+/*
+ * Errors in memory handling
+ */
+
+cl_err_inv_addr::cl_err_inv_addr(class cl_mem *amem, t_addr aaddr):
+  cl_error()
+{
+  mem= amem;
+  addr= aaddr;
+}
+
+void
+cl_err_inv_addr::print(class cl_commander *c)
+{
+  c->dd_printf("Error: invalid address ");
+  c->dd_printf(mem->addr_format, addr);
+  c->dd_printf(" in memory %s.\n", mem->class_name);
 }