Home | History | Annotate | Line # | Download | only in bfin
      1   1.1  christos /* Blackfin Memory Management Unit (MMU) model.
      2   1.1  christos 
      3  1.11  christos    Copyright (C) 2010-2024 Free Software Foundation, Inc.
      4   1.1  christos    Contributed by Analog Devices, Inc.
      5   1.1  christos 
      6   1.1  christos    This file is part of 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.10  christos /* This must come before any other includes.  */
     22  1.10  christos #include "defs.h"
     23   1.1  christos 
     24   1.1  christos #include "sim-main.h"
     25   1.1  christos #include "sim-options.h"
     26   1.1  christos #include "devices.h"
     27   1.1  christos #include "dv-bfin_mmu.h"
     28   1.1  christos #include "dv-bfin_cec.h"
     29   1.1  christos 
     30   1.1  christos /* XXX: Should this really be two blocks of registers ?  PRM describes
     31   1.1  christos         these as two Content Addressable Memory (CAM) blocks.  */
     32   1.1  christos 
     33   1.1  christos struct bfin_mmu
     34   1.1  christos {
     35   1.1  christos   bu32 base;
     36   1.1  christos 
     37   1.1  christos   /* Order after here is important -- matches hardware MMR layout.  */
     38   1.1  christos   bu32 sram_base_address;
     39   1.1  christos 
     40   1.1  christos   bu32 dmem_control, dcplb_fault_status, dcplb_fault_addr;
     41   1.1  christos   char _dpad0[0x100 - 0x0 - (4 * 4)];
     42   1.1  christos   bu32 dcplb_addr[16];
     43   1.1  christos   char _dpad1[0x200 - 0x100 - (4 * 16)];
     44   1.1  christos   bu32 dcplb_data[16];
     45   1.1  christos   char _dpad2[0x300 - 0x200 - (4 * 16)];
     46   1.1  christos   bu32 dtest_command;
     47   1.1  christos   char _dpad3[0x400 - 0x300 - (4 * 1)];
     48   1.1  christos   bu32 dtest_data[2];
     49   1.1  christos 
     50   1.1  christos   char _dpad4[0x1000 - 0x400 - (4 * 2)];
     51   1.1  christos 
     52   1.1  christos   bu32 idk;	/* Filler MMR; hardware simply ignores.  */
     53   1.1  christos   bu32 imem_control, icplb_fault_status, icplb_fault_addr;
     54   1.1  christos   char _ipad0[0x100 - 0x0 - (4 * 4)];
     55   1.1  christos   bu32 icplb_addr[16];
     56   1.1  christos   char _ipad1[0x200 - 0x100 - (4 * 16)];
     57   1.1  christos   bu32 icplb_data[16];
     58   1.1  christos   char _ipad2[0x300 - 0x200 - (4 * 16)];
     59   1.1  christos   bu32 itest_command;
     60   1.1  christos   char _ipad3[0x400 - 0x300 - (4 * 1)];
     61   1.1  christos   bu32 itest_data[2];
     62   1.1  christos };
     63   1.1  christos #define mmr_base()      offsetof(struct bfin_mmu, sram_base_address)
     64   1.1  christos #define mmr_offset(mmr) (offsetof(struct bfin_mmu, mmr) - mmr_base())
     65   1.1  christos #define mmr_idx(mmr)    (mmr_offset (mmr) / 4)
     66   1.1  christos 
     67   1.1  christos static const char * const mmr_names[BFIN_COREMMR_MMU_SIZE / 4] =
     68   1.1  christos {
     69   1.1  christos   "SRAM_BASE_ADDRESS", "DMEM_CONTROL", "DCPLB_FAULT_STATUS", "DCPLB_FAULT_ADDR",
     70   1.1  christos   [mmr_idx (dcplb_addr[0])] = "DCPLB_ADDR0",
     71   1.1  christos   "DCPLB_ADDR1", "DCPLB_ADDR2", "DCPLB_ADDR3", "DCPLB_ADDR4", "DCPLB_ADDR5",
     72   1.1  christos   "DCPLB_ADDR6", "DCPLB_ADDR7", "DCPLB_ADDR8", "DCPLB_ADDR9", "DCPLB_ADDR10",
     73   1.1  christos   "DCPLB_ADDR11", "DCPLB_ADDR12", "DCPLB_ADDR13", "DCPLB_ADDR14", "DCPLB_ADDR15",
     74   1.1  christos   [mmr_idx (dcplb_data[0])] = "DCPLB_DATA0",
     75   1.1  christos   "DCPLB_DATA1", "DCPLB_DATA2", "DCPLB_DATA3", "DCPLB_DATA4", "DCPLB_DATA5",
     76   1.1  christos   "DCPLB_DATA6", "DCPLB_DATA7", "DCPLB_DATA8", "DCPLB_DATA9", "DCPLB_DATA10",
     77   1.1  christos   "DCPLB_DATA11", "DCPLB_DATA12", "DCPLB_DATA13", "DCPLB_DATA14", "DCPLB_DATA15",
     78   1.1  christos   [mmr_idx (dtest_command)] = "DTEST_COMMAND",
     79   1.1  christos   [mmr_idx (dtest_data[0])] = "DTEST_DATA0", "DTEST_DATA1",
     80   1.1  christos   [mmr_idx (imem_control)] = "IMEM_CONTROL", "ICPLB_FAULT_STATUS", "ICPLB_FAULT_ADDR",
     81   1.1  christos   [mmr_idx (icplb_addr[0])] = "ICPLB_ADDR0",
     82   1.1  christos   "ICPLB_ADDR1", "ICPLB_ADDR2", "ICPLB_ADDR3", "ICPLB_ADDR4", "ICPLB_ADDR5",
     83   1.1  christos   "ICPLB_ADDR6", "ICPLB_ADDR7", "ICPLB_ADDR8", "ICPLB_ADDR9", "ICPLB_ADDR10",
     84   1.1  christos   "ICPLB_ADDR11", "ICPLB_ADDR12", "ICPLB_ADDR13", "ICPLB_ADDR14", "ICPLB_ADDR15",
     85   1.1  christos   [mmr_idx (icplb_data[0])] = "ICPLB_DATA0",
     86   1.1  christos   "ICPLB_DATA1", "ICPLB_DATA2", "ICPLB_DATA3", "ICPLB_DATA4", "ICPLB_DATA5",
     87   1.1  christos   "ICPLB_DATA6", "ICPLB_DATA7", "ICPLB_DATA8", "ICPLB_DATA9", "ICPLB_DATA10",
     88   1.1  christos   "ICPLB_DATA11", "ICPLB_DATA12", "ICPLB_DATA13", "ICPLB_DATA14", "ICPLB_DATA15",
     89   1.1  christos   [mmr_idx (itest_command)] = "ITEST_COMMAND",
     90   1.1  christos   [mmr_idx (itest_data[0])] = "ITEST_DATA0", "ITEST_DATA1",
     91   1.1  christos };
     92   1.1  christos #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
     93   1.1  christos 
     94   1.1  christos static bool bfin_mmu_skip_cplbs = false;
     95   1.1  christos 
     96   1.1  christos static unsigned
     97   1.1  christos bfin_mmu_io_write_buffer (struct hw *me, const void *source,
     98   1.1  christos 			  int space, address_word addr, unsigned nr_bytes)
     99   1.1  christos {
    100   1.1  christos   struct bfin_mmu *mmu = hw_data (me);
    101   1.1  christos   bu32 mmr_off;
    102   1.1  christos   bu32 value;
    103   1.1  christos   bu32 *valuep;
    104   1.1  christos 
    105   1.6  christos   /* Invalid access mode is higher priority than missing register.  */
    106   1.6  christos   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
    107   1.6  christos     return 0;
    108   1.6  christos 
    109   1.1  christos   value = dv_load_4 (source);
    110   1.1  christos 
    111   1.1  christos   mmr_off = addr - mmu->base;
    112  1.10  christos   valuep = (void *)((uintptr_t)mmu + mmr_base() + mmr_off);
    113   1.1  christos 
    114   1.1  christos   HW_TRACE_WRITE ();
    115   1.1  christos 
    116   1.1  christos   switch (mmr_off)
    117   1.1  christos     {
    118   1.1  christos     case mmr_offset(dmem_control):
    119   1.1  christos     case mmr_offset(imem_control):
    120   1.1  christos       /* XXX: IMC/DMC bit should add/remove L1 cache regions ...  */
    121   1.1  christos     case mmr_offset(dtest_data[0]) ... mmr_offset(dtest_data[1]):
    122   1.1  christos     case mmr_offset(itest_data[0]) ... mmr_offset(itest_data[1]):
    123   1.1  christos     case mmr_offset(dcplb_addr[0]) ... mmr_offset(dcplb_addr[15]):
    124   1.1  christos     case mmr_offset(dcplb_data[0]) ... mmr_offset(dcplb_data[15]):
    125   1.1  christos     case mmr_offset(icplb_addr[0]) ... mmr_offset(icplb_addr[15]):
    126   1.1  christos     case mmr_offset(icplb_data[0]) ... mmr_offset(icplb_data[15]):
    127   1.1  christos       *valuep = value;
    128   1.1  christos       break;
    129   1.1  christos     case mmr_offset(sram_base_address):
    130   1.1  christos     case mmr_offset(dcplb_fault_status):
    131   1.1  christos     case mmr_offset(dcplb_fault_addr):
    132   1.1  christos     case mmr_offset(idk):
    133   1.1  christos     case mmr_offset(icplb_fault_status):
    134   1.1  christos     case mmr_offset(icplb_fault_addr):
    135   1.1  christos       /* Discard writes to these.  */
    136   1.1  christos       break;
    137   1.1  christos     case mmr_offset(itest_command):
    138   1.1  christos       /* XXX: Not supported atm.  */
    139   1.1  christos       if (value)
    140   1.1  christos 	hw_abort (me, "ITEST_COMMAND unimplemented");
    141   1.1  christos       break;
    142   1.1  christos     case mmr_offset(dtest_command):
    143   1.1  christos       /* Access L1 memory indirectly.  */
    144   1.1  christos       *valuep = value;
    145   1.1  christos       if (value)
    146   1.1  christos 	{
    147  1.11  christos 	  bu32 sram_addr = mmu->sram_base_address   |
    148   1.1  christos 	    ((value >> (26 - 11)) & (1 << 11)) | /* addr bit 11 (Way0/Way1)   */
    149   1.1  christos 	    ((value >> (24 - 21)) & (1 << 21)) | /* addr bit 21 (Data/Inst)   */
    150   1.1  christos 	    ((value >> (23 - 15)) & (1 << 15)) | /* addr bit 15 (Data Bank)   */
    151   1.1  christos 	    ((value >> (16 - 12)) & (3 << 12)) | /* addr bits 13:12 (Subbank) */
    152   1.1  christos 	    (value & 0x47F8);                    /* addr bits 14 & 10:3       */
    153   1.1  christos 
    154   1.1  christos 	  if (!(value & TEST_DATA_ARRAY))
    155   1.1  christos 	    hw_abort (me, "DTEST_COMMAND tag array unimplemented");
    156   1.1  christos 	  if (value & 0xfa7cb801)
    157   1.1  christos 	    hw_abort (me, "DTEST_COMMAND bits undefined");
    158   1.1  christos 
    159   1.1  christos 	  if (value & TEST_WRITE)
    160  1.11  christos 	    sim_write (hw_system (me), sram_addr, mmu->dtest_data, 8);
    161   1.1  christos 	  else
    162  1.11  christos 	    sim_read (hw_system (me), sram_addr, mmu->dtest_data, 8);
    163   1.1  christos 	}
    164   1.1  christos       break;
    165   1.1  christos     default:
    166   1.1  christos       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    167   1.6  christos       return 0;
    168   1.1  christos     }
    169   1.1  christos 
    170   1.1  christos   return nr_bytes;
    171   1.1  christos }
    172   1.1  christos 
    173   1.1  christos static unsigned
    174   1.1  christos bfin_mmu_io_read_buffer (struct hw *me, void *dest,
    175   1.1  christos 			 int space, address_word addr, unsigned nr_bytes)
    176   1.1  christos {
    177   1.1  christos   struct bfin_mmu *mmu = hw_data (me);
    178   1.1  christos   bu32 mmr_off;
    179   1.1  christos   bu32 *valuep;
    180   1.1  christos 
    181   1.6  christos   /* Invalid access mode is higher priority than missing register.  */
    182   1.6  christos   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, false))
    183   1.6  christos     return 0;
    184   1.6  christos 
    185   1.1  christos   mmr_off = addr - mmu->base;
    186  1.10  christos   valuep = (void *)((uintptr_t)mmu + mmr_base() + mmr_off);
    187   1.1  christos 
    188   1.1  christos   HW_TRACE_READ ();
    189   1.1  christos 
    190   1.1  christos   switch (mmr_off)
    191   1.1  christos     {
    192   1.1  christos     case mmr_offset(dmem_control):
    193   1.1  christos     case mmr_offset(imem_control):
    194   1.1  christos     case mmr_offset(dtest_command):
    195   1.1  christos     case mmr_offset(dtest_data[0]) ... mmr_offset(dtest_data[2]):
    196   1.1  christos     case mmr_offset(itest_command):
    197   1.1  christos     case mmr_offset(itest_data[0]) ... mmr_offset(itest_data[2]):
    198   1.1  christos       /* XXX: should do something here.  */
    199   1.1  christos     case mmr_offset(dcplb_addr[0]) ... mmr_offset(dcplb_addr[15]):
    200   1.1  christos     case mmr_offset(dcplb_data[0]) ... mmr_offset(dcplb_data[15]):
    201   1.1  christos     case mmr_offset(icplb_addr[0]) ... mmr_offset(icplb_addr[15]):
    202   1.1  christos     case mmr_offset(icplb_data[0]) ... mmr_offset(icplb_data[15]):
    203   1.1  christos     case mmr_offset(sram_base_address):
    204   1.1  christos     case mmr_offset(dcplb_fault_status):
    205   1.1  christos     case mmr_offset(dcplb_fault_addr):
    206   1.1  christos     case mmr_offset(idk):
    207   1.1  christos     case mmr_offset(icplb_fault_status):
    208   1.1  christos     case mmr_offset(icplb_fault_addr):
    209   1.1  christos       dv_store_4 (dest, *valuep);
    210   1.1  christos       break;
    211   1.1  christos     default:
    212   1.6  christos       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    213   1.6  christos       return 0;
    214   1.1  christos     }
    215   1.1  christos 
    216   1.1  christos   return nr_bytes;
    217   1.1  christos }
    218   1.1  christos 
    219   1.1  christos static void
    220   1.1  christos attach_bfin_mmu_regs (struct hw *me, struct bfin_mmu *mmu)
    221   1.1  christos {
    222   1.1  christos   address_word attach_address;
    223   1.1  christos   int attach_space;
    224   1.1  christos   unsigned attach_size;
    225   1.1  christos   reg_property_spec reg;
    226   1.1  christos 
    227   1.1  christos   if (hw_find_property (me, "reg") == NULL)
    228   1.1  christos     hw_abort (me, "Missing \"reg\" property");
    229   1.1  christos 
    230   1.1  christos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    231   1.1  christos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    232   1.1  christos 
    233   1.1  christos   hw_unit_address_to_attach_address (hw_parent (me),
    234   1.1  christos 				     &reg.address,
    235   1.1  christos 				     &attach_space, &attach_address, me);
    236   1.1  christos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    237   1.1  christos 
    238   1.1  christos   if (attach_size != BFIN_COREMMR_MMU_SIZE)
    239   1.1  christos     hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_MMU_SIZE);
    240   1.1  christos 
    241   1.1  christos   hw_attach_address (hw_parent (me),
    242   1.1  christos 		     0, attach_space, attach_address, attach_size, me);
    243   1.1  christos 
    244   1.1  christos   mmu->base = attach_address;
    245   1.1  christos }
    246   1.1  christos 
    247   1.1  christos static void
    248   1.1  christos bfin_mmu_finish (struct hw *me)
    249   1.1  christos {
    250   1.1  christos   struct bfin_mmu *mmu;
    251   1.1  christos 
    252   1.1  christos   mmu = HW_ZALLOC (me, struct bfin_mmu);
    253   1.1  christos 
    254   1.1  christos   set_hw_data (me, mmu);
    255   1.1  christos   set_hw_io_read_buffer (me, bfin_mmu_io_read_buffer);
    256   1.1  christos   set_hw_io_write_buffer (me, bfin_mmu_io_write_buffer);
    257   1.1  christos 
    258   1.1  christos   attach_bfin_mmu_regs (me, mmu);
    259   1.1  christos 
    260   1.1  christos   /* Initialize the MMU.  */
    261   1.1  christos   mmu->sram_base_address = 0xff800000 - 0;
    262   1.1  christos 			   /*(4 * 1024 * 1024 * CPU_INDEX (hw_system_cpu (me)));*/
    263   1.1  christos   mmu->dmem_control = 0x00000001;
    264   1.1  christos   mmu->imem_control = 0x00000001;
    265   1.1  christos }
    266   1.1  christos 
    267   1.1  christos const struct hw_descriptor dv_bfin_mmu_descriptor[] =
    268   1.1  christos {
    269   1.1  christos   {"bfin_mmu", bfin_mmu_finish,},
    270   1.1  christos   {NULL, NULL},
    271   1.1  christos };
    272   1.1  christos 
    273   1.1  christos /* Device option parsing.  */
    275   1.1  christos 
    276   1.1  christos static DECLARE_OPTION_HANDLER (bfin_mmu_option_handler);
    277   1.1  christos 
    278   1.1  christos enum {
    279   1.1  christos   OPTION_MMU_SKIP_TABLES = OPTION_START,
    280   1.1  christos };
    281  1.10  christos 
    282   1.1  christos static const OPTION bfin_mmu_options[] =
    283   1.1  christos {
    284   1.1  christos   { {"mmu-skip-cplbs", no_argument, NULL, OPTION_MMU_SKIP_TABLES },
    285   1.1  christos       '\0', NULL, "Skip parsing of CPLB tables (big speed increase)",
    286   1.1  christos       bfin_mmu_option_handler, NULL },
    287   1.1  christos 
    288   1.1  christos   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
    289   1.1  christos };
    290   1.1  christos 
    291   1.1  christos static SIM_RC
    292   1.1  christos bfin_mmu_option_handler (SIM_DESC sd, sim_cpu *current_cpu, int opt,
    293   1.1  christos 			 char *arg, int is_command)
    294   1.1  christos {
    295   1.1  christos   switch (opt)
    296   1.1  christos     {
    297   1.1  christos     case OPTION_MMU_SKIP_TABLES:
    298   1.1  christos       bfin_mmu_skip_cplbs = true;
    299   1.1  christos       return SIM_RC_OK;
    300   1.1  christos 
    301   1.1  christos     default:
    302   1.1  christos       sim_io_eprintf (sd, "Unknown Blackfin MMU option %d\n", opt);
    303   1.1  christos       return SIM_RC_FAIL;
    304   1.1  christos     }
    305  1.10  christos }
    306  1.10  christos 
    307  1.10  christos /* Provide a prototype to silence -Wmissing-prototypes.  */
    308  1.10  christos extern MODULE_INIT_FN sim_install_bfin_mmu;
    309  1.10  christos 
    310  1.10  christos SIM_RC
    311  1.10  christos sim_install_bfin_mmu (SIM_DESC sd)
    312  1.10  christos {
    313  1.10  christos   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
    314  1.10  christos   return sim_add_option_table (sd, NULL, bfin_mmu_options);
    315   1.1  christos }
    316   1.1  christos 
    317   1.1  christos #define MMU_STATE(cpu) DV_STATE_CACHED (cpu, mmu)
    319   1.1  christos 
    320   1.1  christos static void
    321   1.1  christos _mmu_log_ifault (SIM_CPU *cpu, struct bfin_mmu *mmu, bu32 pc, bool supv)
    322   1.1  christos {
    323   1.1  christos   mmu->icplb_fault_addr = pc;
    324   1.1  christos   mmu->icplb_fault_status = supv << 17;
    325   1.1  christos }
    326   1.1  christos 
    327   1.1  christos void
    328   1.1  christos mmu_log_ifault (SIM_CPU *cpu)
    329   1.1  christos {
    330   1.1  christos   _mmu_log_ifault (cpu, MMU_STATE (cpu), PCREG, cec_get_ivg (cpu) >= 0);
    331   1.1  christos }
    332   1.1  christos 
    333   1.1  christos static void
    334   1.1  christos _mmu_log_fault (SIM_CPU *cpu, struct bfin_mmu *mmu, bu32 addr, bool write,
    335   1.1  christos 		bool inst, bool miss, bool supv, bool dag1, bu32 faults)
    336   1.1  christos {
    337   1.1  christos   bu32 *fault_status, *fault_addr;
    338   1.1  christos 
    339   1.1  christos   /* No logging in non-OS mode.  */
    340   1.1  christos   if (!mmu)
    341   1.1  christos     return;
    342   1.1  christos 
    343   1.1  christos   fault_status = inst ? &mmu->icplb_fault_status : &mmu->dcplb_fault_status;
    344   1.1  christos   fault_addr = inst ? &mmu->icplb_fault_addr : &mmu->dcplb_fault_addr;
    345   1.1  christos   /* ICPLB regs always get updated.  */
    346   1.1  christos   if (!inst)
    347   1.1  christos     _mmu_log_ifault (cpu, mmu, PCREG, supv);
    348   1.1  christos 
    349   1.1  christos   *fault_addr = addr;
    350   1.1  christos   *fault_status =
    351   1.1  christos 	(miss << 19) |
    352   1.1  christos 	(dag1 << 18) |
    353   1.1  christos 	(supv << 17) |
    354   1.1  christos 	(write << 16) |
    355   1.1  christos 	faults;
    356   1.1  christos }
    357   1.1  christos 
    358   1.1  christos static void
    359   1.1  christos _mmu_process_fault (SIM_CPU *cpu, struct bfin_mmu *mmu, bu32 addr, bool write,
    360   1.1  christos 		    bool inst, bool unaligned, bool miss, bool supv, bool dag1)
    361   1.1  christos {
    362   1.1  christos   int excp;
    363   1.1  christos 
    364   1.1  christos   /* See order in mmu_check_addr() */
    365   1.1  christos   if (unaligned)
    366   1.1  christos     excp = inst ? VEC_MISALI_I : VEC_MISALI_D;
    367   1.1  christos   else if (addr >= BFIN_SYSTEM_MMR_BASE)
    368   1.1  christos     excp = VEC_ILL_RES;
    369   1.1  christos   else if (!mmu)
    370   1.1  christos     excp = inst ? VEC_CPLB_I_M : VEC_CPLB_M;
    371   1.1  christos   else
    372   1.1  christos     {
    373   1.1  christos       /* Misses are hardware errors.  */
    374   1.1  christos       cec_hwerr (cpu, HWERR_EXTERN_ADDR);
    375   1.1  christos       return;
    376   1.1  christos     }
    377   1.1  christos 
    378   1.1  christos   _mmu_log_fault (cpu, mmu, addr, write, inst, miss, supv, dag1, 0);
    379   1.1  christos   cec_exception (cpu, excp);
    380   1.1  christos }
    381   1.1  christos 
    382   1.1  christos void
    383   1.1  christos mmu_process_fault (SIM_CPU *cpu, bu32 addr, bool write, bool inst,
    384   1.1  christos 		   bool unaligned, bool miss)
    385   1.1  christos {
    386   1.1  christos   SIM_DESC sd = CPU_STATE (cpu);
    387   1.1  christos   struct bfin_mmu *mmu;
    388   1.1  christos 
    389   1.1  christos   if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
    390   1.1  christos     mmu = NULL;
    391   1.1  christos   else
    392   1.1  christos     mmu = MMU_STATE (cpu);
    393   1.1  christos 
    394   1.1  christos   _mmu_process_fault (cpu, mmu, addr, write, inst, unaligned, miss,
    395   1.1  christos 		      cec_is_supervisor_mode (cpu),
    396   1.1  christos 		      BFIN_CPU_STATE.multi_pc == PCREG + 6);
    397   1.1  christos }
    398   1.1  christos 
    399   1.1  christos /* Return values:
    400   1.1  christos     -2: no known problems
    401   1.1  christos     -1: valid
    402   1.1  christos      0: miss
    403   1.1  christos      1: protection violation
    404   1.1  christos      2: multiple hits
    405   1.1  christos      3: unaligned
    406   1.1  christos      4: miss; hwerr  */
    407   1.1  christos static int
    408   1.1  christos mmu_check_implicit_addr (SIM_CPU *cpu, bu32 addr, bool inst, int size,
    409   1.1  christos 			 bool supv, bool dag1)
    410   1.1  christos {
    411   1.1  christos   bool l1 = ((addr & 0xFF000000) == 0xFF000000);
    412   1.1  christos   bu32 amask = (addr & 0xFFF00000);
    413   1.1  christos 
    414   1.1  christos   if (addr & (size - 1))
    415   1.1  christos     return 3;
    416   1.1  christos 
    417   1.1  christos   /* MMRs may never be executable or accessed from usermode.  */
    418   1.1  christos   if (addr >= BFIN_SYSTEM_MMR_BASE)
    419   1.1  christos     {
    420   1.1  christos       if (inst)
    421   1.1  christos 	return 0;
    422   1.1  christos       else if (!supv || dag1)
    423   1.1  christos 	return 1;
    424   1.1  christos       else
    425   1.1  christos 	return -1;
    426   1.1  christos     }
    427   1.1  christos   else if (inst)
    428   1.1  christos     {
    429   1.1  christos       /* Some regions are not executable.  */
    430   1.1  christos       /* XXX: Should this be in the model data ?  Core B 561 ?  */
    431   1.1  christos       if (l1)
    432   1.1  christos 	return (amask == 0xFFA00000) ? -1 : 1;
    433   1.1  christos     }
    434   1.1  christos   else
    435   1.1  christos     {
    436   1.1  christos       /* Some regions are not readable.  */
    437   1.1  christos       /* XXX: Should this be in the model data ?  Core B 561 ?  */
    438   1.1  christos       if (l1)
    439   1.1  christos 	return (amask != 0xFFA00000) ? -1 : 4;
    440   1.1  christos     }
    441   1.1  christos 
    442   1.1  christos   return -2;
    443   1.1  christos }
    444   1.1  christos 
    445   1.1  christos /* Exception order per the PRM (first has highest):
    446   1.1  christos      Inst Multiple CPLB Hits
    447   1.1  christos      Inst Misaligned Access
    448   1.1  christos      Inst Protection Violation
    449   1.1  christos      Inst CPLB Miss
    450   1.1  christos   Only the alignment matters in non-OS mode though.  */
    451   1.1  christos static int
    452   1.1  christos _mmu_check_addr (SIM_CPU *cpu, bu32 addr, bool write, bool inst, int size)
    453   1.1  christos {
    454  1.11  christos   SIM_DESC sd = CPU_STATE (cpu);
    455   1.1  christos   struct bfin_mmu *mmu;
    456   1.1  christos   bu32 *mem_control, *cplb_addr, *cplb_data;
    457   1.1  christos   bu32 faults;
    458   1.1  christos   bool supv, do_excp, dag1;
    459   1.1  christos   int i, hits;
    460   1.1  christos 
    461   1.1  christos   supv = cec_is_supervisor_mode (cpu);
    462   1.1  christos   dag1 = (BFIN_CPU_STATE.multi_pc == PCREG + 6);
    463   1.1  christos 
    464   1.1  christos   if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT || bfin_mmu_skip_cplbs)
    465   1.1  christos     {
    466   1.1  christos       int ret = mmu_check_implicit_addr (cpu, addr, inst, size, supv, dag1);
    467   1.1  christos       /* Valid hits and misses are OK in non-OS envs.  */
    468   1.1  christos       if (ret < 0)
    469   1.1  christos 	return 0;
    470   1.1  christos       _mmu_process_fault (cpu, NULL, addr, write, inst, (ret == 3), false, supv, dag1);
    471   1.1  christos     }
    472   1.1  christos 
    473   1.1  christos   mmu = MMU_STATE (cpu);
    474   1.1  christos   mem_control = inst ? &mmu->imem_control : &mmu->dmem_control;
    475   1.1  christos   cplb_addr = inst ? &mmu->icplb_addr[0] : &mmu->dcplb_addr[0];
    476   1.1  christos   cplb_data = inst ? &mmu->icplb_data[0] : &mmu->dcplb_data[0];
    477   1.1  christos 
    478   1.1  christos   faults = 0;
    479   1.1  christos   hits = 0;
    480   1.1  christos   do_excp = false;
    481   1.1  christos 
    482   1.1  christos   /* CPLBs disabled -> little to do.  */
    483   1.1  christos   if (!(*mem_control & ENCPLB))
    484   1.1  christos     {
    485   1.1  christos       hits = 1;
    486   1.1  christos       goto implicit_check;
    487   1.1  christos     }
    488   1.1  christos 
    489   1.1  christos   /* Check all the CPLBs first.  */
    490   1.1  christos   for (i = 0; i < 16; ++i)
    491   1.1  christos     {
    492   1.1  christos       const bu32 pages[4] = { 0x400, 0x1000, 0x100000, 0x400000 };
    493   1.1  christos       bu32 addr_lo, addr_hi;
    494   1.1  christos 
    495   1.1  christos       /* Skip invalid entries.  */
    496   1.1  christos       if (!(cplb_data[i] & CPLB_VALID))
    497   1.1  christos 	continue;
    498   1.1  christos 
    499   1.1  christos       /* See if this entry covers this address.  */
    500   1.1  christos       addr_lo = cplb_addr[i];
    501   1.1  christos       addr_hi = cplb_addr[i] + pages[(cplb_data[i] & PAGE_SIZE) >> 16];
    502   1.1  christos       if (addr < addr_lo || addr >= addr_hi)
    503   1.1  christos 	continue;
    504   1.1  christos 
    505   1.1  christos       ++hits;
    506   1.1  christos       faults |= (1 << i);
    507   1.1  christos       if (write)
    508   1.1  christos 	{
    509   1.1  christos 	  if (!supv && !(cplb_data[i] & CPLB_USER_WR))
    510   1.1  christos 	    do_excp = true;
    511   1.1  christos 	  if (supv && !(cplb_data[i] & CPLB_SUPV_WR))
    512   1.1  christos 	    do_excp = true;
    513   1.1  christos 	  if ((cplb_data[i] & (CPLB_WT | CPLB_L1_CHBL | CPLB_DIRTY)) == CPLB_L1_CHBL)
    514   1.1  christos 	    do_excp = true;
    515   1.1  christos 	}
    516   1.1  christos       else
    517   1.1  christos 	{
    518   1.1  christos 	  if (!supv && !(cplb_data[i] & CPLB_USER_RD))
    519   1.1  christos 	    do_excp = true;
    520   1.1  christos 	}
    521   1.1  christos     }
    522   1.1  christos 
    523   1.1  christos   /* Handle default/implicit CPLBs.  */
    524   1.1  christos   if (!do_excp && hits < 2)
    525   1.1  christos     {
    526   1.1  christos       int ihits;
    527   1.1  christos  implicit_check:
    528   1.1  christos       ihits = mmu_check_implicit_addr (cpu, addr, inst, size, supv, dag1);
    529   1.1  christos       switch (ihits)
    530   1.1  christos 	{
    531   1.1  christos 	/* No faults and one match -> good to go.  */
    532   1.1  christos 	case -1: return 0;
    533   1.1  christos 	case -2:
    534   1.1  christos 	  if (hits == 1)
    535   1.1  christos 	    return 0;
    536   1.1  christos 	  break;
    537   1.1  christos 	case 4:
    538   1.1  christos 	  cec_hwerr (cpu, HWERR_EXTERN_ADDR);
    539   1.1  christos 	  return 0;
    540   1.1  christos 	default:
    541   1.1  christos 	  hits = ihits;
    542   1.1  christos 	}
    543   1.1  christos     }
    544   1.6  christos   else
    545   1.1  christos     /* Normalize hit count so hits==2 is always multiple hit exception.  */
    546   1.1  christos     hits = min (2, hits);
    547   1.1  christos 
    548   1.1  christos   _mmu_log_fault (cpu, mmu, addr, write, inst, hits == 0, supv, dag1, faults);
    549   1.1  christos 
    550   1.1  christos   if (inst)
    551   1.1  christos     {
    552   1.1  christos       int iexcps[] = { VEC_CPLB_I_M, VEC_CPLB_I_VL, VEC_CPLB_I_MHIT, VEC_MISALI_I };
    553   1.1  christos       return iexcps[hits];
    554   1.1  christos     }
    555   1.1  christos   else
    556   1.1  christos     {
    557   1.1  christos       int dexcps[] = { VEC_CPLB_M, VEC_CPLB_VL, VEC_CPLB_MHIT, VEC_MISALI_D };
    558   1.1  christos       return dexcps[hits];
    559   1.1  christos     }
    560   1.1  christos }
    561   1.1  christos 
    562   1.1  christos void
    563   1.1  christos mmu_check_addr (SIM_CPU *cpu, bu32 addr, bool write, bool inst, int size)
    564   1.1  christos {
    565   1.1  christos   int excp = _mmu_check_addr (cpu, addr, write, inst, size);
    566   1.1  christos   if (excp)
    567   1.1  christos     cec_exception (cpu, excp);
    568   1.1  christos }
    569   1.1  christos 
    570   1.1  christos void
    571   1.1  christos mmu_check_cache_addr (SIM_CPU *cpu, bu32 addr, bool write, bool inst)
    572   1.1  christos {
    573   1.1  christos   bu32 cacheaddr;
    574   1.1  christos   int excp;
    575   1.1  christos 
    576   1.1  christos   cacheaddr = addr & ~(BFIN_L1_CACHE_BYTES - 1);
    577   1.1  christos   excp = _mmu_check_addr (cpu, cacheaddr, write, inst, BFIN_L1_CACHE_BYTES);
    578   1.1  christos   if (excp == 0)
    579   1.1  christos     return;
    580   1.1  christos 
    581   1.1  christos   /* Most exceptions are ignored with cache funcs.  */
    582   1.1  christos   /* XXX: Not sure if we should be ignoring CPLB misses.  */
    583   1.1  christos   if (inst)
    584   1.1  christos     {
    585   1.1  christos       if (excp == VEC_CPLB_I_VL)
    586   1.1  christos 	return;
    587   1.1  christos     }
    588   1.1  christos   else
    589   1.1  christos     {
    590   1.1  christos       if (excp == VEC_CPLB_VL)
    591   1.1  christos 	return;
    592   1.1  christos     }
    593                   cec_exception (cpu, excp);
    594                 }
    595