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