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