X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=sim%2Fucsim%2Fsim.src%2Fmem.cc;h=e5a32c93ced7b0fb5597b39bb78d421d5e3d52ef;hb=2c22a2ef761868ef7e4b1b82d33261b49841b458;hp=5c9aa49f096bc4ce32a99233fae6a0aef9397c83;hpb=f27cbdc6513b26748661452e50ed3af99fac16a2;p=fw%2Fsdcc diff --git a/sim/ucsim/sim.src/mem.cc b/sim/ucsim/sim.src/mem.cc index 5c9aa49f..e5a32c93 100644 --- a/sim/ucsim/sim.src/mem.cc +++ b/sim/ucsim/sim.src/mem.cc @@ -7,22 +7,24 @@ * */ -/* 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. */ +/* + 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 @@ -34,8 +36,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "utils.h" #include "globals.h" +// sim +#include "simcl.h" + // cmd #include "newcmdcl.h" +#include "cmdutil.h" // local #include "memcl.h" @@ -43,117 +49,31 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* - * Memory location handled specially by a hw element + * 3rd version of memory system */ -cl_memloc::cl_memloc(t_addr addr): +cl_memory::cl_memory(char *id, t_addr asize, int awidth): 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= DD_FALSE; + size= asize; + set_name(id); + addr_format= data_format= 0; + width= awidth; + start_address= 0; + uc= 0; } -void * -cl_memloc_coll::key_of(void *item) +cl_memory::~cl_memory(void) { - return(&(((class cl_memloc *)item)->address)); + if (addr_format) + free(addr_format); + if (data_format) + free(data_format); } 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 - ****************************************************************************** - */ - -cl_mem::cl_mem(enum mem_class atype, char *aclass_name, - t_addr asize, int awidth): - cl_guiobj() +cl_memory::init(void) { - int i; - - 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) - 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= (char *)malloc(10); sprintf(addr_format, "0x%%0%dx", size-1<=0xf?1: @@ -164,179 +84,105 @@ cl_mem::cl_mem(enum mem_class atype, char *aclass_name, (size-1<=0xffffff?6:12)))))); data_format= (char *)malloc(10); sprintf(data_format, "%%0%dx", width/4+((width%4)?1: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; - - for (i= 0; i < size; i++) - set(i, (type==MEM_ROM)?(-1):0); + data_mask= 1; + int w= width; + for (--w; w; w--) + { + data_mask<<= 1; + data_mask|= 1; + } + dump_finished= start_address; return(0); } -char * -cl_mem::id_string(void) -{ - char *s= get_id_string(mem_ids, type); - - return(s?s:(char*)"NONE"); -} -t_mem -cl_mem::read(t_addr addr) +bool +cl_memory::valid_address(t_addr addr) { - class cl_memloc *loc; - - if (addr >= size) - { - //FIXME - fprintf(stderr, "Address 0x%06lx is over 0x%06lx\n", addr, 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); + return(addr >= start_address && + addr < start_address+size); } -t_mem -cl_mem::get(t_addr addr) +t_addr +cl_memory::inc_address(t_addr addr, int val) { - 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); + if (!start_address) + return(((signed)addr+val)%size); + addr-= start_address; + addr+= val; + addr%= size; + addr+= start_address; + return(addr); } - -/* - * Modify memory location - */ - -/* Write calls callbacks of HW elements */ - -void -cl_mem::write(t_addr addr, t_mem *val) +t_addr +cl_memory::inc_address(t_addr addr) { - 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; + if (!start_address) + return(((signed)addr+1)%size); + addr-= start_address; + addr++; + addr%= size; + addr+= start_address; + return(addr); } -/* Set doesn't call callbacks */ - -void -cl_mem::set(t_addr addr, t_mem val) +t_addr +cl_memory::validate_address(t_addr addr) { - 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; + while (addr < start_address) + addr+= size; + if (addr > start_address+size) + { + addr-= start_address; + addr%= size; + addr+= start_address; + } + return(addr); } -/* Set or clear bits, without callbacks */ void -cl_mem::set_bit1(t_addr addr, t_mem bits) +cl_memory::err_inv_addr(t_addr addr) { - if (addr >= size) + if (!uc) return; - bits&= mask; - if (width <= 8) - ((TYPE_UBYTE*)mem)[addr]|= bits; - else if (width <= 16) - ((TYPE_UWORD*)mem)[addr]|= bits; - else - ((TYPE_UDWORD*)mem)[addr]|= bits; + class cl_error *e= new cl_error_mem_invalid_address(this, addr); + uc->error(e); } void -cl_mem::set_bit0(t_addr addr, t_mem bits) +cl_memory::err_non_decoded(t_addr addr) { - if (addr >= size) + if (!uc) return; - bits&= mask; - if (width <= 8) - ((TYPE_UBYTE*)mem)[addr]&= ~bits; - else if (width <= 16) - ((TYPE_UWORD*)mem)[addr]&= ~bits; - else - ((TYPE_UDWORD*)mem)[addr]&= ~bits; + class cl_error *e= new cl_error_mem_non_decoded(this, addr); + uc->error(e); } -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) +cl_memory::dump(t_addr start, t_addr stop, int bpl, class cl_console *con) { int i; + t_addr lva= lowest_valid_address(); + t_addr hva= highest_valid_address(); + if (start < lva) + start= lva; + if (stop > hva) + stop= hva; while ((start <= stop) && - (start < size)) + (start < hva)) { - con->printf(addr_format, start); con->printf(" "); + con->dd_printf(addr_format, start); con->dd_printf(" "); for (i= 0; (i < bpl) && - (start+i < size) && + (start+i < hva) && (start+i <= stop); i++) { - con->printf(data_format, read(start+i)); con->printf(" "); + con->dd_printf(data_format, /*read*/get(start+i)); con->dd_printf(" "); } while (i < bpl) { @@ -344,26 +190,26 @@ cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con) j= width/4 + ((width%4)?1:0) + 1; while (j) { - con->printf(" "); + con->dd_printf(" "); j--; } i++; } for (i= 0; (i < bpl) && - (start+i < size) && + (start+i < hva) && (start+i <= stop); i++) { - long c= get(start+i); - con->printf("%c", isprint(255&c)?(255&c):'.'); + long c= read(start+i); + 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; } @@ -371,13 +217,14 @@ cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con) } t_addr -cl_mem::dump(class cl_console *con) +cl_memory::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) +cl_memory::search_next(bool case_sensitive, + t_mem *array, int len, t_addr *addr) { t_addr a; int i; @@ -422,69 +269,1165 @@ cl_mem::search_next(bool case_sensitive, t_mem *array, int len, t_addr *addr) /* - * Bitmap + * Memory operators */ -cl_bitmap::cl_bitmap(t_addr asize): +cl_memory_operator::cl_memory_operator(class cl_memory_cell *acell, + t_addr addr): cl_base() { - map= (uchar*)malloc(size= asize/(8*SIZEOF_CHAR)); - memset(map, 0, size); + cell= acell; + data= 0; + mask= ~0; + next_operator= 0; + address= addr; } -cl_bitmap::~cl_bitmap(void) +cl_memory_operator::cl_memory_operator(class cl_memory_cell *acell, + t_addr addr, + t_mem *data_place, t_mem the_mask): + cl_base() { - free(map); + cell= acell; + data= data_place; + mask= the_mask; + next_operator= 0; + address= addr; } void -cl_bitmap::set(t_addr pos) +cl_memory_operator::set_data(t_mem *data_place, t_mem the_mask) { - int i; + data= data_place; + mask= the_mask; +} - if ((i= pos/(8*SIZEOF_CHAR)) < size) - map[i]|= (1 << (pos & ((8*SIZEOF_CHAR)-1))); + +t_mem +cl_memory_operator::read(void) +{ + if (next_operator) + return(next_operator->read()); + else + return(*data); } -void -cl_bitmap::clear(t_addr pos) +t_mem +cl_memory_operator::write(t_mem val) { - int i; + if (next_operator) + return(next_operator->write(val)); + else + return(*data= (val & mask)); +} + + +/* 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; +} + + +t_mem +cl_hw_operator::read(void) +{ + t_mem d= 0; + + if (hw) + d= hw->read(cell); + + if (next_operator) + next_operator->read(); - if ((i= pos/(8*SIZEOF_CHAR)) < size) - map[i]&= ~(1 << (pos & ((8*SIZEOF_CHAR)-1))); + return(d); } -bool -cl_bitmap::get(t_addr pos) +t_mem +cl_hw_operator::read(enum hw_cath skip) { - return(map[pos/(8*SIZEOF_CHAR)] & (1 << (pos & ((8*SIZEOF_CHAR)-1)))); + t_mem d= *data; + + if (hw && + hw->cathegory != skip) + d= hw->read(cell); + + if (next_operator) + next_operator->read(); + + return(d); } -bool -cl_bitmap::empty(void) +t_mem +cl_hw_operator::write(t_mem val) { - int i; + if (hw) + hw->write(cell, &val); + if (next_operator) + val= next_operator->write(val); + return(*data= (val & mask)); +} + + +/* 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; +} + +t_mem +cl_write_operator::write(t_mem val) +{ + //printf("write event at 0x%x bp=%p\n",address,bp); + uc->events->add(bp); + if (next_operator) + return(next_operator->write(val)); + else + return(*data= (val & mask)); +} + + +/* 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; +} - for (i= 0; i < size && map[i] == 0; i++) ; - return(i == size); +t_mem +cl_read_operator::read(void) +{ + //printf("read event at 0x%x bp=%p\n",address,bp); + uc->events->add(bp); + if (next_operator) + return(next_operator->read()); + else + return(*data); } + /* - * Special memory for code (ROM) + * Memory cell */ -cl_rom::cl_rom(t_addr asize, int awidth): - cl_mem(MEM_ROM, get_id_string(mem_classes, MEM_ROM), asize, awidth) +cl_memory_cell::cl_memory_cell(void): + cl_base() +{ + data= (t_mem *)malloc(sizeof(t_mem)); + flags= CELL_NON_DECODED; + width= 8; + *data= 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(); + set(0/*rand()*/); + return(0); +} + + +TYPE_UBYTE +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(TYPE_UBYTE 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= (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= (t_mem *)malloc(sizeof(t_mem)); + flags|= CELL_NON_DECODED; + } + else + flags&= ~(CELL_NON_DECODED); +} + + +t_mem +cl_memory_cell::read(void) +{ +#ifdef STATISTIC + nuof_reads++; +#endif + if (operators) + return(operators->read()); + return(*data); +} + +t_mem +cl_memory_cell::read(enum hw_cath skip) +{ +#ifdef STATISTIC + nuof_reads++; +#endif + if (operators) + return(operators->read(skip)); + return(*data); +} + +t_mem +cl_memory_cell::get(void) +{ + return(*data); +} + +t_mem +cl_memory_cell::write(t_mem val) +{ +#ifdef STATISTIC + nuof_writes++; +#endif + if (operators) + return(operators->write(val)); + *data= val & mask; + return(*data); +} + +t_mem +cl_memory_cell::set(t_mem val) +{ + *data= val & mask; + return(*data); +} + + + +t_mem +cl_memory_cell::add(long what) +{ + *data= (*data + what) & mask; + return(*data); +} + +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)|= bits; +} + +void +cl_memory_cell::set_bit0(t_mem bits) +{ + bits&= mask; + (*data)&= ~bits; +} + + +void +cl_memory_cell::append_operator(class cl_memory_operator *op) { - bp_map= new cl_bitmap(asize); - inst_map= new cl_bitmap(asize); + 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); + } } -cl_rom::~cl_rom(void) +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; + } + } +} + + +class cl_memory_cell * +cl_memory_cell::add_hw(class cl_hw *hw, int *ith, t_addr addr) +{ + class cl_hw_operator *o= new cl_hw_operator(this, addr, data, mask, hw); + append_operator(o); + return(this); +} + +/*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); +} + + +/* + * 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(char *id, + t_addr astart, t_addr asize, int awidth): + cl_memory(id, asize, awidth) +{ + start_address= astart; + decoders= new cl_decoder_list(2, 2, DD_FALSE); + cells= (class cl_memory_cell **)malloc(size * sizeof(class cl_memory_cell*)); + int i; + for (i= 0; i < size; i++) + { + cells[i]= new cl_memory_cell(); + cells[i]->init(); + } + dummy= new cl_dummy_cell(); +} + +cl_address_space::~cl_address_space(void) +{ + delete decoders; + int i; + for (i= 0; i < size; i++) + if (cells[i]) + delete cells[i]; + 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(cells[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(cells[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(cells[idx]->get()); +} + +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)); + } + return(cells[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; + } + cells[idx]->set(val); +} + +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(cells[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= cells[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= cells[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(cells[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(cells[addr]->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(cells[addr]->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= cells[addr]; + cell->set_flag(flag, set_to); +} + + +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(DD_FALSE); + class cl_memory_cell *cell= cells[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= cells[idx]; + + cell->un_decode(); +} + +void +cl_address_space::undecode_area(class cl_address_decoder *skip, + t_addr begin, t_addr end,class cl_console *con) +{ +#define D if (con) con->debug + D("Undecoding area 0x%x-0x%x of %s\n", begin, end, get_name()); + int i; + for (i= 0; i < decoders->count; i++) + { + class cl_address_decoder *d= + dynamic_cast(decoders->object_at(i)); + if (!d || + d == skip) + continue; + D(" Checking decoder 0x%x-0x%x -> %s[0x%x]\n", + d->as_begin, d->as_end, d->memchip->get_name(), 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%x-0x%x -> %s[0x%x]\n", + d->as_begin, d->as_end, d->memchip->get_name(), d->chip_begin); + if (nd) + { + decoders->add(nd); + D(" 0x%x-0x%x -> %s[0x%x]\n", + nd->as_begin, nd->as_end, nd->memchip->get_name(), 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%x-0x%x -> %s[0x%x]\n", + d->as_begin, d->as_end, d->memchip->get_name(), d->chip_begin); + } + } + } +#undef D +} + + +class cl_memory_cell * +cl_address_space::register_hw(t_addr addr, class cl_hw *hw, + int *ith, + bool announce) +{ + t_addr idx= addr-start_address; + if (idx >= size || + addr < start_address) + return(0); + class cl_memory_cell *cell= cells[idx]; + cell->add_hw(hw, ith, addr); + //printf("adding hw %s to cell 0x%x(%d) of %s\n", hw->id_string, addr, idx, get_name("as")); + if (announce) + ;//uc->sim->/*app->*/mem_cell_changed(this, addr);//FIXME + return(cell); +} + + +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= cells[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, DD_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= cells[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, DD_FALSE, CELL_FETCH_BRK); + return; + break; + default: + break; + } +} + + +/* + * 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(char *id, int asize, int awidth, int initial): + cl_memory(id, asize, awidth) +{ + array= (t_mem *)malloc(size * sizeof(t_mem)); + init_value= initial; +} + +cl_memory_chip::~cl_memory_chip(void) +{ + if (array) + free(array); +} + +int +cl_memory_chip::init(void) +{ + cl_memory::init(); + int i; + 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_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); +} + + +/* + * 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->is_address_space()) + address_space= (class cl_address_space *)as; + else + address_space= 0; + if (chip->is_chip()) + memchip= (class cl_memory_chip *)chip; + else + memchip= 0; + as_begin= asb; + as_end= ase; + chip_begin= cb; + activated= DD_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 *con) +{ +#define D if (con) con->debug + D("Activation of an address decoder\n"); + if (activated) + { + D("Already activated\n"); + return(DD_FALSE); + } + if (!address_space || + !address_space->is_address_space()) + { + D("No or non address space\n"); + return(DD_FALSE); + } + if (!memchip || + !memchip->is_chip()) + { + D("No or non memory chip\n"); + return(DD_FALSE); + } + if (as_begin > as_end) + { + D("Wrong address area specification\n"); + return(DD_FALSE); + } + if (chip_begin >= memchip->get_size()) + { + D("Wrong chip area specification\n"); + return(DD_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(DD_FALSE); + } + if (as_end-as_begin > memchip->get_size()-chip_begin) + { + D("Specified area is out of chip size\n"); + return(DD_FALSE); + } + + address_space->undecode_area(this, as_begin, as_end, con); + + 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%06x->0x%06x failed\n", asa, ca); + } + } + activated= DD_TRUE; + +#undef D + return(activated); +} + + +bool +cl_address_decoder::fully_covered_by(t_addr begin, t_addr end) +{ + if (begin <= as_begin && + end >= as_end) + return(DD_TRUE); + return(DD_FALSE); +} + +bool +cl_address_decoder::is_in(t_addr begin, t_addr end) +{ + if (begin >= as_begin && + begin <= as_end) + return(DD_TRUE); + if (end >= as_begin && + end <= as_end) + return(DD_TRUE); + return(DD_FALSE); +} + +bool +cl_address_decoder::covers(t_addr begin, t_addr end) +{ + if (begin > as_begin && + end < as_end) + return(DD_TRUE); + return(DD_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(DD_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(DD_TRUE); + return(DD_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(end+1, as_end); + } + if (nd) + nd->init(); + return(nd); +} + + +/* + * 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= DD_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 */ +ERROR_CLASS_DEF_PARENT_ON(err_error, mem, "memory", + error_class_base, ERROR_ON); + +cl_error_mem::cl_error_mem(class cl_memory *amem, t_addr aaddr) +{ + mem= amem; + addr= aaddr; + classification= &error_mem_class; +} + +/* Invalid address in memory access */ +ERROR_CLASS_DEF_PARENT(err_error, + mem_invalid_address, + "invalid_address", + error_mem_class); + +cl_error_mem_invalid_address:: +cl_error_mem_invalid_address(class cl_memory *amem, t_addr aaddr): + cl_error_mem(amem, aaddr) +{ + classification= &error_mem_invalid_address_class; +} + +void +cl_error_mem_invalid_address::print(class cl_commander *c) +{ + FILE *f= c->get_out(); + cmd_fprintf(f, "%s: invalid address ", get_type_name()); + cmd_fprintf(f, mem->addr_format, addr); + cmd_fprintf(f, " in memory %s.\n", mem->get_name()); +} + +/* Non-decoded address space access */ +ERROR_CLASS_DEF_PARENT(err_error, + mem_non_decoded, + "non_decoded", + error_mem_class); + +cl_error_mem_non_decoded:: +cl_error_mem_non_decoded(class cl_memory *amem, t_addr aaddr): + cl_error_mem(amem, aaddr) +{ + classification= &error_mem_non_decoded_class; +} + +void +cl_error_mem_non_decoded::print(class cl_commander *c) { - delete bp_map; - delete inst_map; + FILE *f= c->get_out(); + cmd_fprintf(f, "%s: access of non-decoded address ", get_type_name()); + cmd_fprintf(f, mem->addr_format, addr); + cmd_fprintf(f, " in memory %s.\n", mem->get_name()); }