summaryrefslogtreecommitdiff
path: root/sim/ucsim/sim.src/mem.cc
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /sim/ucsim/sim.src/mem.cc
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'sim/ucsim/sim.src/mem.cc')
-rw-r--r--sim/ucsim/sim.src/mem.cc2634
1 files changed, 2634 insertions, 0 deletions
diff --git a/sim/ucsim/sim.src/mem.cc b/sim/ucsim/sim.src/mem.cc
new file mode 100644
index 0000000..7b5947a
--- /dev/null
+++ b/sim/ucsim/sim.src/mem.cc
@@ -0,0 +1,2634 @@
+/*
+ * Simulator of microcontrollers (mem.cc)
+ *
+ * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.
+ *
+ * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
+ *
+ */
+
+/*
+ This file is part of microcontroller simulator: ucsim.
+
+ UCSIM 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.
+
+ UCSIM 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 UCSIM; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+/*@1@*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include "i_string.h"
+
+// prj
+#include "utils.h"
+#include "globals.h"
+
+// sim
+#include "simcl.h"
+
+// cmd
+#include "newcmdcl.h"
+#include "cmdutil.h"
+
+// local
+#include "memcl.h"
+#include "hwcl.h"
+
+
+static class cl_mem_error_registry mem_error_registry;
+
+/*
+ * 3rd version of memory system
+ */
+
+cl_memory::cl_memory(const char *id, t_addr asize, int awidth):
+ cl_base()
+{
+ if ((size= asize) > max_mem_size)
+ size= max_mem_size;
+ set_name(id);
+ addr_format= data_format= 0;
+ width= awidth;
+ start_address= 0;
+ uc= 0;
+ hidden= false;
+}
+
+cl_memory::~cl_memory(void)
+{
+ if (addr_format)
+ free(addr_format);
+ if (data_format)
+ free(data_format);
+}
+
+int
+cl_memory::init(void)
+{
+ chars c= chars("",
+ //addr_format= (char *)malloc(10);
+ /*sprintf(addr_format,*/ "0x%%0%d",
+ 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))))));
+ if (sizeof(t_addr) > sizeof(long))
+ c+= cchars("L");//strcat(addr_format, "L");
+ else if (sizeof(t_addr) > sizeof(int))
+ c+= cchars("l");//strcat(addr_format, "l");
+ c+= cchars("x");//strcat(addr_format, "x");
+ addr_format= strdup((char*)c);
+ //data_format= (char *)malloc(10);
+ c= cchars("");
+ /*sprintf(data_*/c.format(/*"0x"*/"%%0%d", width/4+((width%4)?1:0));
+ if (sizeof(t_mem) > sizeof(long))
+ c+= cchars("L");//strcat(data_format, "L");
+ else if (sizeof(t_mem) > sizeof(int))
+ c+= cchars("l");//strcat(data_format, "l");
+ c+= cchars("x");//strcat(data_format, "x");
+ data_format= strdup((char*)c);
+ data_mask= 1;
+ int w= width;
+ for (--w; w; w--)
+ {
+ data_mask<<= 1;
+ data_mask|= 1;
+ }
+ dump_finished= start_address;
+ return(0);
+}
+
+
+bool
+cl_memory::valid_address(t_addr addr)
+{
+ return(addr >= start_address &&
+ addr < start_address+size);
+}
+
+t_addr
+cl_memory::inc_address(t_addr addr, int val)
+{
+ if (!start_address)
+ return(((signed)addr+val)%size);
+ addr-= start_address;
+ addr+= val;
+ addr%= size;
+ addr+= start_address;
+ return(addr);
+}
+
+t_addr
+cl_memory::inc_address(t_addr addr)
+{
+ if (!start_address)
+ return(((signed)addr+1)%size);
+ addr-= start_address;
+ addr++;
+ addr%= size;
+ addr+= start_address;
+ return(addr);
+}
+
+t_addr
+cl_memory::validate_address(t_addr addr)
+{
+ while (addr < start_address)
+ addr+= size;
+ if (addr > start_address+size)
+ {
+ addr-= start_address;
+ addr%= size;
+ addr+= start_address;
+ }
+ return(addr);
+}
+
+
+void
+cl_memory::err_inv_addr(t_addr addr)
+{
+ if (!uc)
+ return;
+ class cl_error *e= new cl_error_mem_invalid_address(this, addr);
+ uc->error(e);
+}
+
+void
+cl_memory::err_non_decoded(t_addr addr)
+{
+ if (!uc)
+ return;
+ class cl_error *e= new cl_error_mem_non_decoded(this, addr);
+ uc->error(e);
+}
+
+
+t_addr
+cl_memory::dump(t_addr start, t_addr stop, int bpl, /*class cl_f *f*/class cl_console_base *con)
+{
+ int i, step;
+ t_addr lva= lowest_valid_address();
+ t_addr hva= highest_valid_address();
+ class cl_f *f= con->get_fout();
+
+ if (!f)
+ return dump_finished;
+
+ if (start < lva)
+ start= lva;
+ if (start > hva)
+ return dump_finished;
+ if (stop > hva)
+ stop= hva;
+ if (stop < lva)
+ return dump_finished;
+ if (stop >= start)
+ {
+ step= +1;
+ stop++;
+ if (start + bpl > stop)
+ bpl= stop - start;
+ }
+ else
+ {
+ step= -1;
+ stop--;
+ if (start - bpl < stop)
+ bpl= start - stop;
+ }
+ while ((step>0)?(start < stop):(start > stop))
+ {
+ // 1. field: address
+ /*f->prntf*/con->dd_cprintf("dump_address", addr_format, start);
+ /*f->write_str*/con->dd_printf(" ");
+ // 2. field: hex list
+ for (i= 0;
+ (i < bpl) &&
+ (start+i*step >= lva) &&
+ (start+i*step <= hva) &&
+ (start+i*step != stop);
+ i++)
+ {
+ /*f->prntf*/con->dd_cprintf("dump_number", data_format, read/*get*/(start+i*step));
+ /*f->write_str*/con->dd_printf(" ");
+ }
+ // 3. field: char list
+ while (i < bpl)
+ {
+ int j;
+ j= width/4 + ((width%4)?1:0) + 1;
+ while (j)
+ {
+ /*f->write_str*/con->dd_printf(" ");
+ j--;
+ }
+ i++;
+ }
+ for (i= 0; (i < bpl) &&
+ (start+i*step >= lva) &&
+ (start+i*step <= hva) &&
+ (start+i*step != stop);
+ i++)
+ {
+ long c= read(start+i*step);
+ /*f->prntf*/con->dd_cprintf("dump_char", "%c", isprint(255&c)?(255&c):'.');
+ if (width > 8)
+ /*f->prntf*/con->dd_cprintf("dump_char", "%c", isprint(255&(c>>8))?(255&(c>>8)):'.');
+ if (width > 16)
+ /*f->prntf*/con->dd_cprintf("dump_char", "%c", isprint(255&(c>>16))?(255&(c>>16)):'.');
+ if (width > 24)
+ /*f->prntf*/con->dd_cprintf("dump_char", "%c", isprint(255&(c>>24))?(255&(c>>24)):'.');
+ }
+ /*f->prntf*/con->dd_printf("\n");
+ dump_finished= start+i*step;
+ start+= i*step;
+ }
+ return(dump_finished);
+}
+
+t_addr
+cl_memory::dump_s(t_addr start, t_addr stop, int bpl, /*class cl_f *f*/class cl_console_base *con)
+{
+ t_addr lva= lowest_valid_address();
+ t_addr hva= highest_valid_address();
+ class cl_f *f= con->get_fout();
+
+ if (!f)
+ return dump_finished;
+ if (start < 0)
+ start= dump_finished;
+ if (stop < 0)
+ stop= start + 10*8 - 1;
+
+ if (start < lva)
+ start= lva;
+ if (start > hva)
+ return dump_finished;
+ if (stop > hva)
+ stop= hva;
+ if (stop < lva)
+ return dump_finished;
+
+ if (bpl < 0)
+ bpl= 8;
+ t_addr a= start;
+ t_mem d= read(a);
+ char last= '\n';
+ con->dd_printf("%s", (char*)(con->get_color_ansiseq("dump_char")));
+ while ((a <= stop) &&
+ (d != 0) &&
+ (a <= hva))
+ {
+ char c= d;
+ int i= d;
+ chars s;
+ if (a >= lva)
+ {
+ switch (c)
+ { // ' " ? \ a b f n r t v
+ case '\'': s= (char*)"\\\'"; f->write((char*)s, s.len()); break;
+ case '\"': s= (char*)"\\\""; f->write((char*)s, s.len()); break;
+ case '\?': s= (char*)"\\\?"; f->write((char*)s, s.len()); break;
+ case '\\': s= (char*)"\\\\"; f->write((char*)s, s.len()); break;
+ case '\a': s= (char*)"\\a"; f->write((char*)s, s.len()); break;
+ case '\b': s= (char*)"\\b"; f->write((char*)s, s.len()); break;
+ case '\f': s= (char*)"\\f"; f->write((char*)s, s.len()); break;
+ case '\n': s= (char*)"\\n"; f->write((char*)s, s.len()); break;
+ case '\r': s= (char*)"\\r"; f->write((char*)s, s.len()); break;
+ case '\t': s= (char*)"\\t"; f->write((char*)s, s.len()); break;
+ case '\v': s= (char*)"\\v"; f->write((char*)s, s.len()); break;
+ default:
+ if (isprint(i))
+ f->write(&c, 1);
+ else
+ {
+ s.format("\\%03o", i);
+ f->write((char*)s, s.len());
+ }
+ }
+ last= c;
+ }
+ d= read(++a);
+ }
+ if (last != '\n')
+ f->write_str("\n");
+ return dump_finished= a;
+}
+
+t_addr
+cl_memory::dump_b(t_addr start, t_addr stop, int bpl, /*class cl_f *f*/class cl_console_base *con)
+{
+ t_addr lva= lowest_valid_address();
+ t_addr hva= highest_valid_address();
+ class cl_f *f= con->get_fout();
+
+ if (!f)
+ return dump_finished;
+ if (start < 0)
+ start= dump_finished;
+ if (stop < 0)
+ stop= start + 10*8 - 1;
+
+ if (start < lva)
+ start= lva;
+ if (start > hva)
+ return dump_finished;
+ if (stop > hva)
+ stop= hva;
+ if (stop < lva)
+ return dump_finished;
+
+ if (bpl < 0)
+ bpl= 8;
+ t_addr a= start;
+ t_mem d= read(a);
+ while ((a <= stop) &&
+ (a <= hva))
+ {
+ char c= d;
+ if (a >= lva)
+ {
+ f->write(&c, 1);
+ }
+ d= read(++a);
+ }
+ return dump_finished= a;
+}
+
+t_addr
+cl_memory::dump_i(t_addr start, t_addr stop, int bpl, /*class cl_f *f*/class cl_console_base *con)
+{
+ t_addr lva= lowest_valid_address();
+ t_addr hva= highest_valid_address();
+ unsigned int sum;
+ t_addr start_line;
+ class cl_f *f= con->get_fout();
+
+ if (!f)
+ return dump_finished;
+ if (start < 0)
+ start= dump_finished;
+ if (start < lva)
+ start= lva;
+ if (stop < 0)
+ stop= start + 10*8 - 1;
+ if (stop > hva)
+ stop= hva;
+
+ if (start < lva)
+ start= lva;
+ if (start > hva)
+ return dump_finished;
+ if (stop > hva)
+ stop= hva;
+ if (stop < lva)
+ return dump_finished;
+
+ if (start > stop)
+ return dump_finished= stop;
+
+ if (bpl < 0)
+ bpl= 16;
+ if (bpl > 32)
+ bpl= 32;
+ t_addr a= start;
+ sum= 0;
+ start_line= a;
+ while (a <= stop)
+ {
+ a++;
+ if (((a % bpl) == 0) ||
+ (a > stop))
+ {
+ // dump line
+ if ((a - start_line) > 0)
+ {
+ unsigned char c;
+ sum= 0;
+ c= a-start_line;
+ f->prntf(":%02X%04X00", c, start_line);
+ sum+= c;
+ c= int(start_line >> 8) & 0xff;
+ sum+= c;
+ c= start_line & 0xff;
+ sum+= c;
+ int i;
+ for (i= 0; i < a-start_line; i++)
+ {
+ c= read(start_line + i);
+ f->prntf("%02X", c);
+ sum+= c;
+ }
+ sum&= 0xff;
+ unsigned char chk= 0x100 - sum;
+ f->prntf("%02X\r\n", chk);
+ }
+ start_line= a;
+ }
+ }
+ f->write_str(":00000001FF\r\n");
+ return dump_finished= a;
+}
+
+t_addr
+cl_memory::dump(/*class cl_f *f*/class cl_console_base *con)
+{
+ if (con->get_fout() == NULL)
+ return dump_finished;
+ return(dump(dump_finished, dump_finished+10*8-1, 8, /*f*/con));
+}
+
+t_addr
+cl_memory::dump(enum dump_format fmt,
+ t_addr start, t_addr stop, int bpl,
+ /*class cl_f *f*/class cl_console_base *con)
+{
+ t_addr lva= lowest_valid_address();
+ t_addr hva= highest_valid_address();
+
+ //if (!f)
+ //return dump_finished;
+ if (start < 0)
+ start= dump_finished;
+ if (stop < 0)
+ stop= start + 10*8 - 1;
+
+ if (start < lva)
+ start= lva;
+ if (start > hva)
+ return dump_finished;
+ if (stop > hva)
+ stop= hva;
+ if (stop < lva)
+ return dump_finished;
+
+ if (bpl < 0)
+ bpl= 8;
+ switch (fmt & df_format)
+ {
+ case df_hex:
+ return dump(start, stop, bpl, /*f*/con);
+ case df_string:
+ return dump_s(start, stop, bpl, /*f*/con);
+ case df_ihex:
+ return dump_i(start, stop, bpl, /*f*/con);
+ case df_binary:
+ return dump_b(start, stop, bpl, /*f*/con);
+ default:
+ return dump(start, stop, bpl, /*f*/con);
+ }
+ return dump_finished;
+}
+
+bool
+cl_memory::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);
+}
+
+void
+cl_memory::print_info(chars pre, class cl_console_base *con)
+{
+ char *n= (char*)(get_name());
+ if (!hidden)
+ {
+ con->dd_printf("%s0x%06x-0x%06x %8d %s (%d,%s,%s)\n", (char*)pre,
+ AU(get_start_address()),
+ AU(highest_valid_address()),
+ AU(get_size()),
+ n,
+ width, data_format, addr_format);
+ }
+}
+
+
+/*
+ * Memory operators
+ */
+
+cl_memory_operator::cl_memory_operator(class cl_memory_cell *acell/*,
+ t_addr addr*/):
+ cl_base()
+{
+ cell= acell;
+ if (cell)
+ {
+ //data= cell->data;
+ mask= cell->mask;
+ }
+ else
+ {
+ //data= 0;
+ mask= ~0;
+ }
+ next_operator= 0;
+ //address= addr;
+}
+/*
+cl_memory_operator::cl_memory_operator(class cl_memory_cell *acell,
+ t_addr addr,
+ t_mem *data_place, t_mem the_mask):
+ cl_base()
+{
+ cell= acell;
+ //data= data_place;
+ mask= the_mask;
+ next_operator= 0;
+ address= addr;
+}
+*/
+/*
+void
+cl_memory_operator::set_data(t_mem *data_place, t_mem the_mask)
+{
+ data= data_place;
+ mask= the_mask;
+}
+*/
+
+t_mem
+cl_memory_operator::read(void)
+{
+ if (next_operator)
+ return(next_operator->read());
+ else if (cell)
+ return(/* *data*/cell->get());
+ return 0;
+}
+
+t_mem
+cl_memory_operator::write(t_mem val)
+{
+ if (next_operator)
+ return(next_operator->write(val));
+ else if (cell)
+ return(/* *data=*/cell->set(val & mask));
+ return val;
+}
+
+
+/* Memory operator for bank switcher */
+
+cl_bank_switcher_operator::cl_bank_switcher_operator(class cl_memory_cell *acell,
+ /*t_addr addr,*/
+ class cl_banker *the_banker):
+ cl_memory_operator(acell/*, addr*/)
+{
+ banker= the_banker;
+ set_name("bank_switcher");
+}
+
+t_mem
+cl_bank_switcher_operator::write(t_mem val)
+{
+ if (next_operator)
+ next_operator->write(val);
+ if (cell) /* *data=*/ cell->set(val & mask);
+ banker->activate(NULL);
+ if (cell)
+ return cell->get();
+ return /* *data*/ 0;
+}
+
+
+/* Memory operator for hw callbacks */
+
+cl_hw_operator::cl_hw_operator(class cl_memory_cell *acell/*, t_addr addr*/,
+ //t_mem *data_place, t_mem the_mask,
+ class cl_hw *ahw):
+ cl_memory_operator(acell/*, addr*//*, data_place, the_mask*/)
+{
+ hw= ahw;
+ set_name(chars("hw:")+hw->get_name());
+}
+
+
+t_mem
+cl_hw_operator::read(void)
+{
+ t_mem d1= 0, d2= 0;
+
+ if (hw)
+ d1= hw->read(cell);
+
+ if (next_operator)
+ d2= next_operator->read();
+
+ return(hw?d1:d2);
+}
+
+t_mem
+cl_hw_operator::read(enum hw_cath skip)
+{
+ t_mem d1= 0/* *data*/, d2= d1;
+ bool use= false;
+
+ if (hw &&
+ hw->cathegory != skip)
+ use= true, d1= hw->read(cell);
+
+ if (next_operator)
+ d2= next_operator->read();
+ else if (cell)
+ d2= cell->get();
+ else
+ return use= true;
+
+ return(use?d1:d2);
+}
+
+t_mem
+cl_hw_operator::write(t_mem val)
+{
+ if (hw)
+ hw->write(cell, &val);
+ if (next_operator)
+ val= next_operator->write(val);
+ //if (cell) return(/* *data=*//*cell->set(val & mask)*/val);
+ return val;
+}
+
+
+/* Write event break on cell */
+
+cl_write_operator::cl_write_operator(class cl_memory_cell *acell/*, t_addr addr*/,
+ //t_mem *data_place, t_mem the_mask,
+ class cl_uc *auc, class cl_brk *the_bp):
+ cl_event_break_operator(acell/*, addr*//*, data_place, the_mask*/, auc, the_bp)
+{
+ uc= auc;
+ bp= the_bp;
+ set_name("write_event");
+}
+
+t_mem
+cl_write_operator::write(t_mem val)
+{
+ //printf("write event at 0x%x bp=%p\n",address,bp);
+ if (bp->do_hit())
+ uc->events->add(bp);
+ if (next_operator)
+ return(next_operator->write(val));
+ else if (cell)
+ return(/* *data=*/cell->set(val & mask));
+ return val;
+}
+
+
+/* Read event break on cell */
+
+cl_read_operator::cl_read_operator(class cl_memory_cell *acell/*, t_addr addr*/,
+ //t_mem *data_place, t_mem the_mask,
+ class cl_uc *auc, class cl_brk *the_bp):
+ cl_event_break_operator(acell/*, addr*//*, data_place, the_mask*/, auc, the_bp)
+{
+ uc= auc;
+ bp= the_bp;
+ set_name("read_event");
+}
+
+t_mem
+cl_read_operator::read(void)
+{
+ //printf("read event at 0x%x bp=%p\n",address,bp);
+ if (bp->do_hit())
+ uc->events->add(bp);
+ if (next_operator)
+ return(next_operator->read());
+ else if (cell)
+ return(/* *data*/cell->get());
+ return 0;
+}
+
+
+/*
+ * Cell data
+ */
+
+t_mem
+cl_cell_data::d()
+{
+ return data?(*data):0;
+}
+
+void
+cl_cell_data::d(t_mem v)
+{
+ data?(*data=v):0;
+}
+
+void
+cl_cell_data::dl(t_mem v)
+{
+ data?(*data=v):0;
+}
+
+// bit cell for bit spaces
+
+t_mem
+cl_bit_cell::d()
+{
+ if (!data)
+ return 0;
+ return (*data&mask)?1:0;
+}
+
+void
+cl_bit_cell::d(t_mem v)
+{
+ if (!data)
+ return;
+ if (v)
+ *data|= mask;
+ else
+ *data&= ~mask;
+}
+
+
+// 8 bit cell;
+
+t_mem
+cl_cell8::d()
+{
+ return data?((/*u8_t*/uchar)*data):0;
+}
+
+void
+cl_cell8::d(t_mem v)
+{
+ data?(*data=(/*u8_t*/uchar)v):0;
+}
+
+// 8 bit cell for bit spaces
+
+t_mem
+cl_bit_cell8::d()
+{
+ if (!data)
+ return 0;
+ /*u8_t*/uchar x= (/*u8_t*/uchar) *data;
+ x&= mask;
+ return x?1:0;
+}
+
+void
+cl_bit_cell8::d(t_mem v)
+{
+ if (!data)
+ return;
+ if (v)
+ *data |= (/*u8_t*/uchar)mask;
+ else
+ *data &= ~(/*u8_t*/uchar)mask;
+}
+
+// 16 bit cell;
+
+t_mem
+cl_cell16::d()
+{
+ return data?((u16_t)*data):0;
+}
+
+void
+cl_cell16::d(t_mem v)
+{
+ data?(*data=(u16_t)v):0;
+}
+
+// 16 bit cell for bit spaces
+
+t_mem
+cl_bit_cell16::d()
+{
+ if (!data)
+ return 0;
+ return (((u16_t)*data)&((u16_t)mask))?1:0;
+}
+
+void
+cl_bit_cell16::d(t_mem v)
+{
+ if (!data)
+ return;
+ if (v)
+ *data |= (u16_t)mask;
+ else
+ *data &= ~(u16_t)mask;
+}
+
+
+/*
+ * Memory cell
+ */
+
+cl_memory_cell::cl_memory_cell(uchar awidth)//: cl_base()
+{
+ data= 0;
+ flags= CELL_NON_DECODED;
+ width= awidth;
+ //*data= 0;
+ def_data= 0;
+ operators= NULL;
+ //bank= 0;
+ //banked_data_ptrs= 0;
+#ifdef STATISTIC
+ nuof_writes= nuof_reads= 0;
+#endif
+ mask= 1;
+ int w= width;
+ for (--w; w; w--)
+ {
+ mask<<= 1;
+ mask|= 1;
+ }
+}
+
+cl_memory_cell::~cl_memory_cell(void)
+{
+ if ((flags & CELL_NON_DECODED) &&
+ data)
+ ;//free(data);
+}
+
+int
+cl_memory_cell::init(void)
+{
+ //cl_base::init();
+ data= &def_data;
+ //flags= CELL_NON_DECODED;
+ /*mask= 1;
+ int w= width;
+ for (--w; w; w--)
+ {
+ mask<<= 1;
+ mask|= 1;
+ }*/
+ //set(0/*rand()*/);
+ return(0);
+}
+
+
+uchar
+cl_memory_cell::get_flags(void)
+{
+ return(flags);
+}
+
+bool
+cl_memory_cell::get_flag(enum cell_flag flag)
+{
+ return(flags & flag);
+}
+
+void
+cl_memory_cell::set_flags(uchar what)
+{
+ flags= what;
+}
+
+void
+cl_memory_cell::set_flag(enum cell_flag flag, bool val)
+{
+ if (val)
+ flags|= flag;
+ else
+ flags&= ~(flag);
+}
+
+
+void
+cl_memory_cell::un_decode(void)
+{
+ if ((flags & CELL_NON_DECODED) == 0)
+ {
+ data= &def_data;//(t_mem *)malloc(sizeof(t_mem));
+ flags|= CELL_NON_DECODED;
+ }
+}
+
+void
+cl_memory_cell::decode(class cl_memory_chip *chip, t_addr addr)
+{
+ if (flags & CELL_NON_DECODED)
+ ;//free(data);
+ data= chip->get_slot(addr);
+ if (!data)
+ {
+ data= &def_data;//(t_mem *)malloc(sizeof(t_mem));
+ flags|= CELL_NON_DECODED;
+ }
+ else
+ flags&= ~(CELL_NON_DECODED);
+}
+
+void
+cl_memory_cell::decode(t_mem *data_ptr)
+{
+ if (data_ptr == NULL)
+ {
+ data= &def_data;
+ flags|= CELL_NON_DECODED;
+ }
+ else
+ {
+ data= data_ptr;
+ flags&= ~CELL_NON_DECODED;
+ }
+}
+
+void
+cl_memory_cell::decode(t_mem *data_ptr, t_mem bit_mask)
+{
+ if (data_ptr == NULL)
+ {
+ data= &def_data;
+ flags|= CELL_NON_DECODED;
+ }
+ else
+ {
+ data= data_ptr;
+ flags&= ~CELL_NON_DECODED;
+ }
+ mask= bit_mask;
+}
+
+t_mem
+cl_memory_cell::read(void)
+{
+#ifdef STATISTIC
+ nuof_reads++;
+#endif
+ if (operators)
+ return(operators->read());
+ return /* *data*/d();
+}
+
+t_mem
+cl_memory_cell::read(enum hw_cath skip)
+{
+#ifdef STATISTIC
+ nuof_reads++;
+#endif
+ if (operators)
+ return(operators->read(skip));
+ return /* *data*/d();
+}
+
+t_mem
+cl_memory_cell::get(void)
+{
+ return /* *data*/d();
+}
+
+t_mem
+cl_memory_cell::write(t_mem val)
+{
+#ifdef STATISTIC
+ nuof_writes++;
+#endif
+ if (operators)
+ val= operators->write(val);
+ if (flags & CELL_READ_ONLY)
+ return d();
+ if (width == 1)
+ d(val);
+ else
+ d(val & mask);
+ return d();
+}
+
+t_mem
+cl_memory_cell::set(t_mem val)
+{
+ if (flags & CELL_READ_ONLY)
+ return d();
+ if (width == 1)
+ d(val);
+ else
+ /* *data=*/d(val & mask);
+ return /* *data*/d();
+}
+
+t_mem
+cl_memory_cell::download(t_mem val)
+{
+ if (width == 1)
+ dl(val);
+ else
+ /* *data=*/dl(val & mask);
+ return /* *data*/d();
+}
+
+t_mem
+cl_memory_cell::add(long what)
+{
+ /* *data=*/ d( (*data + what) & mask);
+ return(/* *data*/d());
+}
+
+t_mem
+cl_memory_cell::wadd(long what)
+{
+ t_mem d= (*data + what) & mask;
+ return(write(d));
+}
+
+void
+cl_memory_cell::set_bit1(t_mem bits)
+{
+ bits&= mask;
+ /*(*data)|=*//*d*/set(d()| bits);
+}
+
+void
+cl_memory_cell::write_bit1(t_mem bits)
+{
+ bits&= mask;
+ /*(*data)|=*//*d*/write(d()| bits);
+}
+
+void
+cl_memory_cell::set_bit0(t_mem bits)
+{
+ bits&= mask;
+ /*(*data)&=*//*d*/set(d()& ~bits);
+}
+
+void
+cl_memory_cell::write_bit0(t_mem bits)
+{
+ bits&= mask;
+ /*(*data)&=*//*d*/write(d()& ~bits);
+}
+
+void
+cl_memory_cell::toggle_bits(t_mem bits)
+{
+ bits&= mask;
+ /*d*/set(d() ^ bits);
+}
+
+void
+cl_memory_cell::wtoggle_bits(t_mem bits)
+{
+ bits&= mask;
+ /*d*/write(d() ^ bits);
+}
+
+
+void
+cl_memory_cell::append_operator(class cl_memory_operator *op)
+{
+ if (!operators)
+ operators= op;
+ else
+ {
+ class cl_memory_operator *o= operators, *n;
+ n= o->get_next();
+ while (n)
+ {
+ o= n;
+ n= o->get_next();
+ }
+ o->set_next(op);
+ }
+}
+
+void
+cl_memory_cell::prepend_operator(class cl_memory_operator *op)
+{
+ if (op)
+ {
+ op->set_next(operators);
+ operators= op;
+ }
+}
+
+void
+cl_memory_cell::del_operator(class cl_brk *brk)
+{
+ if (!operators)
+ return;
+ class cl_memory_operator *op= operators;
+ if (operators->match(brk))
+ {
+ operators= op->get_next();
+ delete op;
+ }
+ else
+ {
+ while (op->get_next() &&
+ !op->get_next()->match(brk))
+ op= op->get_next();
+ if (op->get_next())
+ {
+ class cl_memory_operator *m= op->get_next();
+ op->set_next(m->get_next());;
+ delete m;
+ }
+ }
+}
+
+void
+cl_memory_cell::del_operator(class cl_hw *hw)
+{
+ if (!operators)
+ return;
+ class cl_memory_operator *op= operators;
+ if (operators->match(hw))
+ {
+ operators= op->get_next();
+ delete op;
+ }
+ else
+ {
+ while (op->get_next() &&
+ !op->get_next()->match(hw))
+ op= op->get_next();
+ if (op->get_next())
+ {
+ class cl_memory_operator *m= op->get_next();
+ op->set_next(m->get_next());
+ delete m;
+ }
+ }
+}
+
+class cl_banker *
+cl_memory_cell::get_banker(void)
+{
+ class cl_memory_operator *op= operators;
+ class cl_banker *b= NULL;
+
+ while (op)
+ {
+ b= op->get_banker();
+ if (b)
+ return b;
+ op= op->get_next();
+ }
+ return NULL;
+}
+
+class cl_memory_cell *
+cl_memory_cell::add_hw(class cl_hw *hw/*, t_addr addr*/)
+{
+ class cl_hw_operator *o= new cl_hw_operator(this/*, addr*//*, data, mask*/, hw);
+ append_operator(o);
+ return(this);
+}
+
+void
+cl_memory_cell::remove_hw(class cl_hw *hw)
+{
+ del_operator(hw);
+}
+
+/*class cl_hw *
+cl_memory_cell::get_hw(int ith)
+{
+ return(0);
+}*/
+
+class cl_event_handler *
+cl_memory_cell::get_event_handler(void)
+{
+ return(0);
+}
+
+void
+cl_memory_cell::print_info(chars pre, class cl_console_base *con)
+{
+ con->dd_printf("%sFlags:", (char*)pre);
+ if (flags & CELL_VAR)
+ con->dd_printf(" VAR");
+ if (flags & CELL_INST)
+ con->dd_printf(" INST");
+ if (flags & CELL_FETCH_BRK)
+ con->dd_printf(" FBRK");
+ if (flags & CELL_READ_ONLY)
+ con->dd_printf(" RO");
+ if (flags & CELL_NON_DECODED)
+ con->dd_printf(" NDC");
+ con->dd_printf("\n");
+ print_operators(pre, con);
+}
+
+void
+cl_memory_cell::print_operators(chars pre, class cl_console_base *con)
+{
+ class cl_memory_operator *o= operators;
+ if (!operators)
+ return;
+ int i= 0;
+ while (o)
+ {
+ printf("%s %02d. %s\n", (char*)pre, i, o->get_name("?"));
+ i++;
+ o= o->get_next();
+ }
+}
+
+
+/*
+ * Dummy cell for non-existent addresses
+ */
+
+t_mem
+cl_dummy_cell::write(t_mem val)
+{
+#ifdef STATISTIC
+ nuof_writes++;
+#endif
+ *data= rand() & mask;
+ return(*data);
+}
+
+t_mem
+cl_dummy_cell::set(t_mem val)
+{
+ *data= rand() & mask;
+ return(*data);
+}
+
+
+/*
+ * Address space
+ */
+
+cl_address_space::cl_address_space(const char *id,
+ t_addr astart, t_addr asize, int awidth):
+ cl_memory(id, asize, awidth)
+{
+ class cl_memory_cell c(awidth);
+ class cl_bit_cell8 bc8(awidth);
+ class cl_cell8 c8(awidth);
+ class cl_cell16 c16(awidth);
+ class cl_memory_cell *cell= &c;
+ start_address= astart;
+ decoders= new cl_decoder_list(2, 2, false);
+ cella= (class cl_memory_cell *)malloc(size * sizeof(class cl_memory_cell));
+ if (awidth == 1)
+ cell= &bc8;
+ else if (awidth <= 8)
+ cell= &c8;
+ else if (awidth <= 16)
+ cell= &c16;
+ //cell->init();
+ int i;
+ for (i= 0; i < size; i++)
+ {
+ void *p1= &(cella[i]);
+ void *p2= cell;
+ memcpy(p1, p2, sizeof(c));
+ cella[i].init();
+ }
+ dummy= new cl_dummy_cell(awidth);
+ dummy->init();
+}
+
+cl_address_space::~cl_address_space(void)
+{
+ delete decoders;
+ int i;
+ for (i= 0; i < size; i++)
+ {
+ cella[i].~cl_memory_cell();
+ }
+ free(cella);
+ delete dummy;
+}
+
+
+t_mem
+cl_address_space::read(t_addr addr)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ return(dummy->read());
+ }
+ return(cella[idx].read());
+}
+
+t_mem
+cl_address_space::read(t_addr addr, enum hw_cath skip)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ return(dummy->read());
+ }
+ return(cella[idx].read(skip));
+}
+
+t_mem
+cl_address_space::get(t_addr addr)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ return(dummy->get());
+ }
+ return cella[idx].get();//*(cella[idx].data);
+}
+
+t_mem
+cl_address_space::write(t_addr addr, t_mem val)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ return(dummy->write(val));
+ }
+ //if (cella[idx].get_flag(CELL_NON_DECODED)) printf("%s[%d] nondec write=%x\n",get_name(),addr,val);
+ return(cella[idx].write(val));
+}
+
+void
+cl_address_space::set(t_addr addr, t_mem val)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ dummy->set(val);
+ return;
+ }
+ /* *(cella[idx].data)=*/cella[idx].set( val/*&(data_mask)*/);
+}
+
+void
+cl_address_space::download(t_addr addr, t_mem val)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ dummy->download(val);
+ return;
+ }
+ /* *(cella[idx].data)=*/cella[idx].download( val/*&(data_mask)*/);
+}
+
+t_mem
+cl_address_space::wadd(t_addr addr, long what)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ }
+ return(cella[idx].wadd(what));
+}
+
+/* Set or clear bits, without callbacks */
+
+void
+cl_address_space::set_bit1(t_addr addr, t_mem bits)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return;
+ class cl_memory_cell *cell= &(cella[idx]);
+ cell->set_bit1(bits);
+}
+
+void
+cl_address_space::set_bit0(t_addr addr, t_mem bits)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return;
+ class cl_memory_cell *cell= &(cella[idx]);
+ cell->set_bit0(bits);
+}
+
+
+class cl_memory_cell *
+cl_address_space::get_cell(t_addr addr)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ err_inv_addr(addr);
+ return(dummy);
+ }
+ return(&cella[idx]);
+}
+
+
+int
+cl_address_space::get_cell_flag(t_addr addr)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ return(dummy->get_flags());
+ }
+ return(cella[idx].get_flags());
+}
+
+bool
+cl_address_space::get_cell_flag(t_addr addr, enum cell_flag flag)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ {
+ return(dummy->get_flag(flag));
+ }
+ return(cella[idx].get_flag(flag));
+}
+
+void
+cl_address_space::set_cell_flag(t_addr addr, bool set_to, enum cell_flag flag)
+{
+ t_addr idx= addr-start_address;
+ class cl_memory_cell *cell;
+
+ if (idx >= size ||
+ addr < start_address)
+ {
+ cell= dummy;
+ }
+ else
+ cell= &cella[idx];
+ cell->set_flag(flag, set_to);
+}
+
+void
+cl_address_space::set_cell_flag(t_addr start_addr, t_addr end_addr, bool set_to, enum cell_flag flag)
+{
+ t_addr a;
+
+ for (a= start_addr; a <= end_addr; a++)
+ set_cell_flag(a, set_to, flag);
+}
+
+class cl_memory_cell *
+cl_address_space::search_cell(enum cell_flag flag, bool value, t_addr *addr)
+{
+ int i;
+
+ for (i= 0; i < size; i++)
+ {
+ bool f= cella[i].get_flag(flag);
+ if ((f && value) ||
+ (!f && !value))
+ {
+ if (addr)
+ *addr= i;
+ return &cella[i];
+ }
+ }
+ return NULL;
+}
+
+bool
+cl_address_space::is_owned(class cl_memory_cell *cell, t_addr *addr)
+{
+ if (cell < cella)
+ return false;
+ if (cell > &cella[size-1])
+ return false;
+ int idx= cell - cella;
+ if (addr)
+ *addr= start_address+idx;
+ return true;
+}
+
+class cl_address_decoder *
+cl_address_space::get_decoder_of(t_addr addr)
+{
+ class cl_address_decoder *dc;
+ int i;
+ for (i= 0; i < decoders->count; i++)
+ {
+ dc= (class cl_address_decoder *)(decoders->at(i));
+ if (dc->covers(addr, addr))
+ return dc;
+ }
+ return NULL;
+}
+
+bool
+cl_address_space::decode_cell(t_addr addr,
+ class cl_memory_chip *chip, t_addr chipaddr)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return(false);
+ class cl_memory_cell *cell= &cella[idx];
+
+ if (!cell->get_flag(CELL_NON_DECODED))
+ {
+ // un-decode first!
+ cell->un_decode();
+ }
+ cell->decode(chip, chipaddr);
+
+ return(!cell->get_flag(CELL_NON_DECODED));
+}
+
+void
+cl_address_space::undecode_cell(t_addr addr)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return;
+ class cl_memory_cell *cell= &cella[idx];
+
+ cell->un_decode();
+}
+
+void
+cl_address_space::undecode_area(class cl_address_decoder *skip,
+ t_addr begin, t_addr end,
+ class cl_console_base *con)
+{
+#define D if (con) con->debug
+ //#define D printf
+ D("Undecoding area 0x%lx-0x%lx of %s (skip=%s)\n", begin, end, get_name(), skip?(skip->get_name()):"-");
+ int i;
+ for (i= 0; i < decoders->count; i++)
+ {
+ class cl_address_decoder *d=
+ dynamic_cast<class cl_address_decoder *>(decoders->object_at(i));
+ if (!d ||
+ d == skip)
+ continue;
+ D(" Checking decoder 0x%lx-0x%lx -> %s[0x%lx]\n",
+ d->as_begin, d->as_end, (d->memchip)?(d->memchip->get_name()):"(none)", d->chip_begin);
+ if (d->fully_covered_by(begin, end))
+ {
+ // decoder can be removed
+ D(" Can be removed\n");
+ decoders->disconn(d);
+ i--;
+ delete d;
+ if (decoders->count == 0)
+ break;
+ }
+ else if (d->covers(begin, end))
+ {
+ // decoder must be split
+ D(" Must be split\n");
+ class cl_address_decoder *nd= d->split(begin, end);
+ D(" After split:\n");
+ D(" 0x%lx-0x%lx -> %s[0x%lx]\n",
+ d->as_begin, d->as_end, (d->memchip)?(d->memchip->get_name()):"(none)", d->chip_begin);
+ if (nd)
+ {
+ decoders->add(nd);
+ D(" 0x%lx-0x%lx -> %s[0x%lx]\n",
+ nd->as_begin, nd->as_end, (nd->memchip)?(nd->memchip->get_name()):"none", nd->chip_begin);
+ nd->activate(con);
+ }
+ }
+ else if (d->is_in(begin, end))
+ {
+ // decoder sould shrink
+ D(" Sould shrink\n");
+ if (d->shrink_out_of(begin, end))
+ {
+ D(" Can be removed after shrink\n");
+ decoders->disconn(d);
+ i--;
+ delete d;
+ if (decoders->count == 0)
+ break;
+ }
+ else
+ {
+ D(" Shrinked to 0x%lx-0x%lx -> %s[0x%lx]\n",
+ d->as_begin, d->as_end, (d->memchip)?(d->memchip->get_name()):"(none)", d->chip_begin);
+ }
+ }
+ }
+#undef D
+}
+
+
+class cl_memory_cell *
+cl_address_space::register_hw(t_addr addr, class cl_hw *hw,
+ bool announce)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return(0);
+ class cl_memory_cell *cell= &cella[idx];
+ cell->add_hw(hw/*, addr*/);
+ if (announce)
+ ;//uc->sim->/*app->*/mem_cell_changed(this, addr);//FIXME
+ return(cell);
+}
+
+void
+cl_address_space::unregister_hw(class cl_hw *hw)
+{
+ t_addr idx;
+
+ for (idx= 0; idx < size; idx++)
+ {
+ class cl_memory_cell *cell= &cella[idx];
+ cell->remove_hw(hw);
+ }
+}
+
+void
+cl_address_space::set_brk(t_addr addr, class cl_brk *brk)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return;
+ class cl_memory_cell *cell= &cella[idx];
+ class cl_memory_operator *op;
+
+ switch (brk->get_event())
+ {
+ case brkWRITE: case brkWXRAM: case brkWIRAM: case brkWSFR:
+ //e= 'W';
+ op= new cl_write_operator(cell/*, addr*/, //cell->get_data(), cell->get_mask(),
+ uc, brk);
+ break;
+ case brkREAD: case brkRXRAM: case brkRCODE: case brkRIRAM: case brkRSFR:
+ //e= 'R';
+ op= new cl_read_operator(cell/*, addr*/, //cell->get_data(), cell->get_mask(),
+ uc, brk);
+ break;
+ case brkNONE:
+ set_cell_flag(addr, true, CELL_FETCH_BRK);
+ return;
+ break;
+ default:
+ //e= '.';
+ op= 0;
+ break;
+ }
+ if (op)
+ cell->append_operator(op);
+}
+
+void
+cl_address_space::del_brk(t_addr addr, class cl_brk *brk)
+{
+ t_addr idx= addr-start_address;
+ if (idx >= size ||
+ addr < start_address)
+ return;
+ class cl_memory_cell *cell= &cella[idx];
+
+ switch (brk->get_event())
+ {
+ case brkWRITE: case brkWXRAM: case brkWIRAM: case brkWSFR:
+ case brkREAD: case brkRXRAM: case brkRCODE: case brkRIRAM: case brkRSFR:
+ cell->del_operator(brk);
+ break;
+ case brkNONE:
+ set_cell_flag(addr, false, CELL_FETCH_BRK);
+ return;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+cl_address_space::print_info(chars pre, class cl_console_base *con)
+{
+ char *n= (char*)(get_name());
+ if (!hidden)
+ {
+ con->dd_printf("%s0x%06x-0x%06x %8d %s (%d,%s,%s)\n", (char*)pre,
+ AU(get_start_address()),
+ AU(highest_valid_address()),
+ AU(get_size()),
+ n,
+ width, data_format, addr_format);
+ }
+}
+
+
+/*
+ * List of address spaces
+ */
+
+cl_address_space_list::cl_address_space_list(class cl_uc *the_uc):
+ cl_list(2, 2, "address spaces")
+{
+ uc= the_uc;
+}
+
+t_index
+cl_address_space_list::add(class cl_address_space *mem)
+{
+ mem->set_uc(uc);
+ t_index ret= cl_list::add(mem);
+ if (uc)
+ {
+ class cl_event_address_space_added e(mem);
+ uc->handle_event(e);
+ }
+ return(ret);
+}
+
+
+/*
+ * Memory chip
+ */
+
+cl_memory_chip::cl_memory_chip(const char *id,
+ int asize,
+ int awidth,
+ int initial):
+ cl_memory(id, asize, awidth)
+{
+ array= (t_mem *)malloc(size * sizeof(t_mem));
+ init_value= initial;
+ array_is_mine= true;
+}
+
+cl_memory_chip::cl_memory_chip(const char *id,
+ int asize,
+ int awidth,
+ t_mem *aarray):
+ cl_memory(id, asize, awidth)
+{
+ array= aarray;
+ init_value= 0;
+ array_is_mine= false;
+}
+
+cl_memory_chip::~cl_memory_chip(void)
+{
+ if (array &&
+ array_is_mine)
+ free(array);
+}
+
+int
+cl_memory_chip::init(void)
+{
+ cl_memory::init();
+ int i;
+ if (array_is_mine)
+ {
+ for (i= 0; i < size; i++)
+ set(i,
+ (init_value<0)?rand():(init_value)
+ );
+ }
+ return(0);
+}
+
+
+t_mem *
+cl_memory_chip::get_slot(t_addr addr)
+{
+ if (!array ||
+ size <= addr)
+ return(0);
+ return(&array[addr]);
+}
+
+t_addr
+cl_memory_chip::is_slot(t_mem *data_ptr)
+{
+ if (data_ptr < &(array[0]))
+ return -1;
+ if (data_ptr > &(array[size-1]))
+ return -2;
+ return data_ptr - &(array[0]);
+}
+
+t_mem
+cl_memory_chip::get(t_addr addr)
+{
+ if (!array ||
+ size <= addr)
+ return(0);
+ return(array[addr]);
+}
+
+void
+cl_memory_chip::set(t_addr addr, t_mem val)
+{
+ if (!array ||
+ size <= addr)
+ return;
+ array[addr]= val & data_mask;
+}
+
+void
+cl_memory_chip::set_bit1(t_addr addr, t_mem bits)
+{
+ if (!array ||
+ size <= addr)
+ return;
+ array[addr]|= (bits & data_mask);
+}
+
+void
+cl_memory_chip::set_bit0(t_addr addr, t_mem bits)
+{
+ if (!array ||
+ size <= addr)
+ return;
+ array[addr]&= ((~bits) & data_mask);
+}
+
+void
+cl_memory_chip::print_info(chars pre, class cl_console_base *con)
+{
+ char *n= (char*)(get_name());
+ if (!hidden)
+ {
+ //con->dd_printf(pre0);
+ con->dd_printf("%s0x%06x-0x%06x %8d %s (%d,%s,%s)\n", (char*)pre,
+ AU(get_start_address()),
+ AU(highest_valid_address()),
+ AU(get_size()),
+ n,
+ width, data_format, addr_format);
+ }
+}
+
+
+/*
+ * Address decoder
+ */
+
+cl_address_decoder::cl_address_decoder(class cl_memory *as,
+ class cl_memory *chip,
+ t_addr asb, t_addr ase, t_addr cb)
+{
+ if (as && (as->is_address_space()))
+ address_space= (class cl_address_space *)as;
+ else
+ address_space= 0;
+ if (chip && (chip->is_chip()))
+ memchip= (class cl_memory_chip *)chip;
+ else
+ memchip= 0;
+ as_begin= asb;
+ as_end= ase;
+ chip_begin= cb;
+ activated= false;
+}
+
+cl_address_decoder::~cl_address_decoder(void)
+{
+ t_addr a;
+ if (address_space)
+ for (a= as_begin; a <= as_end; a++)
+ address_space->undecode_cell(a);
+}
+
+int
+cl_address_decoder::init(void)
+{
+ return(0);
+}
+
+
+bool
+cl_address_decoder::activate(class cl_console_base *con)
+{
+#define D if (con) con->debug
+ //#define D printf
+ D("Activation of an address decoder %s (%s[%06lx-%06lx]\n", get_name(""), address_space->get_name(), as_begin, as_end);
+ if (activated)
+ {
+ D("Already activated\n");
+ return(false);
+ }
+ if (!address_space ||
+ !address_space->is_address_space())
+ {
+ D("No or non address space\n");
+ return(false);
+ }
+ if (!memchip ||
+ !memchip->is_chip())
+ {
+ D("No or non memory chip\n");
+ return(false);
+ }
+ if (as_begin > as_end)
+ {
+ D("Wrong address area specification\n");
+ return(false);
+ }
+ if (chip_begin >= memchip->get_size())
+ {
+ D("Wrong chip area specification\n");
+ return(false);
+ }
+ if (as_begin < address_space->start_address ||
+ as_end >= address_space->start_address + address_space->get_size())
+ {
+ D("Specified area is out of address space\n");
+ return(false);
+ }
+ if (as_end-as_begin > memchip->get_size()-chip_begin)
+ {
+ D("Specified area is out of chip size\n");
+ return(false);
+ }
+
+ address_space->undecode_area(this, as_begin, as_end, con);
+
+ D("Decoder maps %s[%06lx-%06lx] -> %s[%06lx]...\n",address_space->get_name(),as_begin,as_end,memchip->get_name(),chip_begin);
+ t_addr asa, ca;
+ for (asa= as_begin, ca= chip_begin;
+ asa <= as_end;
+ asa++, ca++)
+ {
+ if (!address_space->decode_cell(asa, memchip, ca))
+ {
+ D("Decoding 0x%06lx->0x%06lx failed\n", asa, ca);
+ }
+ }
+ activated= true;
+
+#undef D
+ return(activated);
+}
+
+/* Check if this DEC is fully within the specified area
+
+ as_begin....................as_end
+ ^ ^
+ begin end
+
+*/
+
+bool
+cl_address_decoder::fully_covered_by(t_addr begin, t_addr end)
+{
+ if (begin <= as_begin &&
+ end >= as_end)
+ return(true);
+ return(false);
+}
+
+/* Check if some part of this DEC is in the specified area:
+
+ as_begin......................as_end
+ ^ ^
+ begin end
+
+ as_begin......................as_end
+^ ^
+begin end
+
+*/
+
+bool
+cl_address_decoder::is_in(t_addr begin, t_addr end)
+{
+ if (begin >= as_begin &&
+ begin <= as_end)
+ return(true);
+ if (end >= as_begin &&
+ end <= as_end)
+ return(true);
+ return(false);
+}
+
+/* Check if this DEC covers the specified area:
+
+ as_begin....................as_end
+ ^ ^
+ begin end
+
+*/
+
+bool
+cl_address_decoder::covers(t_addr begin, t_addr end)
+{
+ if (begin >= as_begin &&
+ end <= as_end)
+ return(true);
+ return(false);
+}
+
+
+/* Returns TRUE if shrunken decoder is unnecessary */
+
+bool
+cl_address_decoder::shrink_out_of(t_addr begin, t_addr end)
+{
+ t_addr a= as_begin;
+
+ if (!address_space)
+ return(true);
+ if (begin > a)
+ a= begin;
+ while (a <= end &&
+ a <= as_end)
+ {
+ address_space->undecode_cell(a);
+ a++;
+ }
+ if (begin > as_begin)
+ as_end= begin-1;
+ if (as_end > end)
+ {
+ chip_begin+= (end-as_begin+1);
+ as_begin= end+1;
+ }
+ if (as_end < as_begin)
+ return(true);
+ return(false);
+}
+
+class cl_address_decoder *
+cl_address_decoder::split(t_addr begin, t_addr end)
+{
+ class cl_address_decoder *nd= 0;
+ if (begin > as_begin)
+ {
+ if (as_end > end)
+ nd= new cl_address_decoder(address_space, memchip,
+ end+1, as_end, chip_begin+(end-as_begin)+1);
+ shrink_out_of(begin, as_end);
+ }
+ else if (end < as_end)
+ {
+ if (as_begin < begin)
+ nd= new cl_address_decoder(address_space, memchip,
+ as_begin, begin-1, chip_begin);
+ shrink_out_of(as_begin, end);
+ }
+ if (nd)
+ nd->init();
+ return(nd);
+}
+
+void
+cl_address_decoder::print_info(chars pre, class cl_console_base *con)
+{
+ if (address_space &&
+ address_space->hidden)
+ return;
+ if (memchip &&
+ memchip->hidden)
+ return;
+ con->dd_printf(pre);
+ if (address_space)
+ {
+ con->dd_printf("%s ", address_space->get_name("unknown"));
+ con->dd_printf(address_space->addr_format, as_begin);
+ con->dd_printf(" ");
+ con->dd_printf(address_space->addr_format, as_end);
+ }
+ else
+ con->dd_printf("x");
+ con->dd_printf(" -> ");
+ if (memchip)
+ {
+ con->dd_printf("%s ", memchip->get_name("unknown"));
+ con->dd_printf(memchip->addr_format, chip_begin);
+ }
+ else
+ con->dd_printf("x");
+ con->dd_printf(" %s\n", (activated)?"activated":"inactive");
+}
+
+
+/*
+ * Bank switcher
+ */
+
+cl_banker::cl_banker(class cl_address_space *the_banker_as,
+ t_addr the_banker_addr,
+ t_mem the_banker_mask,
+ //int the_banker_shift,
+ class cl_address_space *the_as,
+ t_addr the_asb,
+ t_addr the_ase):
+ cl_address_decoder(the_as, NULL, the_asb, the_ase, (t_addr)-1)
+{
+ banker_as= the_banker_as;
+ banker_addr= the_banker_addr;
+ banker_mask= the_banker_mask;
+ //banker_shift= the_banker_shift;
+ banker2_as= NULL;
+ banker2_addr= 0;
+ banker2_mask= 0;
+ banker2_shift= 0;
+ nuof_banks= 0;
+ banks= 0;
+ //bank_ptrs= 0;
+ bank= -1;
+}
+
+cl_banker::cl_banker(class cl_address_space *the_banker_as,
+ t_addr the_banker_addr,
+ t_mem the_banker_mask,
+ //int the_banker_shift,
+ class cl_address_space *the_banker2_as,
+ t_addr the_banker2_addr,
+ t_mem the_banker2_mask,
+ int the_banker2_shift,
+ class cl_address_space *the_as,
+ t_addr the_asb,
+ t_addr the_ase):
+ cl_address_decoder(the_as, NULL, the_asb, the_ase, (t_addr)-1)
+{
+ banker_as= the_banker_as;
+ banker_addr= the_banker_addr;
+ banker_mask= the_banker_mask;
+ //banker_shift= the_banker_shift;
+ banker2_as= the_banker2_as;
+ banker2_addr= the_banker2_addr;
+ banker2_mask= the_banker2_mask;
+ banker2_shift= the_banker2_shift;
+ nuof_banks= 0;
+ banks= 0;
+ //bank_ptrs= 0;
+ bank= -1;
+}
+
+int
+cl_banker::init()
+{
+ int m= banker_mask;
+ int b, b2;
+
+ shift_by= 0;
+ shift2_by= 0;
+ if (m == 0)
+ nuof_banks= 0;
+ else
+ {
+ while ((m&1) == 0)
+ m>>= 1, shift_by++;
+ b= 1;
+ m>>= 1;
+ while ((m&1) != 0)
+ {
+ m>>= 1;
+ b++;
+ }
+ nuof_banks= 1 << b;
+ }
+ shift2_by= 0;
+ if (banker2_as &&
+ banker2_mask)
+ {
+ m= banker2_mask;
+ while ((m&1) == 0)
+ m>>=1, shift2_by++;
+ b2= 1;
+ m>>= 1;
+ while ((m&1) != 0)
+ m>>= 1, b2++;
+ if (b2)
+ nuof_banks*= (1 << b2);
+ }
+ if (nuof_banks > 0)
+ {
+ banks= (class cl_address_decoder **)malloc(nuof_banks * sizeof(class cl_address_decoder *));
+ //bank_ptrs= (t_mem **)calloc(nuof_banks*(as_end-as_begin+1), sizeof(t_mem *));
+ for (b= 0; b < nuof_banks; b++)
+ {
+ banks[b]= NULL;
+ }
+ }
+
+ class cl_memory_cell *c= banker_as->get_cell(banker_addr);
+ if (c)
+ {
+ class cl_bank_switcher_operator *o=
+ new cl_bank_switcher_operator(c/*, banker_addr*/, this);
+ c->prepend_operator(o);
+ }
+ if (banker2_as &&
+ banker2_mask)
+ {
+ c= banker2_as->get_cell(banker2_addr);
+ if (c)
+ {
+ class cl_bank_switcher_operator *o=
+ new cl_bank_switcher_operator(c/*, banker_addr*/, this);
+ c->prepend_operator(o);
+ }
+ }
+ return 0;
+}
+
+cl_banker::~cl_banker()
+{
+ int i;
+ if (banks)
+ {
+ for (i= 0; i < nuof_banks; i++)
+ {
+ if (banks[i])
+ delete banks[i];
+ }
+ free(banks);
+ }
+ //if (bank_ptrs) free(bank_ptrs);
+}
+
+void
+cl_banker::add_bank(int bank_nr, class cl_memory *chip, t_addr chip_start)
+{
+ if (!chip)
+ return;
+ if (!address_space)
+ return;
+ if (!chip->is_chip())
+ return;
+
+ if (bank_nr >= nuof_banks)
+ return;
+
+ class cl_address_decoder *ad= new cl_address_decoder(address_space,
+ chip,
+ as_begin, as_end,
+ chip_start);
+ ad->init();
+ if (banks[bank_nr])
+ {
+ delete banks[bank_nr];
+ banks[bank_nr]= 0;
+ }
+ banks[bank_nr]= ad;
+ /*
+ t_addr a, s, i;
+ s= as_end - as_begin + 1;
+ for (i= 0; i < s; i++)
+ {
+ a= chip_start + i;
+ //bank_ptrs[bank_nr*s + i]= ad->memchip->get_slot(a);
+ }
+ */
+ activate(0);
+}
+
+t_mem
+cl_banker::actual_bank()
+{
+ //t_mem m= banker_mask;
+ t_mem v= banker_as->read(banker_addr) & banker_mask;
+ t_mem v2;
+
+ v= (v >> shift_by);
+ if (banker2_as &&
+ banker2_mask)
+ {
+ v2= banker2_as->read(banker2_addr) & banker2_mask;
+ v2>>= shift2_by;
+ v2= v2 << banker2_shift;
+ v= v | v2;
+ }
+ return v;
+}
+
+bool
+cl_banker::activate(class cl_console_base *con)
+{
+ int b= actual_bank();
+ t_addr i, s;
+ t_mem *data;
+ class cl_memory_cell *c;
+
+ if (b == bank)
+ return true;
+ if (banks[b] == NULL)
+ return true;
+ s= as_end - as_begin + 1;
+ for (i= 0; i < s; i++)
+ {
+ t_addr ca= banks[b]->chip_begin + i;
+ data= banks[b]->memchip->get_slot(ca);
+ c= address_space->get_cell(as_begin+i);
+ c->decode(data);
+ }
+ bank= b;
+
+ return true;
+}
+
+bool
+cl_banker::switch_to(int bank_nr, class cl_console_base *con)
+{
+ int b= bank_nr;//actual_bank();
+ t_addr i, s;
+ t_mem *data;
+ class cl_memory_cell *c;
+
+ if (b == bank)
+ return true;
+ if (banks[b] == NULL)
+ return true;
+ s= as_end - as_begin + 1;
+ for (i= 0; i < s; i++)
+ {
+ t_addr ca= banks[b]->chip_begin + i;
+ data= banks[b]->memchip->get_slot(ca);
+ c= address_space->get_cell(as_begin+i);
+ c->decode(data);
+ }
+ bank= b;
+
+ return true;
+}
+
+void
+cl_banker::print_info(chars pre, class cl_console_base *con)
+{
+ int b;
+ con->dd_printf(pre);
+ //con->dd_printf(" banked area= ");
+ if (address_space)
+ {
+ con->dd_printf("%s ", address_space->get_name("unknown"));
+ con->dd_printf(address_space->addr_format, as_begin);
+ con->dd_printf(" ");
+ con->dd_printf(address_space->addr_format, as_end);
+ }
+ else
+ con->dd_printf("x");
+ con->dd_printf(" -> banked\n");
+
+ con->dd_printf(pre);
+ con->dd_printf(" bank selector: %s[", banker_as->get_name("unknown"));
+ con->dd_printf(banker_as->addr_format, banker_addr);
+ con->dd_printf("] mask=0x%x banks=%d act=%d\n",
+ banker_mask, nuof_banks,
+ b= actual_bank());
+
+ con->dd_printf(pre);
+ con->dd_printf(" banks:\n");
+
+ class cl_address_decoder *dc;
+ int i;
+ for (i= 0; i < nuof_banks; i++)
+ {
+ dc= (class cl_address_decoder *)(banks[i]);
+ con->dd_printf(pre);
+ con->dd_printf(" %c %2d. ", (b==i)?'*':' ', i);
+ if (dc)
+ {
+ if (dc->memchip)
+ {
+ con->dd_printf("%s ", dc->memchip->get_name("unknown"));
+ con->dd_printf(dc->memchip->addr_format, dc->chip_begin);
+ }
+ else
+ con->dd_printf("x");
+ }
+ else
+ con->dd_printf("-");
+ con->dd_printf("\n");
+ }
+}
+
+
+/*
+ * Bit bander
+ */
+
+cl_bander::cl_bander(class cl_address_space *the_as,
+ t_addr the_asb,
+ t_addr the_ase,
+ class cl_memory *the_chip,
+ t_addr the_cb,
+ int the_bpc,
+ int the_distance):
+ cl_address_decoder(the_as, the_chip, the_asb, the_ase, the_cb)
+{
+ bpc= the_bpc;
+ distance= the_distance;
+}
+
+bool
+cl_bander::activate(class cl_console_base *con)
+{
+ address_space->undecode_area(this, as_begin, as_end, con);
+
+ t_addr asa, ca;
+ int b, m;
+ for (asa= as_begin, ca= chip_begin, b= 0, m= 1;
+ asa <= as_end;
+ asa++)
+ {
+ if (b >= bpc)
+ {
+ ca+= distance;
+ b= 0;
+ m= 1;
+ }
+ t_mem *slot= memchip->get_slot(ca);
+ cl_memory_cell *c= address_space->get_cell(asa);
+ c->decode(slot, m);
+ b++;
+ m<<= 1;
+ }
+ return activated= true;
+}
+
+void
+cl_bander::print_info(chars pre, class cl_console_base *con)
+{
+ if (address_space &&
+ address_space->hidden)
+ return;
+ if (memchip &&
+ memchip->hidden)
+ return;
+ con->dd_printf(pre);
+ if (address_space)
+ {
+ con->dd_printf("%s ", address_space->get_name("unknown"));
+ con->dd_printf(address_space->addr_format, as_begin);
+ con->dd_printf(" ");
+ con->dd_printf(address_space->addr_format, as_end);
+ }
+ else
+ con->dd_printf("x");
+ con->dd_printf(" -> bander(%d/%d) ", bpc, distance);
+ if (memchip)
+ {
+ con->dd_printf("%s ", memchip->get_name("unknown"));
+ con->dd_printf(memchip->addr_format, chip_begin);
+ }
+ else
+ con->dd_printf("x");
+ con->dd_printf(" %s\n", (activated)?"activated":"inactive");
+}
+
+
+/*
+ * List of address decoders
+ */
+
+cl_decoder_list::cl_decoder_list(t_index alimit, t_index adelta, bool bychip):
+ cl_sorted_list(alimit, adelta, "decoder list")
+{
+ Duplicates= true;
+ by_chip= bychip;
+}
+
+void *
+cl_decoder_list::key_of(void *item)
+{
+ class cl_address_decoder *d= (class cl_address_decoder *)item;
+ if (by_chip)
+ return(&(d->chip_begin));
+ else
+ return(&(d->as_begin));
+}
+
+int
+cl_decoder_list::compare(void *key1, void *key2)
+{
+ t_addr k1= *((t_addr*)key1), k2= *((t_addr*)key2);
+ if (k1 == k2)
+ return(0);
+ else if (k1 > k2)
+ return(1);
+ return(-1);
+}
+
+
+/*
+ * Errors in memory handling
+ */
+
+/* All of memory errors */
+
+cl_error_mem::cl_error_mem(class cl_memory *amem, t_addr aaddr)
+{
+ mem= amem;
+ addr= aaddr;
+ classification= mem_error_registry.find("memory");
+}
+
+/* Invalid address in memory access */
+
+cl_error_mem_invalid_address::
+cl_error_mem_invalid_address(class cl_memory *amem, t_addr aaddr):
+ cl_error_mem(amem, aaddr)
+{
+ classification= mem_error_registry.find("invalid_address");
+}
+
+void
+cl_error_mem_invalid_address::print(class cl_commander_base *c)
+{
+ //FILE *f= c->get_fout();
+ /*cmd_fprintf(f,*/c->dd_printf("%s: invalid address ", get_type_name());
+ /*cmd_fprintf(f,*/c->dd_printf(mem->addr_format, addr);
+ /*cmd_fprintf(f,*/c->dd_printf(" in memory %s.\n", mem->get_name());
+}
+
+/* Non-decoded address space access */
+
+cl_error_mem_non_decoded::
+cl_error_mem_non_decoded(class cl_memory *amem, t_addr aaddr):
+ cl_error_mem(amem, aaddr)
+{
+ classification= mem_error_registry.find("non_decoded");
+}
+
+void
+cl_error_mem_non_decoded::print(class cl_commander_base *c)
+{
+ //FILE *f= c->get_fout();
+ /*cmd_fprintf(f,*/c->dd_printf("%s: access of non-decoded address ", get_type_name());
+ /*cmd_fprintf(f,*/c->dd_printf(mem->addr_format, addr);
+ /*cmd_fprintf(f,*/c->dd_printf(" in memory %s.\n", mem->get_name());
+}
+
+cl_mem_error_registry::cl_mem_error_registry(void)
+{
+ class cl_error_class *prev = mem_error_registry.find("non-classified");
+ prev = register_error(new cl_error_class(err_error, "memory", prev, ERROR_OFF));
+ prev = register_error(new cl_error_class(err_error, "invalid_address", prev));
+ prev = register_error(new cl_error_class(err_error, "non_decoded", prev));
+}
+
+/* End of mem.cc */