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