Home | History | Annotate | Line # | Download | only in rl78
mem.c revision 1.1.1.7
      1 /* mem.c --- memory for RL78 simulator.
      2 
      3    Copyright (C) 2011-2020 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