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