1 /* mem.c --- memory for RL78 simulator.
4 Free Software Foundation, Inc.
5 Contributed by Red Hat, Inc.
7 This file is part of the GNU simulators.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "opcode/rl78.h"
32 #define ILLEGAL_OPCODE 0xff
34 int rom_limit = 0x100000;
35 int ram_base = 0xf8000;
36 unsigned char memory[MEM_SIZE];
39 unsigned char initted[MEM_SIZE];
42 #define tprintf if (trace) printf
47 memset (memory, ILLEGAL_OPCODE, sizeof (memory));
48 memset (memory + 0xf0000, 0x33, 0x10000);
50 memset (initted, 0, sizeof (initted));
51 memset (initted + 0xffee0, 1, 0x00120);
52 memset (initted + 0xf0000, 1, 0x01000);
56 mem_ram_size (int ram_bytes)
58 ram_base = 0x100000 - ram_bytes;
62 mem_rom_size (int rom_bytes)
64 rom_limit = rom_bytes;
67 /* ---------------------------------------------------------------------- */
68 /* Note: the RL78 memory map has a few surprises. For starters, part
69 of the first 64k is mapped to the last 64k, depending on an SFR bit
70 and how much RAM the chip has. This is simulated here, as are a
73 /* This is stdout. We only care about the data byte, not the upper byte. */
78 /* RL78/G13 multiply/divide peripheral. */
86 static long long mduc_clock = 0;
87 static int mda_set = 0;
90 static int last_addr_was_mirror;
93 address_mapping (int address)
96 if (address >= 0xf1000 && address < ram_base)
100 if (memory[RL78_SFR_PMC] & 1)
105 last_addr_was_mirror = 1;
108 last_addr_was_mirror = 0;
114 mem_put_byte (int address, unsigned char value)
116 address = address_mapping (address);
117 memory [address] = value;
118 initted [address] = 1;
119 if (address == SDR00)
126 if (timer_enabled == 2)
130 memset (counts_per_insn, 0, sizeof (counts_per_insn));
131 memory[0xf0180] = 0xff;
132 memory[0xf0181] = 0xff;
139 if (address == RL78_SFR_SP && value & 1)
141 printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc);
146 if ((value & 0x81) == 0x81)
149 mduc_clock = total_clocks;
152 if ((address & ~3) == MDAL)
154 mda_set |= (1 << (address & 3));
155 if (mda_set == MDA_SET)
158 unsigned long alu, ahu;
163 switch (memory [MDUC] & 0xc8)
166 alu = mem_get_hi (MDAL);
167 ahu = mem_get_hi (MDAH);
169 tprintf ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu);
170 mem_put_si (MDBL, rvu);
173 als = sign_ext (mem_get_hi (MDAL), 16);
174 ahs = sign_ext (mem_get_hi (MDAH), 16);
176 tprintf ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs);
177 mem_put_si (MDBL, rvs);
180 alu = mem_get_hi (MDAL);
181 ahu = mem_get_hi (MDAH);
183 mem_put_si (MDBL, rvu);
184 mdc = mem_get_si (MDCL);
185 tprintf ("MDUC: %lu * %lu + %lu = ", alu, ahu, mdc);
187 tprintf ("%lu\n", mdc);
188 mem_put_si (MDCL, mdc);
191 als = sign_ext (mem_get_hi (MDAL), 16);
192 ahs = sign_ext (mem_get_hi (MDAH), 16);
194 mem_put_si (MDBL, rvs);
195 mdc = mem_get_si (MDCL);
196 tprintf ("MDUC: %ld * %ld + %ld = ", als, ahs, mdc);
197 tprintf ("%ld\n", mdc);
199 mem_put_si (MDCL, mdc);
206 extern long long total_clocks;
209 mem_get_byte (int address)
211 address = address_mapping (address);
221 return memory[address];
225 unsigned char mduc = memory [MDUC];
226 if ((mduc & 0x81) == 0x81
227 && total_clocks > mduc_clock + 16)
229 unsigned long a, b, q, r;
230 memory [MDUC] &= 0xfe;
231 a = mem_get_si (MDAL);
232 b = mem_get_si (MDAL);
243 tprintf ("MDUC: %lu / %lu = q %lu, r %lu\n", a, b, q, r);
244 mem_put_si (MDAL, q);
245 mem_put_si (MDCL, r);
247 return memory[address];
253 return memory[address];
255 if (address < 0xf1000 && address >= 0xf0000)
258 /* Note: comment out this return to trap the invalid access
259 instead of returning an "undefined" value. */
262 fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc);
267 /* Uncomment this block if you want to trap on reads from unwritten memory. */
268 if (!skip_init && !initted [address])
270 static int uninit_count = 0;
271 fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc);
273 if (uninit_count > 5)
277 return memory [address];
280 extern jmp_buf decode_jmp_buf;
281 #define DO_RETURN(x) longjmp (decode_jmp_buf, x)
283 #define CHECK_ALIGNMENT(a,v,m) \
284 if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \
285 DO_RETURN (RL78_MAKE_HIT_BREAK ()); }
287 /* ---------------------------------------------------------------------- */
288 #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00))
291 mem_put_qi (int address, unsigned char value)
293 if (!SPECIAL_ADDR (address))
294 tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value);
295 mem_put_byte (address, value);
299 mem_put_hi (int address, unsigned short value)
301 if (!SPECIAL_ADDR (address))
302 tprintf ("\033[34m([%05X]<-%04X)\033[0m", address, value);
303 CHECK_ALIGNMENT (address, value, 1);
304 if (address > 0xffff8 && address != RL78_SFR_SP)
306 tprintf ("Word access to 0x%05x!!\n", address);
307 DO_RETURN (RL78_MAKE_HIT_BREAK ());
309 mem_put_byte (address, value);
310 mem_put_byte (address + 1, value >> 8);
314 mem_put_psi (int address, unsigned long value)
316 tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address, value);
317 mem_put_byte (address, value);
318 mem_put_byte (address + 1, value >> 8);
319 mem_put_byte (address + 2, value >> 16);
323 mem_put_si (int address, unsigned long value)
325 tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address, value);
326 CHECK_ALIGNMENT (address, value, 3);
327 mem_put_byte (address, value);
328 mem_put_byte (address + 1, value >> 8);
329 mem_put_byte (address + 2, value >> 16);
330 mem_put_byte (address + 3, value >> 24);
334 mem_put_blk (int address, const void *bufptr, int nbytes)
336 const unsigned char *bp = (unsigned char *)bufptr;
338 mem_put_byte (address ++, *bp ++);
342 mem_get_pc (int address)
344 /* Catch obvious problems. */
345 if (address >= rom_limit && address < 0xf0000)
347 /* This does NOT go through the flash mirror area; you cannot
348 execute out of the mirror. */
349 return memory [address & MASK];
353 mem_get_qi (int address)
356 v = mem_get_byte (address);
357 if (!SPECIAL_ADDR (address))
358 tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
359 if (last_addr_was_mirror)
362 tprintf ("ROM read\n");
368 mem_get_hi (int address)
371 v = mem_get_byte (address)
372 | mem_get_byte (address + 1) * 256;
373 CHECK_ALIGNMENT (address, v, 1);
374 if (!SPECIAL_ADDR (address))
375 tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
376 if (last_addr_was_mirror)
379 tprintf ("ROM read\n");
385 mem_get_psi (int address)
388 v = mem_get_byte (address)
389 | mem_get_byte (address + 1) * 256
390 | mem_get_byte (address + 2) * 65536;
391 tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
396 mem_get_si (int address)
399 v = mem_get_byte (address)
400 | mem_get_byte (address + 1) * 256
401 | mem_get_byte (address + 2) * 65536
402 | mem_get_byte (address + 2) * 16777216;
403 CHECK_ALIGNMENT (address, v, 3);
404 tprintf ("(\033[35m[%05X]->%04X)\033[0m", address, v);
409 mem_get_blk (int address, void *bufptr, int nbytes)
411 unsigned char *bp = (unsigned char *)bufptr;
413 *bp ++ = mem_get_byte (address ++);
417 sign_ext (int v, int bits)
419 if (bits < 8 * sizeof (int))
421 v &= (1 << bits) - 1;
422 if (v & (1 << (bits - 1)))