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, ®)) 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 ®.address, 235 1.1 christos &attach_space, &attach_address, me); 236 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.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