0b6ab8e79f1848152d8d44da22533318e597dd2d
[deliverable/binutils-gdb.git] / sim / rl78 / mem.c
1 /* mem.c --- memory for RL78 simulator.
2
3 Copyright (C) 2011-2021 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.038149 seconds and 3 git commands to generate.