1 /* mem.c --- memory for RL78 simulator. 2 3 Copyright (C) 2011-2017 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 #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 33 int rom_limit = 0x100000; 34 int ram_base = 0xf8000; 35 unsigned char memory[MEM_SIZE]; 36 #define MASK 0xfffff 37 38 unsigned char initted[MEM_SIZE]; 39 int skip_init = 0; 40 41 #define tprintf if (trace) printf 42 43 void 44 init_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 54 void 55 mem_ram_size (int ram_bytes) 56 { 57 ram_base = 0x100000 - ram_bytes; 58 } 59 60 void 61 mem_rom_size (int rom_bytes) 62 { 63 rom_limit = rom_bytes; 64 } 65 66 int mirror_rom_base = 0x01000; 67 int mirror_ram_base = 0xf1000; 68 int mirror_length = 0x7000; 69 70 void 71 mem_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 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 93 #define MDBL 0xffff6 94 #define MDBH 0xffff4 95 #define MDCL 0xf00e0 96 #define MDCH 0xf00e2 97 static long long mduc_clock = 0; 98 static int mda_set = 0; 99 #define MDA_SET 15 100 101 static int last_addr_was_mirror; 102 103 static int 104 address_mapping (int address) 105 { 106 address &= MASK; 107 if (address >= mirror_ram_base && address < mirror_ram_base + mirror_length) 108 { 109 address = address - mirror_ram_base + mirror_rom_base; 110 if (memory[RL78_SFR_PMC] & 1) 111 { 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 122 static void 123 mem_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 } 153 154 if (! g13_multiply) 155 return; 156 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); 183 mem_put_hi (MDBL, rvu & 0xffff); 184 mem_put_hi (MDBH, rvu >> 16); 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); 191 mem_put_hi (MDBL, rvs & 0xffff); 192 mem_put_hi (MDBH, rvs >> 16); 193 break; 194 case 0x40: 195 alu = mem_get_hi (MDAL); 196 ahu = mem_get_hi (MDAH); 197 rvu = alu * ahu; 198 mem_put_hi (MDBL, rvu & 0xffff); 199 mem_put_hi (MDBH, rvu >> 16); 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; 210 mem_put_hi (MDBL, rvs & 0xffff); 211 mem_put_hi (MDBH, rvs >> 16); 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 223 extern long long total_clocks; 224 225 static unsigned char 226 mem_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); 249 b = mem_get_hi (MDBL) | (mem_get_hi (MDBH) << 16); 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 297 extern 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 307 void 308 mem_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 315 void 316 mem_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 330 void 331 mem_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 339 void 340 mem_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 350 void 351 mem_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 358 unsigned char 359 mem_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 369 unsigned char 370 mem_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 384 unsigned short 385 mem_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 401 unsigned long 402 mem_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 412 unsigned long 413 mem_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 425 void 426 mem_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 433 int 434 sign_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 } 444