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