1 1.1 christos /* mem.c --- memory for RL78 simulator. 2 1.1 christos 3 1.1.1.11 christos Copyright (C) 2011-2025 Free Software Foundation, Inc. 4 1.1 christos Contributed by Red Hat, Inc. 5 1.1 christos 6 1.1 christos This file is part of the GNU simulators. 7 1.1 christos 8 1.1 christos This program is free software; you can redistribute it and/or modify 9 1.1 christos it under the terms of the GNU General Public License as published by 10 1.1 christos the Free Software Foundation; either version 3 of the License, or 11 1.1 christos (at your option) any later version. 12 1.1 christos 13 1.1 christos This program is distributed in the hope that it will be useful, 14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 christos GNU General Public License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. 20 1.1 christos */ 21 1.1 christos 22 1.1.1.9 christos /* This must come before any other includes. */ 23 1.1.1.9 christos #include "defs.h" 24 1.1.1.9 christos 25 1.1 christos #include <stdio.h> 26 1.1 christos #include <stdlib.h> 27 1.1 christos #include <string.h> 28 1.1 christos 29 1.1 christos #include "opcode/rl78.h" 30 1.1 christos #include "mem.h" 31 1.1 christos #include "cpu.h" 32 1.1 christos 33 1.1 christos #define ILLEGAL_OPCODE 0xff 34 1.1 christos 35 1.1 christos int rom_limit = 0x100000; 36 1.1 christos int ram_base = 0xf8000; 37 1.1 christos unsigned char memory[MEM_SIZE]; 38 1.1 christos #define MASK 0xfffff 39 1.1 christos 40 1.1 christos unsigned char initted[MEM_SIZE]; 41 1.1 christos int skip_init = 0; 42 1.1 christos 43 1.1 christos #define tprintf if (trace) printf 44 1.1 christos 45 1.1 christos void 46 1.1 christos init_mem (void) 47 1.1 christos { 48 1.1 christos memset (memory, ILLEGAL_OPCODE, sizeof (memory)); 49 1.1 christos memset (memory + 0xf0000, 0x33, 0x10000); 50 1.1 christos 51 1.1 christos memset (initted, 0, sizeof (initted)); 52 1.1 christos memset (initted + 0xffee0, 1, 0x00120); 53 1.1 christos memset (initted + 0xf0000, 1, 0x01000); 54 1.1 christos } 55 1.1 christos 56 1.1 christos void 57 1.1 christos mem_ram_size (int ram_bytes) 58 1.1 christos { 59 1.1 christos ram_base = 0x100000 - ram_bytes; 60 1.1 christos } 61 1.1 christos 62 1.1 christos void 63 1.1 christos mem_rom_size (int rom_bytes) 64 1.1 christos { 65 1.1 christos rom_limit = rom_bytes; 66 1.1 christos } 67 1.1 christos 68 1.1.1.9 christos static int mirror_rom_base = 0x01000; 69 1.1.1.9 christos static int mirror_ram_base = 0xf1000; 70 1.1.1.9 christos static int mirror_length = 0x7000; 71 1.1.1.4 christos 72 1.1.1.4 christos void 73 1.1.1.4 christos mem_set_mirror (int rom_base, int ram_base, int length) 74 1.1.1.4 christos { 75 1.1.1.4 christos mirror_rom_base = rom_base; 76 1.1.1.4 christos mirror_ram_base = ram_base; 77 1.1.1.4 christos mirror_length = length; 78 1.1.1.4 christos } 79 1.1.1.4 christos 80 1.1 christos /* ---------------------------------------------------------------------- */ 81 1.1 christos /* Note: the RL78 memory map has a few surprises. For starters, part 82 1.1 christos of the first 64k is mapped to the last 64k, depending on an SFR bit 83 1.1 christos and how much RAM the chip has. This is simulated here, as are a 84 1.1 christos few peripherals. */ 85 1.1 christos 86 1.1 christos /* This is stdout. We only care about the data byte, not the upper byte. */ 87 1.1 christos #define SDR00 0xfff10 88 1.1 christos #define SSR00 0xf0100 89 1.1 christos #define TS0 0xf01b2 90 1.1 christos 91 1.1 christos /* RL78/G13 multiply/divide peripheral. */ 92 1.1 christos #define MDUC 0xf00e8 93 1.1 christos #define MDAL 0xffff0 94 1.1 christos #define MDAH 0xffff2 95 1.1 christos #define MDBL 0xffff6 96 1.1 christos #define MDBH 0xffff4 97 1.1 christos #define MDCL 0xf00e0 98 1.1 christos #define MDCH 0xf00e2 99 1.1 christos static long long mduc_clock = 0; 100 1.1 christos static int mda_set = 0; 101 1.1 christos #define MDA_SET 15 102 1.1 christos 103 1.1 christos static int last_addr_was_mirror; 104 1.1 christos 105 1.1 christos static int 106 1.1 christos address_mapping (int address) 107 1.1 christos { 108 1.1 christos address &= MASK; 109 1.1.1.4 christos if (address >= mirror_ram_base && address < mirror_ram_base + mirror_length) 110 1.1 christos { 111 1.1.1.4 christos address = address - mirror_ram_base + mirror_rom_base; 112 1.1 christos if (memory[RL78_SFR_PMC] & 1) 113 1.1 christos { 114 1.1 christos address |= 0x10000; 115 1.1 christos } 116 1.1 christos last_addr_was_mirror = 1; 117 1.1 christos } 118 1.1 christos else 119 1.1 christos last_addr_was_mirror = 0; 120 1.1 christos 121 1.1 christos return address; 122 1.1 christos } 123 1.1 christos 124 1.1 christos static void 125 1.1 christos mem_put_byte (int address, unsigned char value) 126 1.1 christos { 127 1.1 christos address = address_mapping (address); 128 1.1 christos memory [address] = value; 129 1.1 christos initted [address] = 1; 130 1.1 christos if (address == SDR00) 131 1.1 christos { 132 1.1 christos putchar (value); 133 1.1 christos fflush (stdout); 134 1.1 christos } 135 1.1 christos if (address == TS0) 136 1.1 christos { 137 1.1 christos if (timer_enabled == 2) 138 1.1 christos { 139 1.1 christos total_clocks = 0; 140 1.1 christos pending_clocks = 0; 141 1.1 christos memset (counts_per_insn, 0, sizeof (counts_per_insn)); 142 1.1 christos memory[0xf0180] = 0xff; 143 1.1 christos memory[0xf0181] = 0xff; 144 1.1 christos } 145 1.1 christos if (value & 1) 146 1.1 christos timer_enabled = 1; 147 1.1 christos else 148 1.1 christos timer_enabled = 0; 149 1.1 christos } 150 1.1 christos if (address == RL78_SFR_SP && value & 1) 151 1.1 christos { 152 1.1 christos printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc); 153 1.1 christos value &= ~1; 154 1.1 christos } 155 1.1.1.4 christos 156 1.1.1.4 christos if (! g13_multiply) 157 1.1.1.4 christos return; 158 1.1.1.4 christos 159 1.1 christos if (address == MDUC) 160 1.1 christos { 161 1.1 christos if ((value & 0x81) == 0x81) 162 1.1 christos { 163 1.1 christos /* division */ 164 1.1 christos mduc_clock = total_clocks; 165 1.1 christos } 166 1.1 christos } 167 1.1 christos if ((address & ~3) == MDAL) 168 1.1 christos { 169 1.1 christos mda_set |= (1 << (address & 3)); 170 1.1 christos if (mda_set == MDA_SET) 171 1.1 christos { 172 1.1 christos long als, ahs; 173 1.1 christos unsigned long alu, ahu; 174 1.1 christos long rvs; 175 1.1 christos long mdc; 176 1.1 christos unsigned long rvu; 177 1.1 christos mda_set = 0; 178 1.1 christos switch (memory [MDUC] & 0xc8) 179 1.1 christos { 180 1.1 christos case 0x00: 181 1.1 christos alu = mem_get_hi (MDAL); 182 1.1 christos ahu = mem_get_hi (MDAH); 183 1.1 christos rvu = alu * ahu; 184 1.1 christos tprintf ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu); 185 1.1.1.4 christos mem_put_hi (MDBL, rvu & 0xffff); 186 1.1.1.4 christos mem_put_hi (MDBH, rvu >> 16); 187 1.1 christos break; 188 1.1 christos case 0x08: 189 1.1 christos als = sign_ext (mem_get_hi (MDAL), 16); 190 1.1 christos ahs = sign_ext (mem_get_hi (MDAH), 16); 191 1.1 christos rvs = als * ahs; 192 1.1 christos tprintf ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs); 193 1.1.1.4 christos mem_put_hi (MDBL, rvs & 0xffff); 194 1.1.1.4 christos mem_put_hi (MDBH, rvs >> 16); 195 1.1 christos break; 196 1.1 christos case 0x40: 197 1.1 christos alu = mem_get_hi (MDAL); 198 1.1 christos ahu = mem_get_hi (MDAH); 199 1.1 christos rvu = alu * ahu; 200 1.1.1.4 christos mem_put_hi (MDBL, rvu & 0xffff); 201 1.1.1.4 christos mem_put_hi (MDBH, rvu >> 16); 202 1.1 christos mdc = mem_get_si (MDCL); 203 1.1 christos tprintf ("MDUC: %lu * %lu + %lu = ", alu, ahu, mdc); 204 1.1 christos mdc += (long) rvu; 205 1.1 christos tprintf ("%lu\n", mdc); 206 1.1 christos mem_put_si (MDCL, mdc); 207 1.1 christos break; 208 1.1 christos case 0x48: 209 1.1 christos als = sign_ext (mem_get_hi (MDAL), 16); 210 1.1 christos ahs = sign_ext (mem_get_hi (MDAH), 16); 211 1.1 christos rvs = als * ahs; 212 1.1.1.4 christos mem_put_hi (MDBL, rvs & 0xffff); 213 1.1.1.4 christos mem_put_hi (MDBH, rvs >> 16); 214 1.1 christos mdc = mem_get_si (MDCL); 215 1.1 christos tprintf ("MDUC: %ld * %ld + %ld = ", als, ahs, mdc); 216 1.1 christos tprintf ("%ld\n", mdc); 217 1.1 christos mdc += rvs; 218 1.1 christos mem_put_si (MDCL, mdc); 219 1.1 christos break; 220 1.1 christos } 221 1.1 christos } 222 1.1 christos } 223 1.1 christos } 224 1.1 christos 225 1.1 christos extern long long total_clocks; 226 1.1 christos 227 1.1 christos static unsigned char 228 1.1 christos mem_get_byte (int address) 229 1.1 christos { 230 1.1 christos address = address_mapping (address); 231 1.1 christos switch (address) 232 1.1 christos { 233 1.1 christos case SSR00: 234 1.1 christos case SSR00 + 1: 235 1.1 christos return 0x00; 236 1.1 christos case 0xf00f0: 237 1.1 christos return 0; 238 1.1 christos case 0xf0180: 239 1.1 christos case 0xf0181: 240 1.1 christos return memory[address]; 241 1.1 christos 242 1.1 christos case MDUC: 243 1.1 christos { 244 1.1 christos unsigned char mduc = memory [MDUC]; 245 1.1 christos if ((mduc & 0x81) == 0x81 246 1.1 christos && total_clocks > mduc_clock + 16) 247 1.1 christos { 248 1.1 christos unsigned long a, b, q, r; 249 1.1 christos memory [MDUC] &= 0xfe; 250 1.1 christos a = mem_get_si (MDAL); 251 1.1.1.4 christos b = mem_get_hi (MDBL) | (mem_get_hi (MDBH) << 16); 252 1.1 christos if (b == 0) 253 1.1 christos { 254 1.1 christos q = ~0; 255 1.1 christos r = ~0; 256 1.1 christos } 257 1.1 christos else 258 1.1 christos { 259 1.1 christos q = a / b; 260 1.1 christos r = a % b; 261 1.1 christos } 262 1.1 christos tprintf ("MDUC: %lu / %lu = q %lu, r %lu\n", a, b, q, r); 263 1.1 christos mem_put_si (MDAL, q); 264 1.1 christos mem_put_si (MDCL, r); 265 1.1 christos } 266 1.1 christos return memory[address]; 267 1.1 christos } 268 1.1 christos case MDCL: 269 1.1 christos case MDCL + 1: 270 1.1 christos case MDCH: 271 1.1 christos case MDCH + 1: 272 1.1 christos return memory[address]; 273 1.1 christos } 274 1.1 christos if (address < 0xf1000 && address >= 0xf0000) 275 1.1 christos { 276 1.1 christos #if 1 277 1.1 christos /* Note: comment out this return to trap the invalid access 278 1.1 christos instead of returning an "undefined" value. */ 279 1.1 christos return 0x11; 280 1.1 christos #else 281 1.1 christos fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc); 282 1.1 christos exit (1); 283 1.1 christos #endif 284 1.1 christos } 285 1.1 christos #if 0 286 1.1 christos /* Uncomment this block if you want to trap on reads from unwritten memory. */ 287 1.1 christos if (!skip_init && !initted [address]) 288 1.1 christos { 289 1.1 christos static int uninit_count = 0; 290 1.1 christos fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc); 291 1.1 christos uninit_count ++; 292 1.1 christos if (uninit_count > 5) 293 1.1 christos exit (1); 294 1.1 christos } 295 1.1 christos #endif 296 1.1 christos return memory [address]; 297 1.1 christos } 298 1.1 christos 299 1.1 christos extern jmp_buf decode_jmp_buf; 300 1.1 christos #define DO_RETURN(x) longjmp (decode_jmp_buf, x) 301 1.1 christos 302 1.1 christos #define CHECK_ALIGNMENT(a,v,m) \ 303 1.1 christos if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \ 304 1.1 christos DO_RETURN (RL78_MAKE_HIT_BREAK ()); } 305 1.1 christos 306 1.1 christos /* ---------------------------------------------------------------------- */ 307 1.1 christos #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00)) 308 1.1 christos 309 1.1 christos void 310 1.1 christos mem_put_qi (int address, unsigned char value) 311 1.1 christos { 312 1.1 christos if (!SPECIAL_ADDR (address)) 313 1.1 christos tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value); 314 1.1 christos mem_put_byte (address, value); 315 1.1 christos } 316 1.1 christos 317 1.1 christos void 318 1.1 christos mem_put_hi (int address, unsigned short value) 319 1.1 christos { 320 1.1 christos if (!SPECIAL_ADDR (address)) 321 1.1 christos tprintf ("\033[34m([%05X]<-%04X)\033[0m", address, value); 322 1.1 christos CHECK_ALIGNMENT (address, value, 1); 323 1.1 christos if (address > 0xffff8 && address != RL78_SFR_SP) 324 1.1 christos { 325 1.1 christos tprintf ("Word access to 0x%05x!!\n", address); 326 1.1 christos DO_RETURN (RL78_MAKE_HIT_BREAK ()); 327 1.1 christos } 328 1.1 christos mem_put_byte (address, value); 329 1.1 christos mem_put_byte (address + 1, value >> 8); 330 1.1 christos } 331 1.1 christos 332 1.1 christos void 333 1.1 christos mem_put_psi (int address, unsigned long value) 334 1.1 christos { 335 1.1 christos tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address, value); 336 1.1 christos mem_put_byte (address, value); 337 1.1 christos mem_put_byte (address + 1, value >> 8); 338 1.1 christos mem_put_byte (address + 2, value >> 16); 339 1.1 christos } 340 1.1 christos 341 1.1 christos void 342 1.1 christos mem_put_si (int address, unsigned long value) 343 1.1 christos { 344 1.1 christos tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address, value); 345 1.1 christos CHECK_ALIGNMENT (address, value, 3); 346 1.1 christos mem_put_byte (address, value); 347 1.1 christos mem_put_byte (address + 1, value >> 8); 348 1.1 christos mem_put_byte (address + 2, value >> 16); 349 1.1 christos mem_put_byte (address + 3, value >> 24); 350 1.1 christos } 351 1.1 christos 352 1.1 christos void 353 1.1 christos mem_put_blk (int address, const void *bufptr, int nbytes) 354 1.1 christos { 355 1.1 christos const unsigned char *bp = (unsigned char *)bufptr; 356 1.1 christos while (nbytes --) 357 1.1 christos mem_put_byte (address ++, *bp ++); 358 1.1 christos } 359 1.1 christos 360 1.1 christos unsigned char 361 1.1 christos mem_get_pc (int address) 362 1.1 christos { 363 1.1 christos /* Catch obvious problems. */ 364 1.1 christos if (address >= rom_limit && address < 0xf0000) 365 1.1 christos return 0xff; 366 1.1 christos /* This does NOT go through the flash mirror area; you cannot 367 1.1 christos execute out of the mirror. */ 368 1.1 christos return memory [address & MASK]; 369 1.1 christos } 370 1.1 christos 371 1.1 christos unsigned char 372 1.1 christos mem_get_qi (int address) 373 1.1 christos { 374 1.1 christos int v; 375 1.1 christos v = mem_get_byte (address); 376 1.1 christos if (!SPECIAL_ADDR (address)) 377 1.1 christos tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v); 378 1.1 christos if (last_addr_was_mirror) 379 1.1 christos { 380 1.1 christos pending_clocks += 3; 381 1.1 christos tprintf ("ROM read\n"); 382 1.1 christos } 383 1.1 christos return v; 384 1.1 christos } 385 1.1 christos 386 1.1 christos unsigned short 387 1.1 christos mem_get_hi (int address) 388 1.1 christos { 389 1.1 christos int v; 390 1.1 christos v = mem_get_byte (address) 391 1.1 christos | mem_get_byte (address + 1) * 256; 392 1.1 christos CHECK_ALIGNMENT (address, v, 1); 393 1.1 christos if (!SPECIAL_ADDR (address)) 394 1.1 christos tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v); 395 1.1 christos if (last_addr_was_mirror) 396 1.1 christos { 397 1.1 christos pending_clocks += 3; 398 1.1 christos tprintf ("ROM read\n"); 399 1.1 christos } 400 1.1 christos return v; 401 1.1 christos } 402 1.1 christos 403 1.1 christos unsigned long 404 1.1 christos mem_get_psi (int address) 405 1.1 christos { 406 1.1 christos int v; 407 1.1 christos v = mem_get_byte (address) 408 1.1 christos | mem_get_byte (address + 1) * 256 409 1.1 christos | mem_get_byte (address + 2) * 65536; 410 1.1 christos tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v); 411 1.1 christos return v; 412 1.1 christos } 413 1.1 christos 414 1.1 christos unsigned long 415 1.1 christos mem_get_si (int address) 416 1.1 christos { 417 1.1 christos int v; 418 1.1 christos v = mem_get_byte (address) 419 1.1 christos | mem_get_byte (address + 1) * 256 420 1.1 christos | mem_get_byte (address + 2) * 65536 421 1.1 christos | mem_get_byte (address + 2) * 16777216; 422 1.1 christos CHECK_ALIGNMENT (address, v, 3); 423 1.1 christos tprintf ("(\033[35m[%05X]->%04X)\033[0m", address, v); 424 1.1 christos return v; 425 1.1 christos } 426 1.1 christos 427 1.1 christos void 428 1.1 christos mem_get_blk (int address, void *bufptr, int nbytes) 429 1.1 christos { 430 1.1 christos unsigned char *bp = (unsigned char *)bufptr; 431 1.1 christos while (nbytes --) 432 1.1 christos *bp ++ = mem_get_byte (address ++); 433 1.1 christos } 434 1.1 christos 435 1.1 christos int 436 1.1 christos sign_ext (int v, int bits) 437 1.1 christos { 438 1.1 christos if (bits < 8 * sizeof (int)) 439 1.1 christos { 440 1.1 christos v &= (1 << bits) - 1; 441 1.1 christos if (v & (1 << (bits - 1))) 442 1.1 christos v -= (1 << bits); 443 1.1 christos } 444 1.1 christos return v; 445 1.1 christos } 446