1 /* mem.c --- memory for RL78 simulator. 2 3 Copyright (C) 2011-2023 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 /* This must come before any other includes. */ 23 #include "defs.h" 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "opcode/rl78.h" 30 #include "mem.h" 31 #include "cpu.h" 32 33 #define ILLEGAL_OPCODE 0xff 34 35 int rom_limit = 0x100000; 36 int ram_base = 0xf8000; 37 unsigned char memory[MEM_SIZE]; 38 #define MASK 0xfffff 39 40 unsigned char initted[MEM_SIZE]; 41 int skip_init = 0; 42 43 #define tprintf if (trace) printf 44 45 void 46 init_mem (void) 47 { 48 memset (memory, ILLEGAL_OPCODE, sizeof (memory)); 49 memset (memory + 0xf0000, 0x33, 0x10000); 50 51 memset (initted, 0, sizeof (initted)); 52 memset (initted + 0xffee0, 1, 0x00120); 53 memset (initted + 0xf0000, 1, 0x01000); 54 } 55 56 void 57 mem_ram_size (int ram_bytes) 58 { 59 ram_base = 0x100000 - ram_bytes; 60 } 61 62 void 63 mem_rom_size (int rom_bytes) 64 { 65 rom_limit = rom_bytes; 66 } 67 68 static int mirror_rom_base = 0x01000; 69 static int mirror_ram_base = 0xf1000; 70 static int mirror_length = 0x7000; 71 72 void 73 mem_set_mirror (int rom_base, int ram_base, int length) 74 { 75 mirror_rom_base = rom_base; 76 mirror_ram_base = ram_base; 77 mirror_length = length; 78 } 79 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 84 few peripherals. */ 85 86 /* This is stdout. We only care about the data byte, not the upper byte. */ 87 #define SDR00 0xfff10 88 #define SSR00 0xf0100 89 #define TS0 0xf01b2 90 91 /* RL78/G13 multiply/divide peripheral. */ 92 #define MDUC 0xf00e8 93 #define MDAL 0xffff0 94 #define MDAH 0xffff2 95 #define MDBL 0xffff6 96 #define MDBH 0xffff4 97 #define MDCL 0xf00e0 98 #define MDCH 0xf00e2 99 static long long mduc_clock = 0; 100 static int mda_set = 0; 101 #define MDA_SET 15 102 103 static int last_addr_was_mirror; 104 105 static int 106 address_mapping (int address) 107 { 108 address &= MASK; 109 if (address >= mirror_ram_base && address < mirror_ram_base + mirror_length) 110 { 111 address = address - mirror_ram_base + mirror_rom_base; 112 if (memory[RL78_SFR_PMC] & 1) 113 { 114 address |= 0x10000; 115 } 116 last_addr_was_mirror = 1; 117 } 118 else 119 last_addr_was_mirror = 0; 120 121 return address; 122 } 123 124 static void 125 mem_put_byte (int address, unsigned char value) 126 { 127 address = address_mapping (address); 128 memory [address] = value; 129 initted [address] = 1; 130 if (address == SDR00) 131 { 132 putchar (value); 133 fflush (stdout); 134 } 135 if (address == TS0) 136 { 137 if (timer_enabled == 2) 138 { 139 total_clocks = 0; 140 pending_clocks = 0; 141 memset (counts_per_insn, 0, sizeof (counts_per_insn)); 142 memory[0xf0180] = 0xff; 143 memory[0xf0181] = 0xff; 144 } 145 if (value & 1) 146 timer_enabled = 1; 147 else 148 timer_enabled = 0; 149 } 150 if (address == RL78_SFR_SP && value & 1) 151 { 152 printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc); 153 value &= ~1; 154 } 155 156 if (! g13_multiply) 157 return; 158 159 if (address == MDUC) 160 { 161 if ((value & 0x81) == 0x81) 162 { 163 /* division */ 164 mduc_clock = total_clocks; 165 } 166 } 167 if ((address & ~3) == MDAL) 168 { 169 mda_set |= (1 << (address & 3)); 170 if (mda_set == MDA_SET) 171 { 172 long als, ahs; 173 unsigned long alu, ahu; 174 long rvs; 175 long mdc; 176 unsigned long rvu; 177 mda_set = 0; 178 switch (memory [MDUC] & 0xc8) 179 { 180 case 0x00: 181 alu = mem_get_hi (MDAL); 182 ahu = mem_get_hi (MDAH); 183 rvu = alu * ahu; 184 tprintf ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu); 185 mem_put_hi (MDBL, rvu & 0xffff); 186 mem_put_hi (MDBH, rvu >> 16); 187 break; 188 case 0x08: 189 als = sign_ext (mem_get_hi (MDAL), 16); 190 ahs = sign_ext (mem_get_hi (MDAH), 16); 191 rvs = als * ahs; 192 tprintf ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs); 193 mem_put_hi (MDBL, rvs & 0xffff); 194 mem_put_hi (MDBH, rvs >> 16); 195 break; 196 case 0x40: 197 alu = mem_get_hi (MDAL); 198 ahu = mem_get_hi (MDAH); 199 rvu = alu * ahu; 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); 204 mdc += (long) rvu; 205 tprintf ("%lu\n", mdc); 206 mem_put_si (MDCL, mdc); 207 break; 208 case 0x48: 209 als = sign_ext (mem_get_hi (MDAL), 16); 210 ahs = sign_ext (mem_get_hi (MDAH), 16); 211 rvs = als * ahs; 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); 217 mdc += rvs; 218 mem_put_si (MDCL, mdc); 219 break; 220 } 221 } 222 } 223 } 224 225 extern long long total_clocks; 226 227 static unsigned char 228 mem_get_byte (int address) 229 { 230 address = address_mapping (address); 231 switch (address) 232 { 233 case SSR00: 234 case SSR00 + 1: 235 return 0x00; 236 case 0xf00f0: 237 return 0; 238 case 0xf0180: 239 case 0xf0181: 240 return memory[address]; 241 242 case MDUC: 243 { 244 unsigned char mduc = memory [MDUC]; 245 if ((mduc & 0x81) == 0x81 246 && total_clocks > mduc_clock + 16) 247 { 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); 252 if (b == 0) 253 { 254 q = ~0; 255 r = ~0; 256 } 257 else 258 { 259 q = a / b; 260 r = a % b; 261 } 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); 265 } 266 return memory[address]; 267 } 268 case MDCL: 269 case MDCL + 1: 270 case MDCH: 271 case MDCH + 1: 272 return memory[address]; 273 } 274 if (address < 0xf1000 && address >= 0xf0000) 275 { 276 #if 1 277 /* Note: comment out this return to trap the invalid access 278 instead of returning an "undefined" value. */ 279 return 0x11; 280 #else 281 fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc); 282 exit (1); 283 #endif 284 } 285 #if 0 286 /* Uncomment this block if you want to trap on reads from unwritten memory. */ 287 if (!skip_init && !initted [address]) 288 { 289 static int uninit_count = 0; 290 fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc); 291 uninit_count ++; 292 if (uninit_count > 5) 293 exit (1); 294 } 295 #endif 296 return memory [address]; 297 } 298 299 extern jmp_buf decode_jmp_buf; 300 #define DO_RETURN(x) longjmp (decode_jmp_buf, x) 301 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 ()); } 305 306 /* ---------------------------------------------------------------------- */ 307 #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00)) 308 309 void 310 mem_put_qi (int address, unsigned char value) 311 { 312 if (!SPECIAL_ADDR (address)) 313 tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value); 314 mem_put_byte (address, value); 315 } 316 317 void 318 mem_put_hi (int address, unsigned short value) 319 { 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) 324 { 325 tprintf ("Word access to 0x%05x!!\n", address); 326 DO_RETURN (RL78_MAKE_HIT_BREAK ()); 327 } 328 mem_put_byte (address, value); 329 mem_put_byte (address + 1, value >> 8); 330 } 331 332 void 333 mem_put_psi (int address, unsigned long value) 334 { 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); 339 } 340 341 void 342 mem_put_si (int address, unsigned long value) 343 { 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); 350 } 351 352 void 353 mem_put_blk (int address, const void *bufptr, int nbytes) 354 { 355 const unsigned char *bp = (unsigned char *)bufptr; 356 while (nbytes --) 357 mem_put_byte (address ++, *bp ++); 358 } 359 360 unsigned char 361 mem_get_pc (int address) 362 { 363 /* Catch obvious problems. */ 364 if (address >= rom_limit && address < 0xf0000) 365 return 0xff; 366 /* This does NOT go through the flash mirror area; you cannot 367 execute out of the mirror. */ 368 return memory [address & MASK]; 369 } 370 371 unsigned char 372 mem_get_qi (int address) 373 { 374 int v; 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) 379 { 380 pending_clocks += 3; 381 tprintf ("ROM read\n"); 382 } 383 return v; 384 } 385 386 unsigned short 387 mem_get_hi (int address) 388 { 389 int v; 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) 396 { 397 pending_clocks += 3; 398 tprintf ("ROM read\n"); 399 } 400 return v; 401 } 402 403 unsigned long 404 mem_get_psi (int address) 405 { 406 int v; 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); 411 return v; 412 } 413 414 unsigned long 415 mem_get_si (int address) 416 { 417 int v; 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); 424 return v; 425 } 426 427 void 428 mem_get_blk (int address, void *bufptr, int nbytes) 429 { 430 unsigned char *bp = (unsigned char *)bufptr; 431 while (nbytes --) 432 *bp ++ = mem_get_byte (address ++); 433 } 434 435 int 436 sign_ext (int v, int bits) 437 { 438 if (bits < 8 * sizeof (int)) 439 { 440 v &= (1 << bits) - 1; 441 if (v & (1 << (bits - 1))) 442 v -= (1 << bits); 443 } 444 return v; 445 } 446