xref: /netbsd-src/external/gpl3/gdb/dist/sim/rl78/mem.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* mem.c --- memory for RL78 simulator.
2 
3    Copyright (C) 2011-2014 Free Software Foundation, Inc.
4    Contributed by Red Hat, Inc.
5 
6    This file is part of the GNU simulators.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "opcode/rl78.h"
28 #include "mem.h"
29 #include "cpu.h"
30 
31 #define ILLEGAL_OPCODE 0xff
32 
33 int rom_limit = 0x100000;
34 int ram_base = 0xf8000;
35 unsigned char memory[MEM_SIZE];
36 #define MASK 0xfffff
37 
38 unsigned char initted[MEM_SIZE];
39 int skip_init = 0;
40 
41 #define tprintf if (trace) printf
42 
43 void
44 init_mem (void)
45 {
46   memset (memory, ILLEGAL_OPCODE, sizeof (memory));
47   memset (memory + 0xf0000, 0x33, 0x10000);
48 
49   memset (initted, 0, sizeof (initted));
50   memset (initted + 0xffee0, 1, 0x00120);
51   memset (initted + 0xf0000, 1, 0x01000);
52 }
53 
54 void
55 mem_ram_size (int ram_bytes)
56 {
57   ram_base = 0x100000 - ram_bytes;
58 }
59 
60 void
61 mem_rom_size (int rom_bytes)
62 {
63   rom_limit = rom_bytes;
64 }
65 
66 /* ---------------------------------------------------------------------- */
67 /* Note: the RL78 memory map has a few surprises.  For starters, part
68    of the first 64k is mapped to the last 64k, depending on an SFR bit
69    and how much RAM the chip has.  This is simulated here, as are a
70    few peripherals.  */
71 
72 /* This is stdout.  We only care about the data byte, not the upper byte.  */
73 #define SDR00	0xfff10
74 #define SSR00	0xf0100
75 #define TS0	0xf01b2
76 
77 /* RL78/G13 multiply/divide peripheral.  */
78 #define MDUC	0xf00e8
79 #define MDAL	0xffff0
80 #define MDAH	0xffff2
81 #define MDBL	0xffff6
82 #define MDBH	0xffff4
83 #define MDCL	0xf00e0
84 #define MDCH	0xf00e2
85 static long long mduc_clock = 0;
86 static int mda_set = 0;
87 #define MDA_SET  15
88 
89 static int last_addr_was_mirror;
90 
91 static int
92 address_mapping (int address)
93 {
94   address &= MASK;
95   if (address >= 0xf1000 && address < ram_base)
96     {
97       address &= 0xffff;
98       tprintf ("&");
99       if (memory[RL78_SFR_PMC] & 1)
100 	{
101 	  tprintf ("|");
102 	  address |= 0x10000;
103 	}
104       last_addr_was_mirror = 1;
105     }
106   else
107       last_addr_was_mirror = 0;
108 
109   return address;
110 }
111 
112 static void
113 mem_put_byte (int address, unsigned char value)
114 {
115   address = address_mapping (address);
116   memory [address] = value;
117   initted [address] = 1;
118   if (address == SDR00)
119     {
120       putchar (value);
121       fflush (stdout);
122     }
123   if (address == TS0)
124     {
125       if (timer_enabled == 2)
126 	{
127 	  total_clocks = 0;
128 	  pending_clocks = 0;
129 	  memset (counts_per_insn, 0, sizeof (counts_per_insn));
130 	  memory[0xf0180] = 0xff;
131 	  memory[0xf0181] = 0xff;
132 	}
133       if (value & 1)
134 	timer_enabled = 1;
135       else
136 	timer_enabled = 0;
137     }
138   if (address == RL78_SFR_SP && value & 1)
139     {
140       printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc);
141       value &= ~1;
142     }
143   if (address == MDUC)
144     {
145       if ((value & 0x81) == 0x81)
146 	{
147 	  /* division */
148 	  mduc_clock = total_clocks;
149 	}
150     }
151   if ((address & ~3) == MDAL)
152     {
153       mda_set |= (1 << (address & 3));
154       if (mda_set == MDA_SET)
155 	{
156 	  long als, ahs;
157 	  unsigned long alu, ahu;
158 	  long rvs;
159 	  long mdc;
160 	  unsigned long rvu;
161 	  mda_set = 0;
162 	  switch (memory [MDUC] & 0xc8)
163 	    {
164 	    case 0x00:
165 	      alu = mem_get_hi (MDAL);
166 	      ahu = mem_get_hi (MDAH);
167 	      rvu = alu * ahu;
168 	      tprintf  ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu);
169 	      mem_put_si (MDBL, rvu);
170 	      break;
171 	    case 0x08:
172 	      als = sign_ext (mem_get_hi (MDAL), 16);
173 	      ahs = sign_ext (mem_get_hi (MDAH), 16);
174 	      rvs = als * ahs;
175 	      tprintf  ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs);
176 	      mem_put_si (MDBL, rvs);
177 	      break;
178 	    case 0x40:
179 	      alu = mem_get_hi (MDAL);
180 	      ahu = mem_get_hi (MDAH);
181 	      rvu = alu * ahu;
182 	      mem_put_si (MDBL, rvu);
183 	      mdc = mem_get_si (MDCL);
184 	      tprintf  ("MDUC: %lu * %lu + %lu = ", alu, ahu, mdc);
185 	      mdc += (long) rvu;
186 	      tprintf ("%lu\n", mdc);
187 	      mem_put_si (MDCL, mdc);
188 	      break;
189 	    case 0x48:
190 	      als = sign_ext (mem_get_hi (MDAL), 16);
191 	      ahs = sign_ext (mem_get_hi (MDAH), 16);
192 	      rvs = als * ahs;
193 	      mem_put_si (MDBL, rvs);
194 	      mdc = mem_get_si (MDCL);
195 	      tprintf  ("MDUC: %ld * %ld + %ld = ", als, ahs, mdc);
196 	      tprintf ("%ld\n", mdc);
197 	      mdc += rvs;
198 	      mem_put_si (MDCL, mdc);
199 	      break;
200 	    }
201 	}
202     }
203 }
204 
205 extern long long total_clocks;
206 
207 static unsigned char
208 mem_get_byte (int address)
209 {
210   address = address_mapping (address);
211   switch (address)
212     {
213     case SSR00:
214     case SSR00 + 1:
215       return 0x00;
216     case 0xf00f0:
217       return 0;
218     case 0xf0180:
219     case 0xf0181:
220       return memory[address];
221 
222     case MDUC:
223       {
224 	unsigned char mduc = memory [MDUC];
225 	if ((mduc & 0x81) == 0x81
226 	    && total_clocks > mduc_clock + 16)
227 	  {
228 	    unsigned long a, b, q, r;
229 	    memory [MDUC] &= 0xfe;
230 	    a = mem_get_si (MDAL);
231 	    b = mem_get_si (MDAL);
232 	    if (b == 0)
233 	      {
234 		q = ~0;
235 		r = ~0;
236 	      }
237 	    else
238 	      {
239 		q = a / b;
240 		r = a % b;
241 	      }
242 	    tprintf  ("MDUC: %lu / %lu = q %lu, r %lu\n", a, b, q, r);
243 	    mem_put_si (MDAL, q);
244 	    mem_put_si (MDCL, r);
245 	  }
246 	return memory[address];
247       }
248     case MDCL:
249     case MDCL + 1:
250     case MDCH:
251     case MDCH + 1:
252       return memory[address];
253     }
254   if (address < 0xf1000 && address >= 0xf0000)
255     {
256 #if 1
257       /* Note: comment out this return to trap the invalid access
258 	 instead of returning an "undefined" value.  */
259       return 0x11;
260 #else
261       fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc);
262       exit (1);
263 #endif
264     }
265 #if 0
266   /* Uncomment this block if you want to trap on reads from unwritten memory.  */
267   if (!skip_init && !initted [address])
268     {
269       static int uninit_count = 0;
270       fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc);
271       uninit_count ++;
272       if (uninit_count > 5)
273 	exit (1);
274     }
275 #endif
276   return memory [address];
277 }
278 
279 extern jmp_buf decode_jmp_buf;
280 #define DO_RETURN(x) longjmp (decode_jmp_buf, x)
281 
282 #define CHECK_ALIGNMENT(a,v,m) \
283   if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \
284     DO_RETURN (RL78_MAKE_HIT_BREAK ()); }
285 
286 /* ---------------------------------------------------------------------- */
287 #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00))
288 
289 void
290 mem_put_qi (int address, unsigned char value)
291 {
292   if (!SPECIAL_ADDR (address))
293     tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value);
294   mem_put_byte (address, value);
295 }
296 
297 void
298 mem_put_hi (int address, unsigned short value)
299 {
300   if (!SPECIAL_ADDR (address))
301     tprintf ("\033[34m([%05X]<-%04X)\033[0m", address, value);
302   CHECK_ALIGNMENT (address, value, 1);
303   if (address > 0xffff8 && address != RL78_SFR_SP)
304     {
305       tprintf ("Word access to 0x%05x!!\n", address);
306       DO_RETURN (RL78_MAKE_HIT_BREAK ());
307     }
308   mem_put_byte (address, value);
309   mem_put_byte (address + 1, value >> 8);
310 }
311 
312 void
313 mem_put_psi (int address, unsigned long value)
314 {
315   tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address, value);
316   mem_put_byte (address, value);
317   mem_put_byte (address + 1, value >> 8);
318   mem_put_byte (address + 2, value >> 16);
319 }
320 
321 void
322 mem_put_si (int address, unsigned long value)
323 {
324   tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address, value);
325   CHECK_ALIGNMENT (address, value, 3);
326   mem_put_byte (address, value);
327   mem_put_byte (address + 1, value >> 8);
328   mem_put_byte (address + 2, value >> 16);
329   mem_put_byte (address + 3, value >> 24);
330 }
331 
332 void
333 mem_put_blk (int address, const void *bufptr, int nbytes)
334 {
335   const unsigned char *bp = (unsigned char *)bufptr;
336   while (nbytes --)
337     mem_put_byte (address ++, *bp ++);
338 }
339 
340 unsigned char
341 mem_get_pc (int address)
342 {
343   /* Catch obvious problems.  */
344   if (address >= rom_limit && address < 0xf0000)
345     return 0xff;
346   /* This does NOT go through the flash mirror area; you cannot
347      execute out of the mirror.  */
348   return memory [address & MASK];
349 }
350 
351 unsigned char
352 mem_get_qi (int address)
353 {
354   int v;
355   v = mem_get_byte (address);
356   if (!SPECIAL_ADDR (address))
357     tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
358   if (last_addr_was_mirror)
359     {
360       pending_clocks += 3;
361       tprintf ("ROM read\n");
362     }
363   return v;
364 }
365 
366 unsigned short
367 mem_get_hi (int address)
368 {
369   int v;
370   v = mem_get_byte (address)
371     | mem_get_byte (address + 1) * 256;
372   CHECK_ALIGNMENT (address, v, 1);
373   if (!SPECIAL_ADDR (address))
374     tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
375   if (last_addr_was_mirror)
376     {
377       pending_clocks += 3;
378       tprintf ("ROM read\n");
379     }
380   return v;
381 }
382 
383 unsigned long
384 mem_get_psi (int address)
385 {
386   int v;
387   v = mem_get_byte (address)
388     | mem_get_byte (address + 1) * 256
389     | mem_get_byte (address + 2) * 65536;
390   tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
391   return v;
392 }
393 
394 unsigned long
395 mem_get_si (int address)
396 {
397   int v;
398   v = mem_get_byte (address)
399     | mem_get_byte (address + 1) * 256
400     | mem_get_byte (address + 2) * 65536
401     | mem_get_byte (address + 2) * 16777216;
402   CHECK_ALIGNMENT (address, v, 3);
403   tprintf ("(\033[35m[%05X]->%04X)\033[0m", address, v);
404   return v;
405 }
406 
407 void
408 mem_get_blk (int address, void *bufptr, int nbytes)
409 {
410   unsigned char *bp = (unsigned char *)bufptr;
411   while (nbytes --)
412     *bp ++ = mem_get_byte (address ++);
413 }
414 
415 int
416 sign_ext (int v, int bits)
417 {
418   if (bits < 8 * sizeof (int))
419     {
420       v &= (1 << bits) - 1;
421       if (v & (1 << (bits - 1)))
422 	v -= (1 << bits);
423     }
424   return v;
425 }
426