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