]> Git Repo - binutils.git/blob - sim/rl78/mem.c
Automatic date update in version.in
[binutils.git] / sim / rl78 / mem.c
1 /* mem.c --- memory for RL78 simulator.
2
3    Copyright (C) 2011-2022 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 }
This page took 0.054364 seconds and 4 git commands to generate.