xref: /netbsd-src/external/gpl3/gdb/dist/sim/rl78/mem.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* mem.c --- memory for RL78 simulator.
2 
3    Copyright (C) 2011-2017 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 int mirror_rom_base = 0x01000;
67 int mirror_ram_base = 0xf1000;
68 int mirror_length = 0x7000;
69 
70 void
71 mem_set_mirror (int rom_base, int ram_base, int length)
72 {
73   mirror_rom_base = rom_base;
74   mirror_ram_base = ram_base;
75   mirror_length = length;
76 }
77 
78 /* ---------------------------------------------------------------------- */
79 /* Note: the RL78 memory map has a few surprises.  For starters, part
80    of the first 64k is mapped to the last 64k, depending on an SFR bit
81    and how much RAM the chip has.  This is simulated here, as are a
82    few peripherals.  */
83 
84 /* This is stdout.  We only care about the data byte, not the upper byte.  */
85 #define SDR00	0xfff10
86 #define SSR00	0xf0100
87 #define TS0	0xf01b2
88 
89 /* RL78/G13 multiply/divide peripheral.  */
90 #define MDUC	0xf00e8
91 #define MDAL	0xffff0
92 #define MDAH	0xffff2
93 #define MDBL	0xffff6
94 #define MDBH	0xffff4
95 #define MDCL	0xf00e0
96 #define MDCH	0xf00e2
97 static long long mduc_clock = 0;
98 static int mda_set = 0;
99 #define MDA_SET  15
100 
101 static int last_addr_was_mirror;
102 
103 static int
104 address_mapping (int address)
105 {
106   address &= MASK;
107   if (address >= mirror_ram_base && address < mirror_ram_base + mirror_length)
108     {
109       address = address - mirror_ram_base + mirror_rom_base;
110       if (memory[RL78_SFR_PMC] & 1)
111 	{
112 	  address |= 0x10000;
113 	}
114       last_addr_was_mirror = 1;
115     }
116   else
117       last_addr_was_mirror = 0;
118 
119   return address;
120 }
121 
122 static void
123 mem_put_byte (int address, unsigned char value)
124 {
125   address = address_mapping (address);
126   memory [address] = value;
127   initted [address] = 1;
128   if (address == SDR00)
129     {
130       putchar (value);
131       fflush (stdout);
132     }
133   if (address == TS0)
134     {
135       if (timer_enabled == 2)
136 	{
137 	  total_clocks = 0;
138 	  pending_clocks = 0;
139 	  memset (counts_per_insn, 0, sizeof (counts_per_insn));
140 	  memory[0xf0180] = 0xff;
141 	  memory[0xf0181] = 0xff;
142 	}
143       if (value & 1)
144 	timer_enabled = 1;
145       else
146 	timer_enabled = 0;
147     }
148   if (address == RL78_SFR_SP && value & 1)
149     {
150       printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc);
151       value &= ~1;
152     }
153 
154   if (! g13_multiply)
155     return;
156 
157   if (address == MDUC)
158     {
159       if ((value & 0x81) == 0x81)
160 	{
161 	  /* division */
162 	  mduc_clock = total_clocks;
163 	}
164     }
165   if ((address & ~3) == MDAL)
166     {
167       mda_set |= (1 << (address & 3));
168       if (mda_set == MDA_SET)
169 	{
170 	  long als, ahs;
171 	  unsigned long alu, ahu;
172 	  long rvs;
173 	  long mdc;
174 	  unsigned long rvu;
175 	  mda_set = 0;
176 	  switch (memory [MDUC] & 0xc8)
177 	    {
178 	    case 0x00:
179 	      alu = mem_get_hi (MDAL);
180 	      ahu = mem_get_hi (MDAH);
181 	      rvu = alu * ahu;
182 	      tprintf  ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu);
183 	      mem_put_hi (MDBL, rvu & 0xffff);
184 	      mem_put_hi (MDBH, rvu >> 16);
185 	      break;
186 	    case 0x08:
187 	      als = sign_ext (mem_get_hi (MDAL), 16);
188 	      ahs = sign_ext (mem_get_hi (MDAH), 16);
189 	      rvs = als * ahs;
190 	      tprintf  ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs);
191 	      mem_put_hi (MDBL, rvs & 0xffff);
192 	      mem_put_hi (MDBH, rvs >> 16);
193 	      break;
194 	    case 0x40:
195 	      alu = mem_get_hi (MDAL);
196 	      ahu = mem_get_hi (MDAH);
197 	      rvu = alu * ahu;
198 	      mem_put_hi (MDBL, rvu & 0xffff);
199 	      mem_put_hi (MDBH, rvu >> 16);
200 	      mdc = mem_get_si (MDCL);
201 	      tprintf  ("MDUC: %lu * %lu + %lu = ", alu, ahu, mdc);
202 	      mdc += (long) rvu;
203 	      tprintf ("%lu\n", mdc);
204 	      mem_put_si (MDCL, mdc);
205 	      break;
206 	    case 0x48:
207 	      als = sign_ext (mem_get_hi (MDAL), 16);
208 	      ahs = sign_ext (mem_get_hi (MDAH), 16);
209 	      rvs = als * ahs;
210 	      mem_put_hi (MDBL, rvs & 0xffff);
211 	      mem_put_hi (MDBH, rvs >> 16);
212 	      mdc = mem_get_si (MDCL);
213 	      tprintf  ("MDUC: %ld * %ld + %ld = ", als, ahs, mdc);
214 	      tprintf ("%ld\n", mdc);
215 	      mdc += rvs;
216 	      mem_put_si (MDCL, mdc);
217 	      break;
218 	    }
219 	}
220     }
221 }
222 
223 extern long long total_clocks;
224 
225 static unsigned char
226 mem_get_byte (int address)
227 {
228   address = address_mapping (address);
229   switch (address)
230     {
231     case SSR00:
232     case SSR00 + 1:
233       return 0x00;
234     case 0xf00f0:
235       return 0;
236     case 0xf0180:
237     case 0xf0181:
238       return memory[address];
239 
240     case MDUC:
241       {
242 	unsigned char mduc = memory [MDUC];
243 	if ((mduc & 0x81) == 0x81
244 	    && total_clocks > mduc_clock + 16)
245 	  {
246 	    unsigned long a, b, q, r;
247 	    memory [MDUC] &= 0xfe;
248 	    a = mem_get_si (MDAL);
249 	    b = mem_get_hi (MDBL) | (mem_get_hi (MDBH) << 16);
250 	    if (b == 0)
251 	      {
252 		q = ~0;
253 		r = ~0;
254 	      }
255 	    else
256 	      {
257 		q = a / b;
258 		r = a % b;
259 	      }
260 	    tprintf  ("MDUC: %lu / %lu = q %lu, r %lu\n", a, b, q, r);
261 	    mem_put_si (MDAL, q);
262 	    mem_put_si (MDCL, r);
263 	  }
264 	return memory[address];
265       }
266     case MDCL:
267     case MDCL + 1:
268     case MDCH:
269     case MDCH + 1:
270       return memory[address];
271     }
272   if (address < 0xf1000 && address >= 0xf0000)
273     {
274 #if 1
275       /* Note: comment out this return to trap the invalid access
276 	 instead of returning an "undefined" value.  */
277       return 0x11;
278 #else
279       fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc);
280       exit (1);
281 #endif
282     }
283 #if 0
284   /* Uncomment this block if you want to trap on reads from unwritten memory.  */
285   if (!skip_init && !initted [address])
286     {
287       static int uninit_count = 0;
288       fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc);
289       uninit_count ++;
290       if (uninit_count > 5)
291 	exit (1);
292     }
293 #endif
294   return memory [address];
295 }
296 
297 extern jmp_buf decode_jmp_buf;
298 #define DO_RETURN(x) longjmp (decode_jmp_buf, x)
299 
300 #define CHECK_ALIGNMENT(a,v,m) \
301   if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \
302     DO_RETURN (RL78_MAKE_HIT_BREAK ()); }
303 
304 /* ---------------------------------------------------------------------- */
305 #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00))
306 
307 void
308 mem_put_qi (int address, unsigned char value)
309 {
310   if (!SPECIAL_ADDR (address))
311     tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value);
312   mem_put_byte (address, value);
313 }
314 
315 void
316 mem_put_hi (int address, unsigned short value)
317 {
318   if (!SPECIAL_ADDR (address))
319     tprintf ("\033[34m([%05X]<-%04X)\033[0m", address, value);
320   CHECK_ALIGNMENT (address, value, 1);
321   if (address > 0xffff8 && address != RL78_SFR_SP)
322     {
323       tprintf ("Word access to 0x%05x!!\n", address);
324       DO_RETURN (RL78_MAKE_HIT_BREAK ());
325     }
326   mem_put_byte (address, value);
327   mem_put_byte (address + 1, value >> 8);
328 }
329 
330 void
331 mem_put_psi (int address, unsigned long value)
332 {
333   tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address, value);
334   mem_put_byte (address, value);
335   mem_put_byte (address + 1, value >> 8);
336   mem_put_byte (address + 2, value >> 16);
337 }
338 
339 void
340 mem_put_si (int address, unsigned long value)
341 {
342   tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address, value);
343   CHECK_ALIGNMENT (address, value, 3);
344   mem_put_byte (address, value);
345   mem_put_byte (address + 1, value >> 8);
346   mem_put_byte (address + 2, value >> 16);
347   mem_put_byte (address + 3, value >> 24);
348 }
349 
350 void
351 mem_put_blk (int address, const void *bufptr, int nbytes)
352 {
353   const unsigned char *bp = (unsigned char *)bufptr;
354   while (nbytes --)
355     mem_put_byte (address ++, *bp ++);
356 }
357 
358 unsigned char
359 mem_get_pc (int address)
360 {
361   /* Catch obvious problems.  */
362   if (address >= rom_limit && address < 0xf0000)
363     return 0xff;
364   /* This does NOT go through the flash mirror area; you cannot
365      execute out of the mirror.  */
366   return memory [address & MASK];
367 }
368 
369 unsigned char
370 mem_get_qi (int address)
371 {
372   int v;
373   v = mem_get_byte (address);
374   if (!SPECIAL_ADDR (address))
375     tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
376   if (last_addr_was_mirror)
377     {
378       pending_clocks += 3;
379       tprintf ("ROM read\n");
380     }
381   return v;
382 }
383 
384 unsigned short
385 mem_get_hi (int address)
386 {
387   int v;
388   v = mem_get_byte (address)
389     | mem_get_byte (address + 1) * 256;
390   CHECK_ALIGNMENT (address, v, 1);
391   if (!SPECIAL_ADDR (address))
392     tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
393   if (last_addr_was_mirror)
394     {
395       pending_clocks += 3;
396       tprintf ("ROM read\n");
397     }
398   return v;
399 }
400 
401 unsigned long
402 mem_get_psi (int address)
403 {
404   int v;
405   v = mem_get_byte (address)
406     | mem_get_byte (address + 1) * 256
407     | mem_get_byte (address + 2) * 65536;
408   tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
409   return v;
410 }
411 
412 unsigned long
413 mem_get_si (int address)
414 {
415   int v;
416   v = mem_get_byte (address)
417     | mem_get_byte (address + 1) * 256
418     | mem_get_byte (address + 2) * 65536
419     | mem_get_byte (address + 2) * 16777216;
420   CHECK_ALIGNMENT (address, v, 3);
421   tprintf ("(\033[35m[%05X]->%04X)\033[0m", address, v);
422   return v;
423 }
424 
425 void
426 mem_get_blk (int address, void *bufptr, int nbytes)
427 {
428   unsigned char *bp = (unsigned char *)bufptr;
429   while (nbytes --)
430     *bp ++ = mem_get_byte (address ++);
431 }
432 
433 int
434 sign_ext (int v, int bits)
435 {
436   if (bits < 8 * sizeof (int))
437     {
438       v &= (1 << bits) - 1;
439       if (v & (1 << (bits - 1)))
440 	v -= (1 << bits);
441     }
442   return v;
443 }
444