Update copyright year range in all GDB files.
[deliverable/binutils-gdb.git] / sim / rl78 / mem.c
CommitLineData
87326c78
DD
1/* mem.c --- memory for RL78 simulator.
2
b811d2c2 3 Copyright (C) 2011-2020 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
0952813b
DD
66int mirror_rom_base = 0x01000;
67int mirror_ram_base = 0xf1000;
68int mirror_length = 0x7000;
69
70void
71mem_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
87326c78
DD
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
69276d02
NC
93#define MDBL 0xffff6
94#define MDBH 0xffff4
87326c78
DD
95#define MDCL 0xf00e0
96#define MDCH 0xf00e2
97static long long mduc_clock = 0;
98static int mda_set = 0;
99#define MDA_SET 15
100
101static int last_addr_was_mirror;
102
103static int
104address_mapping (int address)
105{
106 address &= MASK;
0952813b 107 if (address >= mirror_ram_base && address < mirror_ram_base + mirror_length)
87326c78 108 {
0952813b 109 address = address - mirror_ram_base + mirror_rom_base;
87326c78
DD
110 if (memory[RL78_SFR_PMC] & 1)
111 {
87326c78
DD
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
122static void
123mem_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 }
4819f490
NC
153
154 if (! g13_multiply)
155 return;
156
87326c78
DD
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);
4819f490
NC
183 mem_put_hi (MDBL, rvu & 0xffff);
184 mem_put_hi (MDBH, rvu >> 16);
87326c78
DD
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);
4819f490
NC
191 mem_put_hi (MDBL, rvs & 0xffff);
192 mem_put_hi (MDBH, rvs >> 16);
87326c78
DD
193 break;
194 case 0x40:
195 alu = mem_get_hi (MDAL);
196 ahu = mem_get_hi (MDAH);
197 rvu = alu * ahu;
4819f490
NC
198 mem_put_hi (MDBL, rvu & 0xffff);
199 mem_put_hi (MDBH, rvu >> 16);
87326c78
DD
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;
4819f490
NC
210 mem_put_hi (MDBL, rvs & 0xffff);
211 mem_put_hi (MDBH, rvs >> 16);
87326c78
DD
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
223extern long long total_clocks;
224
225static unsigned char
226mem_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);
4819f490 249 b = mem_get_hi (MDBL) | (mem_get_hi (MDBH) << 16);
87326c78
DD
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
297extern 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
307void
308mem_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
315void
316mem_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
330void
331mem_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
339void
340mem_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
350void
351mem_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
358unsigned char
359mem_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
369unsigned char
370mem_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
384unsigned short
385mem_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
401unsigned long
402mem_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
412unsigned long
413mem_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
425void
426mem_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
433int
434sign_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}
This page took 0.397998 seconds and 4 git commands to generate.