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