Version 0.3.0
[fw/sdcc] / sim / ucsim / sim.src / mem.cc
1 /*
2  * Simulator of microcontrollers (mem.cc)
3  *
4  * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.
5  * 
6  * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
7  *
8  */
9
10 /* This file is part of microcontroller simulator: ucsim.
11
12 UCSIM is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 UCSIM is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with UCSIM; see the file COPYING.  If not, write to the Free
24 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 02111-1307, USA. */
26 /*@1@*/
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include "i_string.h"
32
33 // prj
34 #include "utils.h"
35 #include "globals.h"
36
37 // cmd
38 #include "newcmdcl.h"
39
40 // local
41 #include "memcl.h"
42 #include "hwcl.h"
43
44
45 /*
46  * Memory location handled specially by a hw element
47  */
48
49 cl_memloc::cl_memloc(t_addr addr):
50   cl_base()
51 {
52   address= addr;
53   hws= new cl_list(2, 2);
54   hws->init();
55 }
56
57 cl_memloc::~cl_memloc(void)
58 {
59   hws->disconn_all();
60   delete hws;
61 }
62
63 ulong
64 cl_memloc::read(class cl_mem *mem)
65 {
66   uchar ret= 0;
67   class cl_hw *hw;
68
69   if (!hws ||
70       hws->count == 0)
71     return(ret);
72   if ((hw= (class cl_hw *)(hws->at(0))))
73     ret= hw->read(mem, address);
74   return(ret);
75 }
76
77 void
78 cl_memloc::write(class cl_mem *mem, t_addr addr, t_mem *val)
79 {
80   class cl_hw *hw;
81   int i;
82
83   if (!hws)
84     return;
85   for (i= 0; i < hws->count; i++)
86     {
87       hw= (class cl_hw *)hws->at(0);
88       hw->write(mem, addr, val);
89     }
90 }
91
92
93 /* Sorted collection of memory locations */
94
95 cl_memloc_coll::cl_memloc_coll(void):
96   cl_sorted_list(2, 2)
97 {
98   Duplicates= DD_FALSE;
99 }
100
101 void *
102 cl_memloc_coll::key_of(void *item)
103 {
104   return(&(((class cl_memloc *)item)->address));
105 }
106
107 int
108 cl_memloc_coll::compare(void *key1, void *key2)
109 {
110   if (*(long*)key1 > *(long*)key2)
111     return(1);
112   else
113     if (*(long*)key1 < *(long*)key2)
114       return(-1);
115     else
116       return(0);
117 }
118
119 class cl_memloc *
120 cl_memloc_coll::get_loc(t_addr address)
121 {
122   t_index i;
123
124   if (search(&address, i))
125     return((class cl_memloc*)(at(i)));
126   return(0);
127 }
128
129
130 /*
131  */
132
133 cl_cell::cl_cell(void):
134   cl_base()
135 {
136   data= 0;
137 }
138
139 cl_cell::cl_cell(t_mem idata):
140   cl_base()
141 {
142   data= idata;
143 }
144
145 /*
146  * Memory
147  ******************************************************************************
148  */
149
150 cl_mem::cl_mem(enum mem_class atype, char *aclass_name,
151                t_addr asize, int awidth):
152   cl_guiobj()
153 {
154   int i;
155
156   type= atype;
157   class_name= aclass_name;
158   width= awidth;
159   size= asize;
160   mem= 0;
161   for (i= width, mask= 0; i; i--)
162     mask= (mask<<1) | 1;
163   if (width <= 8)
164     mem= (TYPE_UBYTE *)malloc(size);
165   else if (width <= 16)
166     mem= (TYPE_UWORD *)malloc(size*sizeof(TYPE_WORD));
167   else
168     mem= (TYPE_UDWORD *)malloc(size*sizeof(TYPE_DWORD));
169   read_locs= new cl_memloc_coll();
170   write_locs= new cl_memloc_coll();
171   dump_finished= 0;
172   addr_format= (char *)malloc(10);
173   sprintf(addr_format, "0x%%0%dx",
174           size-1<=0xf?1:
175           (size-1<=0xff?2:
176            (size-1<=0xfff?3:
177             (size-1<=0xffff?4:
178              (size-1<=0xfffff?5:
179               (size-1<=0xffffff?6:12))))));
180   data_format= (char *)malloc(10);
181   sprintf(data_format, "%%0%dx", width/4+((width%4)?1:0));
182 }
183
184 cl_mem::~cl_mem(void)
185 {
186   if (mem)
187     free(mem);
188   if (addr_format)
189     free(addr_format);
190   if (data_format)
191     free(data_format);
192   delete read_locs;
193   delete write_locs;
194 }
195
196 int
197 cl_mem::init(void)
198 {
199   t_addr i;
200
201   for (i= 0; i < size; i++)
202     set(i, (type==MEM_ROM)?(-1):0);
203   return(0);
204 }
205
206 char *
207 cl_mem::id_string(void)
208 {
209   char *s= get_id_string(mem_ids, type);
210
211   return(s?s:(char*)"NONE");
212 }
213
214 t_mem
215 cl_mem::read(t_addr addr)
216 {
217   class cl_memloc *loc;
218
219   if (addr >= size)
220     {
221       //FIXME
222       fprintf(stderr, "Address 0x%06lx is over 0x%06lx\n", addr, size);
223       return(0);
224     }
225   if ((loc= read_locs->get_loc(addr)))
226     return(loc->read(this));
227   if (width <= 8)
228     return((((TYPE_UBYTE*)mem)[addr])&mask);
229   else if (width <= 16)
230     return((((TYPE_UWORD*)mem)[addr])&mask);
231   else
232     return((((TYPE_UDWORD*)mem)[addr])&mask);
233 }
234
235 t_mem
236 cl_mem::get(t_addr addr)
237 {
238   if (addr >= size)
239     return(0);
240   if (width <= 8)
241     return((((TYPE_UBYTE*)mem)[addr])&mask);
242   else if (width <= 16)
243     return((((TYPE_UWORD*)mem)[addr])&mask);
244   else
245     return((((TYPE_UDWORD*)mem)[addr])&mask);
246 }
247
248
249 /*
250  * Modify memory location
251  */
252
253 /* Write calls callbacks of HW elements */
254
255 void
256 cl_mem::write(t_addr addr, t_mem *val)
257 {
258   class cl_memloc *loc;
259
260   if (addr >= size)
261     return;
262   if ((loc= write_locs->get_loc(addr)))
263     loc->write(this, addr, val);
264   if (width <= 8)
265     ((TYPE_UBYTE*)mem)[addr]= (*val)&mask;
266   else if (width <= 16)
267     ((TYPE_UWORD*)mem)[addr]= (*val)&mask;
268   else
269     ((TYPE_UDWORD*)mem)[addr]= (*val)&mask;
270 }
271
272 /* Set doesn't call callbacks */
273
274 void
275 cl_mem::set(t_addr addr, t_mem val)
276 {
277   if (addr >= size)
278     return;
279   if (width <= 8)
280     ((TYPE_UBYTE*)mem)[addr]= val&mask;
281   else if (width <= 16)
282     ((TYPE_UWORD*)mem)[addr]= val&mask;
283   else
284     ((TYPE_UDWORD*)mem)[addr]= val&mask;
285 }
286
287 /* Set or clear bits, without callbacks */
288
289 void
290 cl_mem::set_bit1(t_addr addr, t_mem bits)
291 {
292   if (addr >= size)
293     return;
294   bits&= mask;
295   if (width <= 8)
296     ((TYPE_UBYTE*)mem)[addr]|= bits;
297   else if (width <= 16)
298     ((TYPE_UWORD*)mem)[addr]|= bits;
299   else
300     ((TYPE_UDWORD*)mem)[addr]|= bits;
301 }
302
303 void
304 cl_mem::set_bit0(t_addr addr, t_mem bits)
305 {
306   if (addr >= size)
307     return;
308   bits&= mask;
309   if (width <= 8)
310     ((TYPE_UBYTE*)mem)[addr]&= ~bits;
311   else if (width <= 16)
312     ((TYPE_UWORD*)mem)[addr]&= ~bits;
313   else
314     ((TYPE_UDWORD*)mem)[addr]&= ~bits;
315 }
316
317 t_mem
318 cl_mem::add(t_addr addr, long what)
319 {
320   if (addr >= size)
321     return(0);
322   if (width <= 8)
323     {
324       ((TYPE_UBYTE*)mem)[addr]= ((TYPE_UBYTE*)mem)[addr] + what;
325       return(((TYPE_UBYTE*)mem)[addr]);
326     }
327   else if (width <= 16)
328     {
329       ((TYPE_UWORD*)mem)[addr]= ((TYPE_UWORD*)mem)[addr] + what;
330       return(((TYPE_UWORD*)mem)[addr]);
331     }
332   else
333     {
334       ((TYPE_UDWORD*)mem)[addr]= ((TYPE_UDWORD*)mem)[addr] + what;
335       return(((TYPE_UDWORD*)mem)[addr]);
336     }
337 }
338
339 t_addr
340 cl_mem::dump(t_addr start, t_addr stop, int bpl, class cl_console *con)
341 {
342   int i;
343
344   while ((start <= stop) &&
345          (start < size))
346     {
347       con->printf(addr_format, start); con->printf(" ");
348       for (i= 0;
349            (i < bpl) &&
350              (start+i < size) &&
351              (start+i <= stop);
352            i++)
353         {
354           con->printf(data_format, read(start+i)); con->printf(" ");
355         }
356       while (i < bpl)
357         {
358           int j;
359           j= width/4 + ((width%4)?1:0) + 1;
360           while (j)
361             {
362               con->printf(" ");
363               j--;
364             }
365           i++;
366         }
367       for (i= 0; (i < bpl) &&
368              (start+i < size) &&
369              (start+i <= stop);
370            i++)
371         {
372           long c= get(start+i);
373           con->printf("%c", isprint(255&c)?(255&c):'.');
374           if (width > 8)
375             con->printf("%c", isprint(255&(c>>8))?(255&(c>>8)):'.');
376           if (width > 16)
377             con->printf("%c", isprint(255&(c>>16))?(255&(c>>16)):'.');
378           if (width > 24)
379             con->printf("%c", isprint(255&(c>>24))?(255&(c>>24)):'.');
380         }
381       con->printf("\n");
382       dump_finished= start+i;
383       start+= bpl;
384     }
385   return(dump_finished);
386 }
387
388 t_addr
389 cl_mem::dump(class cl_console *con)
390 {
391   return(dump(dump_finished, dump_finished+10*8-1, 8, con));
392 }
393
394 bool
395 cl_mem::search_next(bool case_sensitive, t_mem *array, int len, t_addr *addr)
396 {
397   t_addr a;
398   int i;
399   bool found;
400
401   if (addr == NULL)
402     a= 0;
403   else
404     a= *addr;
405   
406   if (a+len > size)
407     return(DD_FALSE);
408
409   found= DD_FALSE;
410   while (!found &&
411          a+len <= size)
412     {
413       bool match= DD_TRUE;
414       for (i= 0; i < len && match; i++)
415         {
416           t_mem d1, d2;
417           d1= get(a+i);
418           d2= array[i];
419           if (!case_sensitive)
420             {
421               if (/*d1 < 128*/isalpha(d1))
422                 d1= toupper(d1);
423               if (/*d2 < 128*/isalpha(d2))
424                 d2= toupper(d2);
425             }
426           match= d1 == d2;
427         }
428       found= match;
429       if (!found)
430         a++;
431     }
432
433   if (addr)
434     *addr= a;
435   return(found);
436 }
437
438
439 /*
440  * Bitmap
441  */
442
443 cl_bitmap::cl_bitmap(t_addr asize):
444   cl_base()
445 {
446   map= (uchar*)malloc(size= asize/(8*SIZEOF_CHAR));
447   memset(map, 0, size);
448 }
449
450 cl_bitmap::~cl_bitmap(void)
451 {
452   free(map);
453 }
454
455 void
456 cl_bitmap::set(t_addr pos)
457 {
458   int i;
459
460   if ((i= pos/(8*SIZEOF_CHAR)) < size)
461     map[i]|= (1 << (pos & ((8*SIZEOF_CHAR)-1)));
462 }
463
464 void
465 cl_bitmap::clear(t_addr pos)
466 {
467   int i;
468
469   if ((i= pos/(8*SIZEOF_CHAR)) < size)
470     map[i]&= ~(1 << (pos & ((8*SIZEOF_CHAR)-1)));
471 }
472
473 bool
474 cl_bitmap::get(t_addr pos)
475 {
476   return(map[pos/(8*SIZEOF_CHAR)] & (1 << (pos & ((8*SIZEOF_CHAR)-1))));
477 }
478
479 bool
480 cl_bitmap::empty(void)
481 {
482   int i;
483
484   for (i= 0; i < size && map[i] == 0; i++) ;
485   return(i == size);
486 }
487
488 /*
489  * Special memory for code (ROM)
490  */
491
492 cl_rom::cl_rom(t_addr asize, int awidth):
493   cl_mem(MEM_ROM, get_id_string(mem_classes, MEM_ROM), asize, awidth)
494 {
495   bp_map= new cl_bitmap(asize);
496   inst_map= new cl_bitmap(asize);
497 }
498
499 cl_rom::~cl_rom(void)
500 {
501   delete bp_map;
502   delete inst_map;
503 }
504
505
506 /* End of mem.cc */