PowerPC relocations for prefix insns
[external/binutils.git] / sim / rl78 / mem.c
1 /* mem.c --- memory for RL78 simulator.
2
3    Copyright (C) 2011-2019 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 }