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