gbdk/sdcc/sim/ucsim/sim.src/mem.cc
2015-01-10 16:25:09 +01:00

644 lines
11 KiB
C++

/*
* 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 "i_string.h"
// prj
#include "utils.h"
#include "globals.h"
// cmd
#include "newcmdcl.h"
// local
#include "memcl.h"
#include "hwcl.h"
/*
* Memory location handled specially by a hw element
*/
cl_memloc::cl_memloc(t_addr addr):
cl_base()
{
address= addr;
hws= new cl_list(2, 2);
hws->init();
}
cl_memloc::~cl_memloc(void)
{
hws->disconn_all();
delete hws;
}
ulong
cl_memloc::read(class cl_mem *mem)
{
uchar ret= 0;
class cl_hw *hw;
if (!hws ||
hws->count == 0)
return(ret);
if ((hw= (class cl_hw *)(hws->at(0))))
ret= hw->read(mem, address);
return(ret);
}
void
cl_memloc::write(class cl_mem *mem, t_addr addr, t_mem *val)
{
class cl_hw *hw;
int i;
if (!hws)
return;
for (i= 0; i < hws->count; i++)
{
hw= (class cl_hw *)hws->at(0);
hw->write(mem, addr, val);
}
}
/* Sorted collection of memory locations */
cl_memloc_coll::cl_memloc_coll(void):
cl_sorted_list(2, 2)
{
Duplicates= DD_FALSE;
}
void *
cl_memloc_coll::key_of(void *item)
{
return(&(((class cl_memloc *)item)->address));
}
int
cl_memloc_coll::compare(void *key1, void *key2)
{
if (*(long*)key1 > *(long*)key2)
return(1);
else
if (*(long*)key1 < *(long*)key2)
return(-1);
else
return(0);
}
class cl_memloc *
cl_memloc_coll::get_loc(t_addr address)
{
t_index i;
if (search(&address, i))
return((class cl_memloc*)(at(i)));
return(0);
}
/*
*/
cl_cell::cl_cell(int awidth):
cl_base()
{
data= 0;
mask= 1;
for (; awidth; awidth--)
{
mask<<= 1;
mask|= 1;
}
}
/*t_mem
cl_cell::read(void)
{
return(data);
}*/
/*t_mem
cl_cell::get(void)
{
return(data);
}*/
/*void
cl_cell::write(t_mem *val)
{
data= *val= (*val & mask);
}*/
/*void
cl_cell::set(t_mem val)
{
data= val & mask;
}*/
cl_registered_cell::cl_registered_cell(int awidth):
cl_cell(awidth)
{
hws= new cl_list(1, 1);
hardwares= 0;
nuof_hws= 0;
}
cl_registered_cell::~cl_registered_cell(void)
{
hws->disconn_all();
delete hws;
}
t_mem
cl_registered_cell::read(void)
{
int i;
/*if (hws->count)
for (i= 0; i < hws->count; i++)
{
class cl_hw *hw= (class cl_hw *)(hws->at(i));
;
}*/
if (nuof_hws)
for (i= 0; i < nuof_hws; i++)
{
//hardwares[i];
;
}
return(data);
}
void
cl_registered_cell::write(t_mem *val)
{
int i;
/*if (hws->count)
for (i= 0; i < hws->count; i++)
{
class cl_hw *hw= (class cl_hw *)(hws->at(i));
;
}*/
if (nuof_hws)
for (i= 0; i < nuof_hws; i++)
{
//hardwares[i];
;
}
data= *val= (*val & mask);
}
/*
*/
cl_m::cl_m(t_addr asize, int awidth):
cl_mem(MEM_SFR, "sfr", 0, awidth)
{
t_addr a;
size= asize;
width= awidth;
array= (class cl_cell **)malloc(size * sizeof(class cl_cell *));
for (a= 0; a < size; a++)
array[a]= new cl_registered_cell(width);
}
cl_m::~cl_m(void)
{
t_addr a;
for (a= 0; a < size; a++)
delete array[a];
free(array);
}
t_mem
cl_m::read(t_addr addr)
{
if (addr >= size)
return(0);
return(array[addr]->read());
}
t_mem
cl_m::get(t_addr addr)
{
if (addr >= size)
return(0);
return(array[addr]->get());
}
void
cl_m::write(t_addr addr, t_mem *val)
{
if (addr >= size)
return;
array[addr]->write(val);
}
void
cl_m::set(t_addr addr, t_mem val)
{
if (addr >= size)
return;
array[addr]->set(val);
}
/*
* Memory
******************************************************************************
*/
cl_mem::cl_mem(enum mem_class atype, char *aclass_name,
t_addr asize, int awidth):
cl_guiobj()
{
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:
(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));
}
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);
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)
{
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);
}
t_mem
cl_mem::get(t_addr addr)
{
if (addr >= size)
return(0);
if (width <= 8)
return((((TYPE_UBYTE*)mem)[addr])&mask);
else if (width <= 16)
return((((TYPE_UWORD*)mem)[addr])&mask);
else
return((((TYPE_UDWORD*)mem)[addr])&mask);
}
/*
* Modify memory location
*/
/* Write calls callbacks of HW elements */
void
cl_mem::write(t_addr addr, t_mem *val)
{
class cl_memloc *loc;
if (addr >= size)
return;
if ((loc= write_locs->get_loc(addr)))
loc->write(this, addr, val);
if (width <= 8)
((TYPE_UBYTE*)mem)[addr]= (*val)&mask;
else if (width <= 16)
((TYPE_UWORD*)mem)[addr]= (*val)&mask;
else
((TYPE_UDWORD*)mem)[addr]= (*val)&mask;
}
/* Set doesn't call callbacks */
void
cl_mem::set(t_addr addr, t_mem val)
{
if (addr >= size)
return;
if (width <= 8)
((TYPE_UBYTE*)mem)[addr]= val&mask;
else if (width <= 16)
((TYPE_UWORD*)mem)[addr]= val&mask;
else
((TYPE_UDWORD*)mem)[addr]= val&mask;
}
/* Set or clear bits, without callbacks */
void
cl_mem::set_bit1(t_addr addr, t_mem bits)
{
if (addr >= size)
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;
}
void
cl_mem::set_bit0(t_addr addr, t_mem bits)
{
if (addr >= size)
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;
}
t_mem
cl_mem::add(t_addr addr, long what)
{
if (addr >= size)
return(0);
if (width <= 8)
{
((TYPE_UBYTE*)mem)[addr]= ((TYPE_UBYTE*)mem)[addr] + what;
return(((TYPE_UBYTE*)mem)[addr]);
}
else if (width <= 16)
{
((TYPE_UWORD*)mem)[addr]= ((TYPE_UWORD*)mem)[addr] + what;
return(((TYPE_UWORD*)mem)[addr]);
}
else
{
((TYPE_UDWORD*)mem)[addr]= ((TYPE_UDWORD*)mem)[addr] + what;
return(((TYPE_UDWORD*)mem)[addr]);
}
}
t_addr
cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con)
{
int i;
while ((start <= stop) &&
(start < size))
{
con->printf(addr_format, start); con->printf(" ");
for (i= 0;
(i < bpl) &&
(start+i < size) &&
(start+i <= stop);
i++)
{
con->printf(data_format, read(start+i)); con->printf(" ");
}
while (i < bpl)
{
int j;
j= width/4 + ((width%4)?1:0) + 1;
while (j)
{
con->printf(" ");
j--;
}
i++;
}
for (i= 0; (i < bpl) &&
(start+i < size) &&
(start+i <= stop);
i++)
{
long c= get(start+i);
con->printf("%c", isprint(255&c)?(255&c):'.');
if (width > 8)
con->printf("%c", isprint(255&(c>>8))?(255&(c>>8)):'.');
if (width > 16)
con->printf("%c", isprint(255&(c>>16))?(255&(c>>16)):'.');
if (width > 24)
con->printf("%c", isprint(255&(c>>24))?(255&(c>>24)):'.');
}
con->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);
}
/*
* Bitmap
*/
cl_bitmap::cl_bitmap(t_addr asize):
cl_base()
{
map= (uchar*)malloc(size= asize/(8*SIZEOF_CHAR));
memset(map, 0, size);
}
cl_bitmap::~cl_bitmap(void)
{
free(map);
}
void
cl_bitmap::set(t_addr pos)
{
int i;
if ((i= pos/(8*SIZEOF_CHAR)) < size)
map[i]|= (1 << (pos & ((8*SIZEOF_CHAR)-1)));
}
void
cl_bitmap::clear(t_addr pos)
{
int i;
if ((i= pos/(8*SIZEOF_CHAR)) < size)
map[i]&= ~(1 << (pos & ((8*SIZEOF_CHAR)-1)));
}
bool
cl_bitmap::get(t_addr pos)
{
return(map[pos/(8*SIZEOF_CHAR)] & (1 << (pos & ((8*SIZEOF_CHAR)-1))));
}
bool
cl_bitmap::empty(void)
{
int i;
for (i= 0; i < size && map[i] == 0; i++) ;
return(i == size);
}
/*
* Special memory for code (ROM)
*/
cl_rom::cl_rom(t_addr asize, int awidth):
cl_mem(MEM_ROM, get_id_string(mem_classes, MEM_ROM), asize, awidth)
{
bp_map= new cl_bitmap(asize);
inst_map= new cl_bitmap(asize);
}
cl_rom::~cl_rom(void)
{
delete bp_map;
delete inst_map;
}
/* End of mem.cc */