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