1 /* mem.c --- memory for RL78 simulator.
3 Copyright (C) 2011-2024 Free Software Foundation, Inc.
4 Contributed by Red Hat, Inc.
6 This file is part of the GNU simulators.
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.
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.
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/>.
22 /* This must come before any other includes. */
29 #include "opcode/rl78.h"
33 #define ILLEGAL_OPCODE 0xff
35 int rom_limit
= 0x100000;
36 int ram_base
= 0xf8000;
37 unsigned char memory
[MEM_SIZE
];
40 unsigned char initted
[MEM_SIZE
];
43 #define tprintf if (trace) printf
48 memset (memory
, ILLEGAL_OPCODE
, sizeof (memory
));
49 memset (memory
+ 0xf0000, 0x33, 0x10000);
51 memset (initted
, 0, sizeof (initted
));
52 memset (initted
+ 0xffee0, 1, 0x00120);
53 memset (initted
+ 0xf0000, 1, 0x01000);
57 mem_ram_size (int ram_bytes
)
59 ram_base
= 0x100000 - ram_bytes
;
63 mem_rom_size (int rom_bytes
)
65 rom_limit
= rom_bytes
;
68 static int mirror_rom_base
= 0x01000;
69 static int mirror_ram_base
= 0xf1000;
70 static int mirror_length
= 0x7000;
73 mem_set_mirror (int rom_base
, int ram_base
, int length
)
75 mirror_rom_base
= rom_base
;
76 mirror_ram_base
= ram_base
;
77 mirror_length
= length
;
80 /* ---------------------------------------------------------------------- */
81 /* Note: the RL78 memory map has a few surprises. For starters, part
82 of the first 64k is mapped to the last 64k, depending on an SFR bit
83 and how much RAM the chip has. This is simulated here, as are a
86 /* This is stdout. We only care about the data byte, not the upper byte. */
91 /* RL78/G13 multiply/divide peripheral. */
99 static long long mduc_clock
= 0;
100 static int mda_set
= 0;
103 static int last_addr_was_mirror
;
106 address_mapping (int address
)
109 if (address
>= mirror_ram_base
&& address
< mirror_ram_base
+ mirror_length
)
111 address
= address
- mirror_ram_base
+ mirror_rom_base
;
112 if (memory
[RL78_SFR_PMC
] & 1)
116 last_addr_was_mirror
= 1;
119 last_addr_was_mirror
= 0;
125 mem_put_byte (int address
, unsigned char value
)
127 address
= address_mapping (address
);
128 memory
[address
] = value
;
129 initted
[address
] = 1;
130 if (address
== SDR00
)
137 if (timer_enabled
== 2)
141 memset (counts_per_insn
, 0, sizeof (counts_per_insn
));
142 memory
[0xf0180] = 0xff;
143 memory
[0xf0181] = 0xff;
150 if (address
== RL78_SFR_SP
&& value
& 1)
152 printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value
, pc
);
161 if ((value
& 0x81) == 0x81)
164 mduc_clock
= total_clocks
;
167 if ((address
& ~3) == MDAL
)
169 mda_set
|= (1 << (address
& 3));
170 if (mda_set
== MDA_SET
)
173 unsigned long alu
, ahu
;
178 switch (memory
[MDUC
] & 0xc8)
181 alu
= mem_get_hi (MDAL
);
182 ahu
= mem_get_hi (MDAH
);
184 tprintf ("MDUC: %lu * %lu = %lu\n", alu
, ahu
, rvu
);
185 mem_put_hi (MDBL
, rvu
& 0xffff);
186 mem_put_hi (MDBH
, rvu
>> 16);
189 als
= sign_ext (mem_get_hi (MDAL
), 16);
190 ahs
= sign_ext (mem_get_hi (MDAH
), 16);
192 tprintf ("MDUC: %ld * %ld = %ld\n", als
, ahs
, rvs
);
193 mem_put_hi (MDBL
, rvs
& 0xffff);
194 mem_put_hi (MDBH
, rvs
>> 16);
197 alu
= mem_get_hi (MDAL
);
198 ahu
= mem_get_hi (MDAH
);
200 mem_put_hi (MDBL
, rvu
& 0xffff);
201 mem_put_hi (MDBH
, rvu
>> 16);
202 mdc
= mem_get_si (MDCL
);
203 tprintf ("MDUC: %lu * %lu + %lu = ", alu
, ahu
, mdc
);
205 tprintf ("%lu\n", mdc
);
206 mem_put_si (MDCL
, mdc
);
209 als
= sign_ext (mem_get_hi (MDAL
), 16);
210 ahs
= sign_ext (mem_get_hi (MDAH
), 16);
212 mem_put_hi (MDBL
, rvs
& 0xffff);
213 mem_put_hi (MDBH
, rvs
>> 16);
214 mdc
= mem_get_si (MDCL
);
215 tprintf ("MDUC: %ld * %ld + %ld = ", als
, ahs
, mdc
);
216 tprintf ("%ld\n", mdc
);
218 mem_put_si (MDCL
, mdc
);
225 extern long long total_clocks
;
228 mem_get_byte (int address
)
230 address
= address_mapping (address
);
240 return memory
[address
];
244 unsigned char mduc
= memory
[MDUC
];
245 if ((mduc
& 0x81) == 0x81
246 && total_clocks
> mduc_clock
+ 16)
248 unsigned long a
, b
, q
, r
;
249 memory
[MDUC
] &= 0xfe;
250 a
= mem_get_si (MDAL
);
251 b
= mem_get_hi (MDBL
) | (mem_get_hi (MDBH
) << 16);
262 tprintf ("MDUC: %lu / %lu = q %lu, r %lu\n", a
, b
, q
, r
);
263 mem_put_si (MDAL
, q
);
264 mem_put_si (MDCL
, r
);
266 return memory
[address
];
272 return memory
[address
];
274 if (address
< 0xf1000 && address
>= 0xf0000)
277 /* Note: comment out this return to trap the invalid access
278 instead of returning an "undefined" value. */
281 fprintf (stderr
, "SFR access error: addr 0x%05x pc 0x%05x\n", address
, pc
);
286 /* Uncomment this block if you want to trap on reads from unwritten memory. */
287 if (!skip_init
&& !initted
[address
])
289 static int uninit_count
= 0;
290 fprintf (stderr
, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address
, pc
);
292 if (uninit_count
> 5)
296 return memory
[address
];
299 extern jmp_buf decode_jmp_buf
;
300 #define DO_RETURN(x) longjmp (decode_jmp_buf, x)
302 #define CHECK_ALIGNMENT(a,v,m) \
303 if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \
304 DO_RETURN (RL78_MAKE_HIT_BREAK ()); }
306 /* ---------------------------------------------------------------------- */
307 #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00))
310 mem_put_qi (int address
, unsigned char value
)
312 if (!SPECIAL_ADDR (address
))
313 tprintf ("\033[34m([%05X]<-%02X)\033[0m", address
, value
);
314 mem_put_byte (address
, value
);
318 mem_put_hi (int address
, unsigned short value
)
320 if (!SPECIAL_ADDR (address
))
321 tprintf ("\033[34m([%05X]<-%04X)\033[0m", address
, value
);
322 CHECK_ALIGNMENT (address
, value
, 1);
323 if (address
> 0xffff8 && address
!= RL78_SFR_SP
)
325 tprintf ("Word access to 0x%05x!!\n", address
);
326 DO_RETURN (RL78_MAKE_HIT_BREAK ());
328 mem_put_byte (address
, value
);
329 mem_put_byte (address
+ 1, value
>> 8);
333 mem_put_psi (int address
, unsigned long value
)
335 tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address
, value
);
336 mem_put_byte (address
, value
);
337 mem_put_byte (address
+ 1, value
>> 8);
338 mem_put_byte (address
+ 2, value
>> 16);
342 mem_put_si (int address
, unsigned long value
)
344 tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address
, value
);
345 CHECK_ALIGNMENT (address
, value
, 3);
346 mem_put_byte (address
, value
);
347 mem_put_byte (address
+ 1, value
>> 8);
348 mem_put_byte (address
+ 2, value
>> 16);
349 mem_put_byte (address
+ 3, value
>> 24);
353 mem_put_blk (int address
, const void *bufptr
, int nbytes
)
355 const unsigned char *bp
= (unsigned char *)bufptr
;
357 mem_put_byte (address
++, *bp
++);
361 mem_get_pc (int address
)
363 /* Catch obvious problems. */
364 if (address
>= rom_limit
&& address
< 0xf0000)
366 /* This does NOT go through the flash mirror area; you cannot
367 execute out of the mirror. */
368 return memory
[address
& MASK
];
372 mem_get_qi (int address
)
375 v
= mem_get_byte (address
);
376 if (!SPECIAL_ADDR (address
))
377 tprintf ("\033[35m([%05X]->%04X)\033[0m", address
, v
);
378 if (last_addr_was_mirror
)
381 tprintf ("ROM read\n");
387 mem_get_hi (int address
)
390 v
= mem_get_byte (address
)
391 | mem_get_byte (address
+ 1) * 256;
392 CHECK_ALIGNMENT (address
, v
, 1);
393 if (!SPECIAL_ADDR (address
))
394 tprintf ("\033[35m([%05X]->%04X)\033[0m", address
, v
);
395 if (last_addr_was_mirror
)
398 tprintf ("ROM read\n");
404 mem_get_psi (int address
)
407 v
= mem_get_byte (address
)
408 | mem_get_byte (address
+ 1) * 256
409 | mem_get_byte (address
+ 2) * 65536;
410 tprintf ("\033[35m([%05X]->%04X)\033[0m", address
, v
);
415 mem_get_si (int address
)
418 v
= mem_get_byte (address
)
419 | mem_get_byte (address
+ 1) * 256
420 | mem_get_byte (address
+ 2) * 65536
421 | mem_get_byte (address
+ 2) * 16777216;
422 CHECK_ALIGNMENT (address
, v
, 3);
423 tprintf ("(\033[35m[%05X]->%04X)\033[0m", address
, v
);
428 mem_get_blk (int address
, void *bufptr
, int nbytes
)
430 unsigned char *bp
= (unsigned char *)bufptr
;
432 *bp
++ = mem_get_byte (address
++);
436 sign_ext (int v
, int bits
)
438 if (bits
< 8 * sizeof (int))
440 v
&= (1 << bits
) - 1;
441 if (v
& (1 << (bits
- 1)))