1 /* mem.c --- memory for RL78 simulator. 2 3 Copyright (C) 2011-2014 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 /* ---------------------------------------------------------------------- */ 67 /* Note: the RL78 memory map has a few surprises. For starters, part 68 of the first 64k is mapped to the last 64k, depending on an SFR bit 69 and how much RAM the chip has. This is simulated here, as are a 70 few peripherals. */ 71 72 /* This is stdout. We only care about the data byte, not the upper byte. */ 73 #define SDR00 0xfff10 74 #define SSR00 0xf0100 75 #define TS0 0xf01b2 76 77 /* RL78/G13 multiply/divide peripheral. */ 78 #define MDUC 0xf00e8 79 #define MDAL 0xffff0 80 #define MDAH 0xffff2 81 #define MDBL 0xffff6 82 #define MDBH 0xffff4 83 #define MDCL 0xf00e0 84 #define MDCH 0xf00e2 85 static long long mduc_clock = 0; 86 static int mda_set = 0; 87 #define MDA_SET 15 88 89 static int last_addr_was_mirror; 90 91 static int 92 address_mapping (int address) 93 { 94 address &= MASK; 95 if (address >= 0xf1000 && address < ram_base) 96 { 97 address &= 0xffff; 98 tprintf ("&"); 99 if (memory[RL78_SFR_PMC] & 1) 100 { 101 tprintf ("|"); 102 address |= 0x10000; 103 } 104 last_addr_was_mirror = 1; 105 } 106 else 107 last_addr_was_mirror = 0; 108 109 return address; 110 } 111 112 static void 113 mem_put_byte (int address, unsigned char value) 114 { 115 address = address_mapping (address); 116 memory [address] = value; 117 initted [address] = 1; 118 if (address == SDR00) 119 { 120 putchar (value); 121 fflush (stdout); 122 } 123 if (address == TS0) 124 { 125 if (timer_enabled == 2) 126 { 127 total_clocks = 0; 128 pending_clocks = 0; 129 memset (counts_per_insn, 0, sizeof (counts_per_insn)); 130 memory[0xf0180] = 0xff; 131 memory[0xf0181] = 0xff; 132 } 133 if (value & 1) 134 timer_enabled = 1; 135 else 136 timer_enabled = 0; 137 } 138 if (address == RL78_SFR_SP && value & 1) 139 { 140 printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc); 141 value &= ~1; 142 } 143 if (address == MDUC) 144 { 145 if ((value & 0x81) == 0x81) 146 { 147 /* division */ 148 mduc_clock = total_clocks; 149 } 150 } 151 if ((address & ~3) == MDAL) 152 { 153 mda_set |= (1 << (address & 3)); 154 if (mda_set == MDA_SET) 155 { 156 long als, ahs; 157 unsigned long alu, ahu; 158 long rvs; 159 long mdc; 160 unsigned long rvu; 161 mda_set = 0; 162 switch (memory [MDUC] & 0xc8) 163 { 164 case 0x00: 165 alu = mem_get_hi (MDAL); 166 ahu = mem_get_hi (MDAH); 167 rvu = alu * ahu; 168 tprintf ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu); 169 mem_put_si (MDBL, rvu); 170 break; 171 case 0x08: 172 als = sign_ext (mem_get_hi (MDAL), 16); 173 ahs = sign_ext (mem_get_hi (MDAH), 16); 174 rvs = als * ahs; 175 tprintf ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs); 176 mem_put_si (MDBL, rvs); 177 break; 178 case 0x40: 179 alu = mem_get_hi (MDAL); 180 ahu = mem_get_hi (MDAH); 181 rvu = alu * ahu; 182 mem_put_si (MDBL, rvu); 183 mdc = mem_get_si (MDCL); 184 tprintf ("MDUC: %lu * %lu + %lu = ", alu, ahu, mdc); 185 mdc += (long) rvu; 186 tprintf ("%lu\n", mdc); 187 mem_put_si (MDCL, mdc); 188 break; 189 case 0x48: 190 als = sign_ext (mem_get_hi (MDAL), 16); 191 ahs = sign_ext (mem_get_hi (MDAH), 16); 192 rvs = als * ahs; 193 mem_put_si (MDBL, rvs); 194 mdc = mem_get_si (MDCL); 195 tprintf ("MDUC: %ld * %ld + %ld = ", als, ahs, mdc); 196 tprintf ("%ld\n", mdc); 197 mdc += rvs; 198 mem_put_si (MDCL, mdc); 199 break; 200 } 201 } 202 } 203 } 204 205 extern long long total_clocks; 206 207 static unsigned char 208 mem_get_byte (int address) 209 { 210 address = address_mapping (address); 211 switch (address) 212 { 213 case SSR00: 214 case SSR00 + 1: 215 return 0x00; 216 case 0xf00f0: 217 return 0; 218 case 0xf0180: 219 case 0xf0181: 220 return memory[address]; 221 222 case MDUC: 223 { 224 unsigned char mduc = memory [MDUC]; 225 if ((mduc & 0x81) == 0x81 226 && total_clocks > mduc_clock + 16) 227 { 228 unsigned long a, b, q, r; 229 memory [MDUC] &= 0xfe; 230 a = mem_get_si (MDAL); 231 b = mem_get_si (MDAL); 232 if (b == 0) 233 { 234 q = ~0; 235 r = ~0; 236 } 237 else 238 { 239 q = a / b; 240 r = a % b; 241 } 242 tprintf ("MDUC: %lu / %lu = q %lu, r %lu\n", a, b, q, r); 243 mem_put_si (MDAL, q); 244 mem_put_si (MDCL, r); 245 } 246 return memory[address]; 247 } 248 case MDCL: 249 case MDCL + 1: 250 case MDCH: 251 case MDCH + 1: 252 return memory[address]; 253 } 254 if (address < 0xf1000 && address >= 0xf0000) 255 { 256 #if 1 257 /* Note: comment out this return to trap the invalid access 258 instead of returning an "undefined" value. */ 259 return 0x11; 260 #else 261 fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc); 262 exit (1); 263 #endif 264 } 265 #if 0 266 /* Uncomment this block if you want to trap on reads from unwritten memory. */ 267 if (!skip_init && !initted [address]) 268 { 269 static int uninit_count = 0; 270 fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc); 271 uninit_count ++; 272 if (uninit_count > 5) 273 exit (1); 274 } 275 #endif 276 return memory [address]; 277 } 278 279 extern jmp_buf decode_jmp_buf; 280 #define DO_RETURN(x) longjmp (decode_jmp_buf, x) 281 282 #define CHECK_ALIGNMENT(a,v,m) \ 283 if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \ 284 DO_RETURN (RL78_MAKE_HIT_BREAK ()); } 285 286 /* ---------------------------------------------------------------------- */ 287 #define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00)) 288 289 void 290 mem_put_qi (int address, unsigned char value) 291 { 292 if (!SPECIAL_ADDR (address)) 293 tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value); 294 mem_put_byte (address, value); 295 } 296 297 void 298 mem_put_hi (int address, unsigned short value) 299 { 300 if (!SPECIAL_ADDR (address)) 301 tprintf ("\033[34m([%05X]<-%04X)\033[0m", address, value); 302 CHECK_ALIGNMENT (address, value, 1); 303 if (address > 0xffff8 && address != RL78_SFR_SP) 304 { 305 tprintf ("Word access to 0x%05x!!\n", address); 306 DO_RETURN (RL78_MAKE_HIT_BREAK ()); 307 } 308 mem_put_byte (address, value); 309 mem_put_byte (address + 1, value >> 8); 310 } 311 312 void 313 mem_put_psi (int address, unsigned long value) 314 { 315 tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address, value); 316 mem_put_byte (address, value); 317 mem_put_byte (address + 1, value >> 8); 318 mem_put_byte (address + 2, value >> 16); 319 } 320 321 void 322 mem_put_si (int address, unsigned long value) 323 { 324 tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address, value); 325 CHECK_ALIGNMENT (address, value, 3); 326 mem_put_byte (address, value); 327 mem_put_byte (address + 1, value >> 8); 328 mem_put_byte (address + 2, value >> 16); 329 mem_put_byte (address + 3, value >> 24); 330 } 331 332 void 333 mem_put_blk (int address, const void *bufptr, int nbytes) 334 { 335 const unsigned char *bp = (unsigned char *)bufptr; 336 while (nbytes --) 337 mem_put_byte (address ++, *bp ++); 338 } 339 340 unsigned char 341 mem_get_pc (int address) 342 { 343 /* Catch obvious problems. */ 344 if (address >= rom_limit && address < 0xf0000) 345 return 0xff; 346 /* This does NOT go through the flash mirror area; you cannot 347 execute out of the mirror. */ 348 return memory [address & MASK]; 349 } 350 351 unsigned char 352 mem_get_qi (int address) 353 { 354 int v; 355 v = mem_get_byte (address); 356 if (!SPECIAL_ADDR (address)) 357 tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v); 358 if (last_addr_was_mirror) 359 { 360 pending_clocks += 3; 361 tprintf ("ROM read\n"); 362 } 363 return v; 364 } 365 366 unsigned short 367 mem_get_hi (int address) 368 { 369 int v; 370 v = mem_get_byte (address) 371 | mem_get_byte (address + 1) * 256; 372 CHECK_ALIGNMENT (address, v, 1); 373 if (!SPECIAL_ADDR (address)) 374 tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v); 375 if (last_addr_was_mirror) 376 { 377 pending_clocks += 3; 378 tprintf ("ROM read\n"); 379 } 380 return v; 381 } 382 383 unsigned long 384 mem_get_psi (int address) 385 { 386 int v; 387 v = mem_get_byte (address) 388 | mem_get_byte (address + 1) * 256 389 | mem_get_byte (address + 2) * 65536; 390 tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v); 391 return v; 392 } 393 394 unsigned long 395 mem_get_si (int address) 396 { 397 int v; 398 v = mem_get_byte (address) 399 | mem_get_byte (address + 1) * 256 400 | mem_get_byte (address + 2) * 65536 401 | mem_get_byte (address + 2) * 16777216; 402 CHECK_ALIGNMENT (address, v, 3); 403 tprintf ("(\033[35m[%05X]->%04X)\033[0m", address, v); 404 return v; 405 } 406 407 void 408 mem_get_blk (int address, void *bufptr, int nbytes) 409 { 410 unsigned char *bp = (unsigned char *)bufptr; 411 while (nbytes --) 412 *bp ++ = mem_get_byte (address ++); 413 } 414 415 int 416 sign_ext (int v, int bits) 417 { 418 if (bits < 8 * sizeof (int)) 419 { 420 v &= (1 << bits) - 1; 421 if (v & (1 << (bits - 1))) 422 v -= (1 << bits); 423 } 424 return v; 425 } 426