Silence uninitialized warning on ehdr_start_save
[platform/upstream/binutils.git] / sim / rl78 / mem.c
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 }