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