]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/rl78/mem.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / rl78 / mem.c
CommitLineData
87326c78
DD
1/* mem.c --- memory for RL78 simulator.
2
8acc9f48 3 Copyright (C) 2011-2013 Free Software Foundation, Inc.
87326c78
DD
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
33int rom_limit = 0x100000;
34int ram_base = 0xf8000;
35unsigned char memory[MEM_SIZE];
36#define MASK 0xfffff
37
38unsigned char initted[MEM_SIZE];
39int skip_init = 0;
40
41#define tprintf if (trace) printf
42
43void
44init_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
54void
55mem_ram_size (int ram_bytes)
56{
57 ram_base = 0x100000 - ram_bytes;
58}
59
60void
61mem_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
85static long long mduc_clock = 0;
86static int mda_set = 0;
87#define MDA_SET 15
88
89static int last_addr_was_mirror;
90
91static int
92address_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
112static void
113mem_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
205extern long long total_clocks;
206
207static unsigned char
208mem_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
279extern 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
289void
290mem_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
297void
298mem_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
312void
313mem_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
321void
322mem_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
332void
333mem_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
340unsigned char
341mem_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
351unsigned char
352mem_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
366unsigned short
367mem_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
383unsigned long
384mem_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
394unsigned long
395mem_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
407void
408mem_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
415int
416sign_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}