]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/rl78/mem.c
sim: create a makefile fragment to pass common settings down
[thirdparty/binutils-gdb.git] / sim / rl78 / mem.c
CommitLineData
87326c78
DD
1/* mem.c --- memory for RL78 simulator.
2
3666a048 3 Copyright (C) 2011-2021 Free Software Foundation, Inc.
87326c78
DD
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
6df01ab8
MF
22/* This must come before any other includes. */
23#include "defs.h"
24
87326c78
DD
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
35int rom_limit = 0x100000;
36int ram_base = 0xf8000;
37unsigned char memory[MEM_SIZE];
38#define MASK 0xfffff
39
40unsigned char initted[MEM_SIZE];
41int skip_init = 0;
42
43#define tprintf if (trace) printf
44
45void
46init_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
56void
57mem_ram_size (int ram_bytes)
58{
59 ram_base = 0x100000 - ram_bytes;
60}
61
62void
63mem_rom_size (int rom_bytes)
64{
65 rom_limit = rom_bytes;
66}
67
5318ba65
MF
68static int mirror_rom_base = 0x01000;
69static int mirror_ram_base = 0xf1000;
70static int mirror_length = 0x7000;
0952813b
DD
71
72void
73mem_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
87326c78
DD
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
69276d02
NC
95#define MDBL 0xffff6
96#define MDBH 0xffff4
87326c78
DD
97#define MDCL 0xf00e0
98#define MDCH 0xf00e2
99static long long mduc_clock = 0;
100static int mda_set = 0;
101#define MDA_SET 15
102
103static int last_addr_was_mirror;
104
105static int
106address_mapping (int address)
107{
108 address &= MASK;
0952813b 109 if (address >= mirror_ram_base && address < mirror_ram_base + mirror_length)
87326c78 110 {
0952813b 111 address = address - mirror_ram_base + mirror_rom_base;
87326c78
DD
112 if (memory[RL78_SFR_PMC] & 1)
113 {
87326c78
DD
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
124static void
125mem_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 }
4819f490
NC
155
156 if (! g13_multiply)
157 return;
158
87326c78
DD
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);
4819f490
NC
185 mem_put_hi (MDBL, rvu & 0xffff);
186 mem_put_hi (MDBH, rvu >> 16);
87326c78
DD
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);
4819f490
NC
193 mem_put_hi (MDBL, rvs & 0xffff);
194 mem_put_hi (MDBH, rvs >> 16);
87326c78
DD
195 break;
196 case 0x40:
197 alu = mem_get_hi (MDAL);
198 ahu = mem_get_hi (MDAH);
199 rvu = alu * ahu;
4819f490
NC
200 mem_put_hi (MDBL, rvu & 0xffff);
201 mem_put_hi (MDBH, rvu >> 16);
87326c78
DD
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;
4819f490
NC
212 mem_put_hi (MDBL, rvs & 0xffff);
213 mem_put_hi (MDBH, rvs >> 16);
87326c78
DD
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
225extern long long total_clocks;
226
227static unsigned char
228mem_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);
4819f490 251 b = mem_get_hi (MDBL) | (mem_get_hi (MDBH) << 16);
87326c78
DD
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
299extern 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
309void
310mem_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
317void
318mem_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
332void
333mem_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
341void
342mem_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
352void
353mem_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
360unsigned char
361mem_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
371unsigned char
372mem_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
386unsigned short
387mem_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
403unsigned long
404mem_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
414unsigned long
415mem_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
427void
428mem_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
435int
436sign_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}