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