14e98e3e1Schristos /* frv memory model. 2*2a9ac006Schristos Copyright (C) 1999-2024 Free Software Foundation, Inc. 34e98e3e1Schristos Contributed by Red Hat 44e98e3e1Schristos 54e98e3e1Schristos This file is part of the GNU simulators. 64e98e3e1Schristos 74e98e3e1Schristos This program is free software; you can redistribute it and/or modify 84e98e3e1Schristos it under the terms of the GNU General Public License as published by 94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 104e98e3e1Schristos (at your option) any later version. 114e98e3e1Schristos 124e98e3e1Schristos This program is distributed in the hope that it will be useful, 134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154e98e3e1Schristos GNU General Public License for more details. 164e98e3e1Schristos 174e98e3e1Schristos You should have received a copy of the GNU General Public License 184e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 194e98e3e1Schristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224b169a6bSchristos 234e98e3e1Schristos #define WANT_CPU frvbf 244e98e3e1Schristos #define WANT_CPU_FRVBF 254e98e3e1Schristos 264e98e3e1Schristos #include "sim-main.h" 274e98e3e1Schristos #include "cgen-mem.h" 284e98e3e1Schristos #include "bfd.h" 294b169a6bSchristos #include <stdlib.h> 304e98e3e1Schristos 314e98e3e1Schristos /* Check for alignment and access restrictions. Return the corrected address. 324e98e3e1Schristos */ 334e98e3e1Schristos static SI 344e98e3e1Schristos fr400_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask) 354e98e3e1Schristos { 364e98e3e1Schristos /* Check access restrictions for double word loads only. */ 374e98e3e1Schristos if (align_mask == 7) 384e98e3e1Schristos { 394e98e3e1Schristos if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff) 404e98e3e1Schristos frv_queue_data_access_error_interrupt (current_cpu, address); 414e98e3e1Schristos } 424e98e3e1Schristos return address; 434e98e3e1Schristos } 444e98e3e1Schristos 454e98e3e1Schristos static SI 464e98e3e1Schristos fr500_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask) 474e98e3e1Schristos { 484e98e3e1Schristos if (address & align_mask) 494e98e3e1Schristos { 504e98e3e1Schristos frv_queue_mem_address_not_aligned_interrupt (current_cpu, address); 514e98e3e1Schristos address &= ~align_mask; 524e98e3e1Schristos } 534e98e3e1Schristos 544b169a6bSchristos if (((USI)address >= 0xfeff0600 && (USI)address <= 0xfeff7fff) 554b169a6bSchristos || ((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff)) 564e98e3e1Schristos frv_queue_data_access_error_interrupt (current_cpu, address); 574e98e3e1Schristos 584e98e3e1Schristos return address; 594e98e3e1Schristos } 604e98e3e1Schristos 614e98e3e1Schristos static SI 624e98e3e1Schristos fr550_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask) 634e98e3e1Schristos { 644b169a6bSchristos if (((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff) 654e98e3e1Schristos || (align_mask > 0x3 664e98e3e1Schristos && ((USI)address >= 0xfeff0000 && (USI)address <= 0xfeffffff))) 674e98e3e1Schristos frv_queue_data_access_error_interrupt (current_cpu, address); 684e98e3e1Schristos 694e98e3e1Schristos return address; 704e98e3e1Schristos } 714e98e3e1Schristos 724e98e3e1Schristos static SI 734e98e3e1Schristos check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask) 744e98e3e1Schristos { 754e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 764e98e3e1Schristos switch (STATE_ARCHITECTURE (sd)->mach) 774e98e3e1Schristos { 784e98e3e1Schristos case bfd_mach_fr400: 794e98e3e1Schristos case bfd_mach_fr450: 804e98e3e1Schristos address = fr400_check_data_read_address (current_cpu, address, 814e98e3e1Schristos align_mask); 824e98e3e1Schristos break; 834e98e3e1Schristos case bfd_mach_frvtomcat: 844e98e3e1Schristos case bfd_mach_fr500: 854e98e3e1Schristos case bfd_mach_frv: 864e98e3e1Schristos address = fr500_check_data_read_address (current_cpu, address, 874e98e3e1Schristos align_mask); 884e98e3e1Schristos break; 894e98e3e1Schristos case bfd_mach_fr550: 904e98e3e1Schristos address = fr550_check_data_read_address (current_cpu, address, 914e98e3e1Schristos align_mask); 924e98e3e1Schristos break; 934e98e3e1Schristos default: 944e98e3e1Schristos break; 954e98e3e1Schristos } 964e98e3e1Schristos 974e98e3e1Schristos return address; 984e98e3e1Schristos } 994e98e3e1Schristos 1004e98e3e1Schristos static SI 1014e98e3e1Schristos fr400_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask) 1024e98e3e1Schristos { 1034e98e3e1Schristos if (address & align_mask) 1044e98e3e1Schristos { 1054e98e3e1Schristos /* Make sure that this exception is not masked. */ 1064e98e3e1Schristos USI isr = GET_ISR (); 1074e98e3e1Schristos if (! GET_ISR_EMAM (isr)) 1084e98e3e1Schristos { 1094e98e3e1Schristos /* Bad alignment causes a data_access_error on fr400. */ 1104e98e3e1Schristos frv_queue_data_access_error_interrupt (current_cpu, address); 1114e98e3e1Schristos } 1124e98e3e1Schristos address &= ~align_mask; 1134e98e3e1Schristos } 1144e98e3e1Schristos /* Nothing to check. */ 1154e98e3e1Schristos return address; 1164e98e3e1Schristos } 1174e98e3e1Schristos 1184e98e3e1Schristos static SI 1194e98e3e1Schristos fr500_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask) 1204e98e3e1Schristos { 1214b169a6bSchristos if (((USI)address >= 0xfe000000 && (USI)address <= 0xfe003fff) 1224b169a6bSchristos || ((USI)address >= 0xfe004000 && (USI)address <= 0xfe3fffff) 1234b169a6bSchristos || ((USI)address >= 0xfe400000 && (USI)address <= 0xfe403fff) 1244b169a6bSchristos || ((USI)address >= 0xfe404000 && (USI)address <= 0xfe7fffff)) 1254e98e3e1Schristos frv_queue_data_access_exception_interrupt (current_cpu); 1264e98e3e1Schristos 1274e98e3e1Schristos return address; 1284e98e3e1Schristos } 1294e98e3e1Schristos 1304e98e3e1Schristos static SI 1314e98e3e1Schristos fr550_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask) 1324e98e3e1Schristos { 1334e98e3e1Schristos /* No alignment restrictions on fr550 */ 1344e98e3e1Schristos 1354b169a6bSchristos if (((USI)address >= 0xfe000000 && (USI)address <= 0xfe3fffff) 1364b169a6bSchristos || ((USI)address >= 0xfe408000 && (USI)address <= 0xfe7fffff)) 1374e98e3e1Schristos frv_queue_data_access_exception_interrupt (current_cpu); 1384e98e3e1Schristos else 1394e98e3e1Schristos { 1404e98e3e1Schristos USI hsr0 = GET_HSR0 (); 1414e98e3e1Schristos if (! GET_HSR0_RME (hsr0) 1424b169a6bSchristos && ((USI)address >= 0xfe400000 && (USI)address <= 0xfe407fff)) 1434e98e3e1Schristos frv_queue_data_access_exception_interrupt (current_cpu); 1444e98e3e1Schristos } 1454e98e3e1Schristos 1464e98e3e1Schristos return address; 1474e98e3e1Schristos } 1484e98e3e1Schristos 1494e98e3e1Schristos static SI 1504e98e3e1Schristos check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask) 1514e98e3e1Schristos { 1524e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 1534e98e3e1Schristos switch (STATE_ARCHITECTURE (sd)->mach) 1544e98e3e1Schristos { 1554e98e3e1Schristos case bfd_mach_fr400: 1564e98e3e1Schristos case bfd_mach_fr450: 1574e98e3e1Schristos address = fr400_check_readwrite_address (current_cpu, address, 1584e98e3e1Schristos align_mask); 1594e98e3e1Schristos break; 1604e98e3e1Schristos case bfd_mach_frvtomcat: 1614e98e3e1Schristos case bfd_mach_fr500: 1624e98e3e1Schristos case bfd_mach_frv: 1634e98e3e1Schristos address = fr500_check_readwrite_address (current_cpu, address, 1644e98e3e1Schristos align_mask); 1654e98e3e1Schristos break; 1664e98e3e1Schristos case bfd_mach_fr550: 1674e98e3e1Schristos address = fr550_check_readwrite_address (current_cpu, address, 1684e98e3e1Schristos align_mask); 1694e98e3e1Schristos break; 1704e98e3e1Schristos default: 1714e98e3e1Schristos break; 1724e98e3e1Schristos } 1734e98e3e1Schristos 1744e98e3e1Schristos return address; 1754e98e3e1Schristos } 1764e98e3e1Schristos 1774e98e3e1Schristos static PCADDR 1784e98e3e1Schristos fr400_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address, 1794e98e3e1Schristos int align_mask) 1804e98e3e1Schristos { 1814e98e3e1Schristos if (address & align_mask) 1824e98e3e1Schristos { 1834e98e3e1Schristos frv_queue_instruction_access_error_interrupt (current_cpu); 1844e98e3e1Schristos address &= ~align_mask; 1854e98e3e1Schristos } 1864e98e3e1Schristos else if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff) 1874e98e3e1Schristos frv_queue_instruction_access_error_interrupt (current_cpu); 1884e98e3e1Schristos 1894e98e3e1Schristos return address; 1904e98e3e1Schristos } 1914e98e3e1Schristos 1924e98e3e1Schristos static PCADDR 1934e98e3e1Schristos fr500_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address, 1944e98e3e1Schristos int align_mask) 1954e98e3e1Schristos { 1964e98e3e1Schristos if (address & align_mask) 1974e98e3e1Schristos { 1984e98e3e1Schristos frv_queue_mem_address_not_aligned_interrupt (current_cpu, address); 1994e98e3e1Schristos address &= ~align_mask; 2004e98e3e1Schristos } 2014e98e3e1Schristos 2024b169a6bSchristos if (((USI)address >= 0xfeff0600 && (USI)address <= 0xfeff7fff) 2034b169a6bSchristos || ((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff)) 2044e98e3e1Schristos frv_queue_instruction_access_error_interrupt (current_cpu); 2054b169a6bSchristos else if (((USI)address >= 0xfe004000 && (USI)address <= 0xfe3fffff) 2064b169a6bSchristos || ((USI)address >= 0xfe400000 && (USI)address <= 0xfe403fff) 2074b169a6bSchristos || ((USI)address >= 0xfe404000 && (USI)address <= 0xfe7fffff)) 2084e98e3e1Schristos frv_queue_instruction_access_exception_interrupt (current_cpu); 2094e98e3e1Schristos else 2104e98e3e1Schristos { 2114e98e3e1Schristos USI hsr0 = GET_HSR0 (); 2124e98e3e1Schristos if (! GET_HSR0_RME (hsr0) 2134b169a6bSchristos && ((USI)address >= 0xfe000000 && (USI)address <= 0xfe003fff)) 2144e98e3e1Schristos frv_queue_instruction_access_exception_interrupt (current_cpu); 2154e98e3e1Schristos } 2164e98e3e1Schristos 2174e98e3e1Schristos return address; 2184e98e3e1Schristos } 2194e98e3e1Schristos 2204e98e3e1Schristos static PCADDR 2214e98e3e1Schristos fr550_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address, 2224e98e3e1Schristos int align_mask) 2234e98e3e1Schristos { 2244e98e3e1Schristos address &= ~align_mask; 2254e98e3e1Schristos 2264e98e3e1Schristos if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff) 2274e98e3e1Schristos frv_queue_instruction_access_error_interrupt (current_cpu); 2284e98e3e1Schristos else if ((USI)address >= 0xfe008000 && (USI)address <= 0xfe7fffff) 2294e98e3e1Schristos frv_queue_instruction_access_exception_interrupt (current_cpu); 2304e98e3e1Schristos else 2314e98e3e1Schristos { 2324e98e3e1Schristos USI hsr0 = GET_HSR0 (); 2334e98e3e1Schristos if (! GET_HSR0_RME (hsr0) 2344e98e3e1Schristos && (USI)address >= 0xfe000000 && (USI)address <= 0xfe007fff) 2354e98e3e1Schristos frv_queue_instruction_access_exception_interrupt (current_cpu); 2364e98e3e1Schristos } 2374e98e3e1Schristos 2384e98e3e1Schristos return address; 2394e98e3e1Schristos } 2404e98e3e1Schristos 2414e98e3e1Schristos static PCADDR 2424e98e3e1Schristos check_insn_read_address (SIM_CPU *current_cpu, PCADDR address, int align_mask) 2434e98e3e1Schristos { 2444e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 2454e98e3e1Schristos switch (STATE_ARCHITECTURE (sd)->mach) 2464e98e3e1Schristos { 2474e98e3e1Schristos case bfd_mach_fr400: 2484e98e3e1Schristos case bfd_mach_fr450: 2494e98e3e1Schristos address = fr400_check_insn_read_address (current_cpu, address, 2504e98e3e1Schristos align_mask); 2514e98e3e1Schristos break; 2524e98e3e1Schristos case bfd_mach_frvtomcat: 2534e98e3e1Schristos case bfd_mach_fr500: 2544e98e3e1Schristos case bfd_mach_frv: 2554e98e3e1Schristos address = fr500_check_insn_read_address (current_cpu, address, 2564e98e3e1Schristos align_mask); 2574e98e3e1Schristos break; 2584e98e3e1Schristos case bfd_mach_fr550: 2594e98e3e1Schristos address = fr550_check_insn_read_address (current_cpu, address, 2604e98e3e1Schristos align_mask); 2614e98e3e1Schristos break; 2624e98e3e1Schristos default: 2634e98e3e1Schristos break; 2644e98e3e1Schristos } 2654e98e3e1Schristos 2664e98e3e1Schristos return address; 2674e98e3e1Schristos } 2684e98e3e1Schristos 2694e98e3e1Schristos /* Memory reads. */ 2704e98e3e1Schristos QI 2714e98e3e1Schristos frvbf_read_mem_QI (SIM_CPU *current_cpu, IADDR pc, SI address) 2724e98e3e1Schristos { 2734e98e3e1Schristos USI hsr0 = GET_HSR0 (); 2744e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 2754e98e3e1Schristos 2764e98e3e1Schristos /* Check for access exceptions. */ 2774e98e3e1Schristos address = check_data_read_address (current_cpu, address, 0); 2784e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 0); 2794e98e3e1Schristos 2804e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 2814e98e3e1Schristos initiated from the model profiling functions. 2824e98e3e1Schristos See frvbf_model_.... */ 2834e98e3e1Schristos if (model_insn) 2844e98e3e1Schristos { 2854e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 2864e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 1; 2874e98e3e1Schristos CPU_LOAD_SIGNED (current_cpu) = 1; 2884e98e3e1Schristos return 0xb7; /* any random value */ 2894e98e3e1Schristos } 2904e98e3e1Schristos 2914e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 2924e98e3e1Schristos { 2934e98e3e1Schristos int cycles; 2944e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 2954e98e3e1Schristos if (cycles != 0) 2964e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, QI, 1); 2974e98e3e1Schristos } 2984e98e3e1Schristos 2994e98e3e1Schristos return GETMEMQI (current_cpu, pc, address); 3004e98e3e1Schristos } 3014e98e3e1Schristos 3024e98e3e1Schristos UQI 3034e98e3e1Schristos frvbf_read_mem_UQI (SIM_CPU *current_cpu, IADDR pc, SI address) 3044e98e3e1Schristos { 3054e98e3e1Schristos USI hsr0 = GET_HSR0 (); 3064e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 3074e98e3e1Schristos 3084e98e3e1Schristos /* Check for access exceptions. */ 3094e98e3e1Schristos address = check_data_read_address (current_cpu, address, 0); 3104e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 0); 3114e98e3e1Schristos 3124e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 3134e98e3e1Schristos initiated from the model profiling functions. 3144e98e3e1Schristos See frvbf_model_.... */ 3154e98e3e1Schristos if (model_insn) 3164e98e3e1Schristos { 3174e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 3184e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 1; 3194e98e3e1Schristos CPU_LOAD_SIGNED (current_cpu) = 0; 3204e98e3e1Schristos return 0xb7; /* any random value */ 3214e98e3e1Schristos } 3224e98e3e1Schristos 3234e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 3244e98e3e1Schristos { 3254e98e3e1Schristos int cycles; 3264e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 3274e98e3e1Schristos if (cycles != 0) 3284e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, UQI, 1); 3294e98e3e1Schristos } 3304e98e3e1Schristos 3314e98e3e1Schristos return GETMEMUQI (current_cpu, pc, address); 3324e98e3e1Schristos } 3334e98e3e1Schristos 3344e98e3e1Schristos /* Read a HI which spans two cache lines */ 3354e98e3e1Schristos static HI 3364e98e3e1Schristos read_mem_unaligned_HI (SIM_CPU *current_cpu, IADDR pc, SI address) 3374e98e3e1Schristos { 3384e98e3e1Schristos HI value = frvbf_read_mem_QI (current_cpu, pc, address); 3394e98e3e1Schristos value <<= 8; 3404e98e3e1Schristos value |= frvbf_read_mem_UQI (current_cpu, pc, address + 1); 3414e98e3e1Schristos return T2H_2 (value); 3424e98e3e1Schristos } 3434e98e3e1Schristos 3444e98e3e1Schristos HI 3454e98e3e1Schristos frvbf_read_mem_HI (SIM_CPU *current_cpu, IADDR pc, SI address) 3464e98e3e1Schristos { 3474e98e3e1Schristos USI hsr0; 3484e98e3e1Schristos FRV_CACHE *cache; 3494e98e3e1Schristos 3504e98e3e1Schristos /* Check for access exceptions. */ 3514e98e3e1Schristos address = check_data_read_address (current_cpu, address, 1); 3524e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 1); 3534e98e3e1Schristos 3544e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 3554e98e3e1Schristos initiated from the model profiling functions. 3564e98e3e1Schristos See frvbf_model_.... */ 3574e98e3e1Schristos hsr0 = GET_HSR0 (); 3584e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 3594e98e3e1Schristos if (model_insn) 3604e98e3e1Schristos { 3614e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 3624e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 2; 3634e98e3e1Schristos CPU_LOAD_SIGNED (current_cpu) = 1; 3644e98e3e1Schristos return 0xb711; /* any random value */ 3654e98e3e1Schristos } 3664e98e3e1Schristos 3674e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 3684e98e3e1Schristos { 3694e98e3e1Schristos int cycles; 3704e98e3e1Schristos /* Handle access which crosses cache line boundary */ 3714e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 3724e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 3734e98e3e1Schristos { 3744e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 2)) 3754e98e3e1Schristos return read_mem_unaligned_HI (current_cpu, pc, address); 3764e98e3e1Schristos } 3774e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 3784e98e3e1Schristos if (cycles != 0) 3794e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, HI, 2); 3804e98e3e1Schristos } 3814e98e3e1Schristos 3824e98e3e1Schristos return GETMEMHI (current_cpu, pc, address); 3834e98e3e1Schristos } 3844e98e3e1Schristos 3854e98e3e1Schristos UHI 3864e98e3e1Schristos frvbf_read_mem_UHI (SIM_CPU *current_cpu, IADDR pc, SI address) 3874e98e3e1Schristos { 3884e98e3e1Schristos USI hsr0; 3894e98e3e1Schristos FRV_CACHE *cache; 3904e98e3e1Schristos 3914e98e3e1Schristos /* Check for access exceptions. */ 3924e98e3e1Schristos address = check_data_read_address (current_cpu, address, 1); 3934e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 1); 3944e98e3e1Schristos 3954e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 3964e98e3e1Schristos initiated from the model profiling functions. 3974e98e3e1Schristos See frvbf_model_.... */ 3984e98e3e1Schristos hsr0 = GET_HSR0 (); 3994e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 4004e98e3e1Schristos if (model_insn) 4014e98e3e1Schristos { 4024e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 4034e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 2; 4044e98e3e1Schristos CPU_LOAD_SIGNED (current_cpu) = 0; 4054e98e3e1Schristos return 0xb711; /* any random value */ 4064e98e3e1Schristos } 4074e98e3e1Schristos 4084e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 4094e98e3e1Schristos { 4104e98e3e1Schristos int cycles; 4114e98e3e1Schristos /* Handle access which crosses cache line boundary */ 4124e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 4134e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 4144e98e3e1Schristos { 4154e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 2)) 4164e98e3e1Schristos return read_mem_unaligned_HI (current_cpu, pc, address); 4174e98e3e1Schristos } 4184e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 4194e98e3e1Schristos if (cycles != 0) 4204e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, UHI, 2); 4214e98e3e1Schristos } 4224e98e3e1Schristos 4234e98e3e1Schristos return GETMEMUHI (current_cpu, pc, address); 4244e98e3e1Schristos } 4254e98e3e1Schristos 4264e98e3e1Schristos /* Read a SI which spans two cache lines */ 4274e98e3e1Schristos static SI 4284e98e3e1Schristos read_mem_unaligned_SI (SIM_CPU *current_cpu, IADDR pc, SI address) 4294e98e3e1Schristos { 4304e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 4314e98e3e1Schristos unsigned hi_len = cache->line_size - (address & (cache->line_size - 1)); 4324e98e3e1Schristos char valarray[4]; 4334e98e3e1Schristos SI SIvalue; 4344e98e3e1Schristos HI HIvalue; 4354e98e3e1Schristos 4364e98e3e1Schristos switch (hi_len) 4374e98e3e1Schristos { 4384e98e3e1Schristos case 1: 4394e98e3e1Schristos valarray[0] = frvbf_read_mem_QI (current_cpu, pc, address); 4404e98e3e1Schristos SIvalue = frvbf_read_mem_SI (current_cpu, pc, address + 1); 4414e98e3e1Schristos SIvalue = H2T_4 (SIvalue); 4424e98e3e1Schristos memcpy (valarray + 1, (char*)&SIvalue, 3); 4434e98e3e1Schristos break; 4444e98e3e1Schristos case 2: 4454e98e3e1Schristos HIvalue = frvbf_read_mem_HI (current_cpu, pc, address); 4464e98e3e1Schristos HIvalue = H2T_2 (HIvalue); 4474e98e3e1Schristos memcpy (valarray, (char*)&HIvalue, 2); 4484e98e3e1Schristos HIvalue = frvbf_read_mem_HI (current_cpu, pc, address + 2); 4494e98e3e1Schristos HIvalue = H2T_2 (HIvalue); 4504e98e3e1Schristos memcpy (valarray + 2, (char*)&HIvalue, 2); 4514e98e3e1Schristos break; 4524e98e3e1Schristos case 3: 4534e98e3e1Schristos SIvalue = frvbf_read_mem_SI (current_cpu, pc, address - 1); 4544e98e3e1Schristos SIvalue = H2T_4 (SIvalue); 4554e98e3e1Schristos memcpy (valarray, (char*)&SIvalue, 3); 4564e98e3e1Schristos valarray[3] = frvbf_read_mem_QI (current_cpu, pc, address + 3); 4574e98e3e1Schristos break; 4584e98e3e1Schristos default: 4594e98e3e1Schristos abort (); /* can't happen */ 4604e98e3e1Schristos } 4614e98e3e1Schristos return T2H_4 (*(SI*)valarray); 4624e98e3e1Schristos } 4634e98e3e1Schristos 4644e98e3e1Schristos SI 4654e98e3e1Schristos frvbf_read_mem_SI (SIM_CPU *current_cpu, IADDR pc, SI address) 4664e98e3e1Schristos { 4674e98e3e1Schristos FRV_CACHE *cache; 4684e98e3e1Schristos USI hsr0; 4694e98e3e1Schristos 4704e98e3e1Schristos /* Check for access exceptions. */ 4714e98e3e1Schristos address = check_data_read_address (current_cpu, address, 3); 4724e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 3); 4734e98e3e1Schristos 4744e98e3e1Schristos hsr0 = GET_HSR0 (); 4754e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 4764e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 4774e98e3e1Schristos initiated from the model profiling functions. 4784e98e3e1Schristos See frvbf_model_.... */ 4794e98e3e1Schristos if (model_insn) 4804e98e3e1Schristos { 4814e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 4824e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 4; 4834e98e3e1Schristos return 0x37111319; /* any random value */ 4844e98e3e1Schristos } 4854e98e3e1Schristos 4864e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 4874e98e3e1Schristos { 4884e98e3e1Schristos int cycles; 4894e98e3e1Schristos /* Handle access which crosses cache line boundary */ 4904e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 4914e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 4924e98e3e1Schristos { 4934e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 4)) 4944e98e3e1Schristos return read_mem_unaligned_SI (current_cpu, pc, address); 4954e98e3e1Schristos } 4964e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 4974e98e3e1Schristos if (cycles != 0) 4984e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, SI, 4); 4994e98e3e1Schristos } 5004e98e3e1Schristos 5014e98e3e1Schristos return GETMEMSI (current_cpu, pc, address); 5024e98e3e1Schristos } 5034e98e3e1Schristos 5044e98e3e1Schristos SI 5054e98e3e1Schristos frvbf_read_mem_WI (SIM_CPU *current_cpu, IADDR pc, SI address) 5064e98e3e1Schristos { 5074e98e3e1Schristos return frvbf_read_mem_SI (current_cpu, pc, address); 5084e98e3e1Schristos } 5094e98e3e1Schristos 5104e98e3e1Schristos /* Read a SI which spans two cache lines */ 5114e98e3e1Schristos static DI 5124e98e3e1Schristos read_mem_unaligned_DI (SIM_CPU *current_cpu, IADDR pc, SI address) 5134e98e3e1Schristos { 5144e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 5154e98e3e1Schristos unsigned hi_len = cache->line_size - (address & (cache->line_size - 1)); 5164e98e3e1Schristos DI value, value1; 5174e98e3e1Schristos 5184e98e3e1Schristos switch (hi_len) 5194e98e3e1Schristos { 5204e98e3e1Schristos case 1: 5214e98e3e1Schristos value = frvbf_read_mem_QI (current_cpu, pc, address); 5224e98e3e1Schristos value <<= 56; 5234e98e3e1Schristos value1 = frvbf_read_mem_DI (current_cpu, pc, address + 1); 5244e98e3e1Schristos value1 = H2T_8 (value1); 5254e98e3e1Schristos value |= value1 & ((DI)0x00ffffff << 32); 5264e98e3e1Schristos value |= value1 & 0xffffffffu; 5274e98e3e1Schristos break; 5284e98e3e1Schristos case 2: 5294e98e3e1Schristos value = frvbf_read_mem_HI (current_cpu, pc, address); 5304e98e3e1Schristos value = H2T_2 (value); 5314e98e3e1Schristos value <<= 48; 5324e98e3e1Schristos value1 = frvbf_read_mem_DI (current_cpu, pc, address + 2); 5334e98e3e1Schristos value1 = H2T_8 (value1); 5344e98e3e1Schristos value |= value1 & ((DI)0x0000ffff << 32); 5354e98e3e1Schristos value |= value1 & 0xffffffffu; 5364e98e3e1Schristos break; 5374e98e3e1Schristos case 3: 5384e98e3e1Schristos value = frvbf_read_mem_SI (current_cpu, pc, address - 1); 5394e98e3e1Schristos value = H2T_4 (value); 5404e98e3e1Schristos value <<= 40; 5414e98e3e1Schristos value1 = frvbf_read_mem_DI (current_cpu, pc, address + 3); 5424e98e3e1Schristos value1 = H2T_8 (value1); 5434e98e3e1Schristos value |= value1 & ((DI)0x000000ff << 32); 5444e98e3e1Schristos value |= value1 & 0xffffffffu; 5454e98e3e1Schristos break; 5464e98e3e1Schristos case 4: 5474e98e3e1Schristos value = frvbf_read_mem_SI (current_cpu, pc, address); 5484e98e3e1Schristos value = H2T_4 (value); 5494e98e3e1Schristos value <<= 32; 5504e98e3e1Schristos value1 = frvbf_read_mem_SI (current_cpu, pc, address + 4); 5514e98e3e1Schristos value1 = H2T_4 (value1); 5524e98e3e1Schristos value |= value1 & 0xffffffffu; 5534e98e3e1Schristos break; 5544e98e3e1Schristos case 5: 5554e98e3e1Schristos value = frvbf_read_mem_DI (current_cpu, pc, address - 3); 5564e98e3e1Schristos value = H2T_8 (value); 5574e98e3e1Schristos value <<= 24; 5584e98e3e1Schristos value1 = frvbf_read_mem_SI (current_cpu, pc, address + 5); 5594e98e3e1Schristos value1 = H2T_4 (value1); 5604e98e3e1Schristos value |= value1 & 0x00ffffff; 5614e98e3e1Schristos break; 5624e98e3e1Schristos case 6: 5634e98e3e1Schristos value = frvbf_read_mem_DI (current_cpu, pc, address - 2); 5644e98e3e1Schristos value = H2T_8 (value); 5654e98e3e1Schristos value <<= 16; 5664e98e3e1Schristos value1 = frvbf_read_mem_HI (current_cpu, pc, address + 6); 5674e98e3e1Schristos value1 = H2T_2 (value1); 5684e98e3e1Schristos value |= value1 & 0x0000ffff; 5694e98e3e1Schristos break; 5704e98e3e1Schristos case 7: 5714e98e3e1Schristos value = frvbf_read_mem_DI (current_cpu, pc, address - 1); 5724e98e3e1Schristos value = H2T_8 (value); 5734e98e3e1Schristos value <<= 8; 5744e98e3e1Schristos value1 = frvbf_read_mem_QI (current_cpu, pc, address + 7); 5754e98e3e1Schristos value |= value1 & 0x000000ff; 5764e98e3e1Schristos break; 5774e98e3e1Schristos default: 5784e98e3e1Schristos abort (); /* can't happen */ 5794e98e3e1Schristos } 5804e98e3e1Schristos return T2H_8 (value); 5814e98e3e1Schristos } 5824e98e3e1Schristos 5834e98e3e1Schristos DI 5844e98e3e1Schristos frvbf_read_mem_DI (SIM_CPU *current_cpu, IADDR pc, SI address) 5854e98e3e1Schristos { 5864e98e3e1Schristos USI hsr0; 5874e98e3e1Schristos FRV_CACHE *cache; 5884e98e3e1Schristos 5894e98e3e1Schristos /* Check for access exceptions. */ 5904e98e3e1Schristos address = check_data_read_address (current_cpu, address, 7); 5914e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 7); 5924e98e3e1Schristos 5934e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 5944e98e3e1Schristos initiated from the model profiling functions. 5954e98e3e1Schristos See frvbf_model_.... */ 5964e98e3e1Schristos hsr0 = GET_HSR0 (); 5974e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 5984e98e3e1Schristos if (model_insn) 5994e98e3e1Schristos { 6004e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 6014e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 8; 6024e98e3e1Schristos return 0x37111319; /* any random value */ 6034e98e3e1Schristos } 6044e98e3e1Schristos 6054e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 6064e98e3e1Schristos { 6074e98e3e1Schristos int cycles; 6084e98e3e1Schristos /* Handle access which crosses cache line boundary */ 6094e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 6104e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 6114e98e3e1Schristos { 6124e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 8)) 6134e98e3e1Schristos return read_mem_unaligned_DI (current_cpu, pc, address); 6144e98e3e1Schristos } 6154e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 6164e98e3e1Schristos if (cycles != 0) 6174e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, DI, 8); 6184e98e3e1Schristos } 6194e98e3e1Schristos 6204e98e3e1Schristos return GETMEMDI (current_cpu, pc, address); 6214e98e3e1Schristos } 6224e98e3e1Schristos 6234e98e3e1Schristos DF 6244e98e3e1Schristos frvbf_read_mem_DF (SIM_CPU *current_cpu, IADDR pc, SI address) 6254e98e3e1Schristos { 6264e98e3e1Schristos USI hsr0; 6274e98e3e1Schristos FRV_CACHE *cache; 6284e98e3e1Schristos 6294e98e3e1Schristos /* Check for access exceptions. */ 6304e98e3e1Schristos address = check_data_read_address (current_cpu, address, 7); 6314e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 7); 6324e98e3e1Schristos 6334e98e3e1Schristos /* If we need to count cycles, then the cache operation will be 6344e98e3e1Schristos initiated from the model profiling functions. 6354e98e3e1Schristos See frvbf_model_.... */ 6364e98e3e1Schristos hsr0 = GET_HSR0 (); 6374e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 6384e98e3e1Schristos if (model_insn) 6394e98e3e1Schristos { 6404e98e3e1Schristos CPU_LOAD_ADDRESS (current_cpu) = address; 6414e98e3e1Schristos CPU_LOAD_LENGTH (current_cpu) = 8; 6424e98e3e1Schristos return 0x37111319; /* any random value */ 6434e98e3e1Schristos } 6444e98e3e1Schristos 6454e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 6464e98e3e1Schristos { 6474e98e3e1Schristos int cycles; 6484e98e3e1Schristos /* Handle access which crosses cache line boundary */ 6494e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 6504e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 6514e98e3e1Schristos { 6524e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 8)) 6534e98e3e1Schristos return read_mem_unaligned_DI (current_cpu, pc, address); 6544e98e3e1Schristos } 6554e98e3e1Schristos cycles = frv_cache_read (cache, 0, address); 6564e98e3e1Schristos if (cycles != 0) 6574e98e3e1Schristos return CACHE_RETURN_DATA (cache, 0, address, DF, 8); 6584e98e3e1Schristos } 6594e98e3e1Schristos 6604e98e3e1Schristos return GETMEMDF (current_cpu, pc, address); 6614e98e3e1Schristos } 6624e98e3e1Schristos 6634e98e3e1Schristos USI 6644e98e3e1Schristos frvbf_read_imem_USI (SIM_CPU *current_cpu, PCADDR vpc) 6654e98e3e1Schristos { 6664e98e3e1Schristos USI hsr0; 6674e98e3e1Schristos vpc = check_insn_read_address (current_cpu, vpc, 3); 6684e98e3e1Schristos 6694e98e3e1Schristos hsr0 = GET_HSR0 (); 6704e98e3e1Schristos if (GET_HSR0_ICE (hsr0)) 6714e98e3e1Schristos { 6724e98e3e1Schristos FRV_CACHE *cache; 673*2a9ac006Schristos SI value; 6744e98e3e1Schristos 6754e98e3e1Schristos /* We don't want this to show up in the cache statistics. That read 6764e98e3e1Schristos is done in frvbf_simulate_insn_prefetch. So read the cache or memory 6774e98e3e1Schristos passively here. */ 6784e98e3e1Schristos cache = CPU_INSN_CACHE (current_cpu); 6794e98e3e1Schristos if (frv_cache_read_passive_SI (cache, vpc, &value)) 6804e98e3e1Schristos return value; 6814e98e3e1Schristos } 6824e98e3e1Schristos return sim_core_read_unaligned_4 (current_cpu, vpc, read_map, vpc); 6834e98e3e1Schristos } 6844e98e3e1Schristos 6854e98e3e1Schristos static SI 6864e98e3e1Schristos fr400_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask) 6874e98e3e1Schristos { 6884e98e3e1Schristos if (align_mask == 7 6894e98e3e1Schristos && address >= 0xfe800000 && address <= 0xfeffffff) 6904e98e3e1Schristos frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR); 6914e98e3e1Schristos 6924e98e3e1Schristos return address; 6934e98e3e1Schristos } 6944e98e3e1Schristos 6954e98e3e1Schristos static SI 6964e98e3e1Schristos fr500_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask) 6974e98e3e1Schristos { 6984e98e3e1Schristos if (address & align_mask) 6994e98e3e1Schristos { 7004e98e3e1Schristos struct frv_interrupt_queue_element *item = 7014e98e3e1Schristos frv_queue_mem_address_not_aligned_interrupt (current_cpu, address); 7024e98e3e1Schristos /* Record the correct vliw slot with the interrupt. */ 7034e98e3e1Schristos if (item != NULL) 7044e98e3e1Schristos item->slot = frv_interrupt_state.slot; 7054e98e3e1Schristos address &= ~align_mask; 7064e98e3e1Schristos } 7074b169a6bSchristos if ((address >= 0xfeff0600 && address <= 0xfeff7fff) 7084b169a6bSchristos || (address >= 0xfe800000 && address <= 0xfefeffff)) 7094e98e3e1Schristos frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR); 7104e98e3e1Schristos 7114e98e3e1Schristos return address; 7124e98e3e1Schristos } 7134e98e3e1Schristos 7144e98e3e1Schristos static SI 7154e98e3e1Schristos fr550_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask) 7164e98e3e1Schristos { 7174b169a6bSchristos if (((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff) 7184e98e3e1Schristos || (align_mask > 0x3 7194e98e3e1Schristos && ((USI)address >= 0xfeff0000 && (USI)address <= 0xfeffffff))) 7204e98e3e1Schristos frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR); 7214e98e3e1Schristos 7224e98e3e1Schristos return address; 7234e98e3e1Schristos } 7244e98e3e1Schristos 7254e98e3e1Schristos static SI 7264e98e3e1Schristos check_write_address (SIM_CPU *current_cpu, SI address, int align_mask) 7274e98e3e1Schristos { 7284e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 7294e98e3e1Schristos switch (STATE_ARCHITECTURE (sd)->mach) 7304e98e3e1Schristos { 7314e98e3e1Schristos case bfd_mach_fr400: 7324e98e3e1Schristos case bfd_mach_fr450: 7334e98e3e1Schristos address = fr400_check_write_address (current_cpu, address, align_mask); 7344e98e3e1Schristos break; 7354e98e3e1Schristos case bfd_mach_frvtomcat: 7364e98e3e1Schristos case bfd_mach_fr500: 7374e98e3e1Schristos case bfd_mach_frv: 7384e98e3e1Schristos address = fr500_check_write_address (current_cpu, address, align_mask); 7394e98e3e1Schristos break; 7404e98e3e1Schristos case bfd_mach_fr550: 7414e98e3e1Schristos address = fr550_check_write_address (current_cpu, address, align_mask); 7424e98e3e1Schristos break; 7434e98e3e1Schristos default: 7444e98e3e1Schristos break; 7454e98e3e1Schristos } 7464e98e3e1Schristos return address; 7474e98e3e1Schristos } 7484e98e3e1Schristos 7494e98e3e1Schristos void 7504e98e3e1Schristos frvbf_write_mem_QI (SIM_CPU *current_cpu, IADDR pc, SI address, QI value) 7514e98e3e1Schristos { 7524e98e3e1Schristos USI hsr0; 7534e98e3e1Schristos hsr0 = GET_HSR0 (); 7544e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 7554e98e3e1Schristos sim_queue_fn_mem_qi_write (current_cpu, frvbf_mem_set_QI, address, value); 7564e98e3e1Schristos else 7574e98e3e1Schristos sim_queue_mem_qi_write (current_cpu, address, value); 7584e98e3e1Schristos frv_set_write_queue_slot (current_cpu); 7594e98e3e1Schristos } 7604e98e3e1Schristos 7614e98e3e1Schristos void 7624e98e3e1Schristos frvbf_write_mem_UQI (SIM_CPU *current_cpu, IADDR pc, SI address, UQI value) 7634e98e3e1Schristos { 7644e98e3e1Schristos frvbf_write_mem_QI (current_cpu, pc, address, value); 7654e98e3e1Schristos } 7664e98e3e1Schristos 7674e98e3e1Schristos void 7684e98e3e1Schristos frvbf_write_mem_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value) 7694e98e3e1Schristos { 7704e98e3e1Schristos USI hsr0; 7714e98e3e1Schristos hsr0 = GET_HSR0 (); 7724e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 7734e98e3e1Schristos sim_queue_fn_mem_hi_write (current_cpu, frvbf_mem_set_HI, address, value); 7744e98e3e1Schristos else 7754e98e3e1Schristos sim_queue_mem_hi_write (current_cpu, address, value); 7764e98e3e1Schristos frv_set_write_queue_slot (current_cpu); 7774e98e3e1Schristos } 7784e98e3e1Schristos 7794e98e3e1Schristos void 7804e98e3e1Schristos frvbf_write_mem_UHI (SIM_CPU *current_cpu, IADDR pc, SI address, UHI value) 7814e98e3e1Schristos { 7824e98e3e1Schristos frvbf_write_mem_HI (current_cpu, pc, address, value); 7834e98e3e1Schristos } 7844e98e3e1Schristos 7854e98e3e1Schristos void 7864e98e3e1Schristos frvbf_write_mem_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value) 7874e98e3e1Schristos { 7884e98e3e1Schristos USI hsr0; 7894e98e3e1Schristos hsr0 = GET_HSR0 (); 7904e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 7914e98e3e1Schristos sim_queue_fn_mem_si_write (current_cpu, frvbf_mem_set_SI, address, value); 7924e98e3e1Schristos else 7934e98e3e1Schristos sim_queue_mem_si_write (current_cpu, address, value); 7944e98e3e1Schristos frv_set_write_queue_slot (current_cpu); 7954e98e3e1Schristos } 7964e98e3e1Schristos 7974e98e3e1Schristos void 7984e98e3e1Schristos frvbf_write_mem_WI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value) 7994e98e3e1Schristos { 8004e98e3e1Schristos frvbf_write_mem_SI (current_cpu, pc, address, value); 8014e98e3e1Schristos } 8024e98e3e1Schristos 8034e98e3e1Schristos void 8044e98e3e1Schristos frvbf_write_mem_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value) 8054e98e3e1Schristos { 8064e98e3e1Schristos USI hsr0; 8074e98e3e1Schristos hsr0 = GET_HSR0 (); 8084e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 8094e98e3e1Schristos sim_queue_fn_mem_di_write (current_cpu, frvbf_mem_set_DI, address, value); 8104e98e3e1Schristos else 8114e98e3e1Schristos sim_queue_mem_di_write (current_cpu, address, value); 8124e98e3e1Schristos frv_set_write_queue_slot (current_cpu); 8134e98e3e1Schristos } 8144e98e3e1Schristos 8154e98e3e1Schristos void 8164e98e3e1Schristos frvbf_write_mem_DF (SIM_CPU *current_cpu, IADDR pc, SI address, DF value) 8174e98e3e1Schristos { 8184e98e3e1Schristos USI hsr0; 8194e98e3e1Schristos hsr0 = GET_HSR0 (); 8204e98e3e1Schristos if (GET_HSR0_DCE (hsr0)) 8214e98e3e1Schristos sim_queue_fn_mem_df_write (current_cpu, frvbf_mem_set_DF, address, value); 8224e98e3e1Schristos else 8234e98e3e1Schristos sim_queue_mem_df_write (current_cpu, address, value); 8244e98e3e1Schristos frv_set_write_queue_slot (current_cpu); 8254e98e3e1Schristos } 8264e98e3e1Schristos 8274e98e3e1Schristos /* Memory writes. These do the actual writing through the cache. */ 8284e98e3e1Schristos void 8294e98e3e1Schristos frvbf_mem_set_QI (SIM_CPU *current_cpu, IADDR pc, SI address, QI value) 8304e98e3e1Schristos { 8314e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 8324e98e3e1Schristos 8334e98e3e1Schristos /* Check for access errors. */ 8344e98e3e1Schristos address = check_write_address (current_cpu, address, 0); 8354e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 0); 8364e98e3e1Schristos 8374e98e3e1Schristos /* If we need to count cycles, then submit the write request to the cache 8384e98e3e1Schristos and let it prioritize the request. Otherwise perform the write now. */ 8394e98e3e1Schristos if (model_insn) 8404e98e3e1Schristos { 8414e98e3e1Schristos int slot = UNIT_I0; 8424e98e3e1Schristos frv_cache_request_store (cache, address, slot, (char *)&value, 8434e98e3e1Schristos sizeof (value)); 8444e98e3e1Schristos } 8454e98e3e1Schristos else 8464e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, sizeof (value)); 8474e98e3e1Schristos } 8484e98e3e1Schristos 8494e98e3e1Schristos /* Write a HI which spans two cache lines */ 8504e98e3e1Schristos static void 8514e98e3e1Schristos mem_set_unaligned_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value) 8524e98e3e1Schristos { 8534e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 8544e98e3e1Schristos /* value is already in target byte order */ 8554e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, 1); 8564e98e3e1Schristos frv_cache_write (cache, address + 1, ((char *)&value + 1), 1); 8574e98e3e1Schristos } 8584e98e3e1Schristos 8594e98e3e1Schristos void 8604e98e3e1Schristos frvbf_mem_set_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value) 8614e98e3e1Schristos { 8624e98e3e1Schristos FRV_CACHE *cache; 8634e98e3e1Schristos 8644e98e3e1Schristos /* Check for access errors. */ 8654e98e3e1Schristos address = check_write_address (current_cpu, address, 1); 8664e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 1); 8674e98e3e1Schristos 8684e98e3e1Schristos /* If we need to count cycles, then submit the write request to the cache 8694e98e3e1Schristos and let it prioritize the request. Otherwise perform the write now. */ 8704e98e3e1Schristos value = H2T_2 (value); 8714e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 8724e98e3e1Schristos if (model_insn) 8734e98e3e1Schristos { 8744e98e3e1Schristos int slot = UNIT_I0; 8754e98e3e1Schristos frv_cache_request_store (cache, address, slot, 8764e98e3e1Schristos (char *)&value, sizeof (value)); 8774e98e3e1Schristos } 8784e98e3e1Schristos else 8794e98e3e1Schristos { 8804e98e3e1Schristos /* Handle access which crosses cache line boundary */ 8814e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 8824e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 8834e98e3e1Schristos { 8844e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 2)) 8854e98e3e1Schristos { 8864e98e3e1Schristos mem_set_unaligned_HI (current_cpu, pc, address, value); 8874e98e3e1Schristos return; 8884e98e3e1Schristos } 8894e98e3e1Schristos } 8904e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, sizeof (value)); 8914e98e3e1Schristos } 8924e98e3e1Schristos } 8934e98e3e1Schristos 8944e98e3e1Schristos /* Write a SI which spans two cache lines */ 8954e98e3e1Schristos static void 8964e98e3e1Schristos mem_set_unaligned_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value) 8974e98e3e1Schristos { 8984e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 8994e98e3e1Schristos unsigned hi_len = cache->line_size - (address & (cache->line_size - 1)); 9004e98e3e1Schristos /* value is already in target byte order */ 9014e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, hi_len); 9024e98e3e1Schristos frv_cache_write (cache, address + hi_len, (char *)&value + hi_len, 4 - hi_len); 9034e98e3e1Schristos } 9044e98e3e1Schristos 9054e98e3e1Schristos void 9064e98e3e1Schristos frvbf_mem_set_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value) 9074e98e3e1Schristos { 9084e98e3e1Schristos FRV_CACHE *cache; 9094e98e3e1Schristos 9104e98e3e1Schristos /* Check for access errors. */ 9114e98e3e1Schristos address = check_write_address (current_cpu, address, 3); 9124e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 3); 9134e98e3e1Schristos 9144e98e3e1Schristos /* If we need to count cycles, then submit the write request to the cache 9154e98e3e1Schristos and let it prioritize the request. Otherwise perform the write now. */ 9164e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 9174e98e3e1Schristos value = H2T_4 (value); 9184e98e3e1Schristos if (model_insn) 9194e98e3e1Schristos { 9204e98e3e1Schristos int slot = UNIT_I0; 9214e98e3e1Schristos frv_cache_request_store (cache, address, slot, 9224e98e3e1Schristos (char *)&value, sizeof (value)); 9234e98e3e1Schristos } 9244e98e3e1Schristos else 9254e98e3e1Schristos { 9264e98e3e1Schristos /* Handle access which crosses cache line boundary */ 9274e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 9284e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 9294e98e3e1Schristos { 9304e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 4)) 9314e98e3e1Schristos { 9324e98e3e1Schristos mem_set_unaligned_SI (current_cpu, pc, address, value); 9334e98e3e1Schristos return; 9344e98e3e1Schristos } 9354e98e3e1Schristos } 9364e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, sizeof (value)); 9374e98e3e1Schristos } 9384e98e3e1Schristos } 9394e98e3e1Schristos 9404e98e3e1Schristos /* Write a DI which spans two cache lines */ 9414e98e3e1Schristos static void 9424e98e3e1Schristos mem_set_unaligned_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value) 9434e98e3e1Schristos { 9444e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 9454e98e3e1Schristos unsigned hi_len = cache->line_size - (address & (cache->line_size - 1)); 9464e98e3e1Schristos /* value is already in target byte order */ 9474e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, hi_len); 9484e98e3e1Schristos frv_cache_write (cache, address + hi_len, (char *)&value + hi_len, 8 - hi_len); 9494e98e3e1Schristos } 9504e98e3e1Schristos 9514e98e3e1Schristos void 9524e98e3e1Schristos frvbf_mem_set_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value) 9534e98e3e1Schristos { 9544e98e3e1Schristos FRV_CACHE *cache; 9554e98e3e1Schristos 9564e98e3e1Schristos /* Check for access errors. */ 9574e98e3e1Schristos address = check_write_address (current_cpu, address, 7); 9584e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 7); 9594e98e3e1Schristos 9604e98e3e1Schristos /* If we need to count cycles, then submit the write request to the cache 9614e98e3e1Schristos and let it prioritize the request. Otherwise perform the write now. */ 9624e98e3e1Schristos value = H2T_8 (value); 9634e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 9644e98e3e1Schristos if (model_insn) 9654e98e3e1Schristos { 9664e98e3e1Schristos int slot = UNIT_I0; 9674e98e3e1Schristos frv_cache_request_store (cache, address, slot, 9684e98e3e1Schristos (char *)&value, sizeof (value)); 9694e98e3e1Schristos } 9704e98e3e1Schristos else 9714e98e3e1Schristos { 9724e98e3e1Schristos /* Handle access which crosses cache line boundary */ 9734e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 9744e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 9754e98e3e1Schristos { 9764e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 8)) 9774e98e3e1Schristos { 9784e98e3e1Schristos mem_set_unaligned_DI (current_cpu, pc, address, value); 9794e98e3e1Schristos return; 9804e98e3e1Schristos } 9814e98e3e1Schristos } 9824e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, sizeof (value)); 9834e98e3e1Schristos } 9844e98e3e1Schristos } 9854e98e3e1Schristos 9864e98e3e1Schristos void 9874e98e3e1Schristos frvbf_mem_set_DF (SIM_CPU *current_cpu, IADDR pc, SI address, DF value) 9884e98e3e1Schristos { 9894e98e3e1Schristos FRV_CACHE *cache; 9904e98e3e1Schristos 9914e98e3e1Schristos /* Check for access errors. */ 9924e98e3e1Schristos address = check_write_address (current_cpu, address, 7); 9934e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 7); 9944e98e3e1Schristos 9954e98e3e1Schristos /* If we need to count cycles, then submit the write request to the cache 9964e98e3e1Schristos and let it prioritize the request. Otherwise perform the write now. */ 9974e98e3e1Schristos value = H2T_8 (value); 9984e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 9994e98e3e1Schristos if (model_insn) 10004e98e3e1Schristos { 10014e98e3e1Schristos int slot = UNIT_I0; 10024e98e3e1Schristos frv_cache_request_store (cache, address, slot, 10034e98e3e1Schristos (char *)&value, sizeof (value)); 10044e98e3e1Schristos } 10054e98e3e1Schristos else 10064e98e3e1Schristos { 10074e98e3e1Schristos /* Handle access which crosses cache line boundary */ 10084e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 10094e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 10104e98e3e1Schristos { 10114e98e3e1Schristos if (DATA_CROSSES_CACHE_LINE (cache, address, 8)) 10124e98e3e1Schristos { 10134e98e3e1Schristos mem_set_unaligned_DI (current_cpu, pc, address, value); 10144e98e3e1Schristos return; 10154e98e3e1Schristos } 10164e98e3e1Schristos } 10174e98e3e1Schristos frv_cache_write (cache, address, (char *)&value, sizeof (value)); 10184e98e3e1Schristos } 10194e98e3e1Schristos } 10204e98e3e1Schristos 10214e98e3e1Schristos void 10224e98e3e1Schristos frvbf_mem_set_XI (SIM_CPU *current_cpu, IADDR pc, SI address, SI *value) 10234e98e3e1Schristos { 10244e98e3e1Schristos int i; 10254e98e3e1Schristos FRV_CACHE *cache; 10264e98e3e1Schristos 10274e98e3e1Schristos /* Check for access errors. */ 10284e98e3e1Schristos address = check_write_address (current_cpu, address, 0xf); 10294e98e3e1Schristos address = check_readwrite_address (current_cpu, address, 0xf); 10304e98e3e1Schristos 10314e98e3e1Schristos /* TODO -- reverse word order as well? */ 10324e98e3e1Schristos for (i = 0; i < 4; ++i) 10334e98e3e1Schristos value[i] = H2T_4 (value[i]); 10344e98e3e1Schristos 10354e98e3e1Schristos /* If we need to count cycles, then submit the write request to the cache 10364e98e3e1Schristos and let it prioritize the request. Otherwise perform the write now. */ 10374e98e3e1Schristos cache = CPU_DATA_CACHE (current_cpu); 10384e98e3e1Schristos if (model_insn) 10394e98e3e1Schristos { 10404e98e3e1Schristos int slot = UNIT_I0; 10414e98e3e1Schristos frv_cache_request_store (cache, address, slot, (char*)value, 16); 10424e98e3e1Schristos } 10434e98e3e1Schristos else 10444e98e3e1Schristos frv_cache_write (cache, address, (char*)value, 16); 10454e98e3e1Schristos } 10464e98e3e1Schristos 10474e98e3e1Schristos /* Record the current VLIW slot on the element at the top of the write queue. 10484e98e3e1Schristos */ 10494e98e3e1Schristos void 10504e98e3e1Schristos frv_set_write_queue_slot (SIM_CPU *current_cpu) 10514e98e3e1Schristos { 10524e98e3e1Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 10534e98e3e1Schristos int slot = vliw->next_slot - 1; 10544e98e3e1Schristos CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu); 10554e98e3e1Schristos int ix = CGEN_WRITE_QUEUE_INDEX (q) - 1; 10564e98e3e1Schristos CGEN_WRITE_QUEUE_ELEMENT *item = CGEN_WRITE_QUEUE_ELEMENT (q, ix); 10574e98e3e1Schristos CGEN_WRITE_QUEUE_ELEMENT_PIPE (item) = (*vliw->current_vliw)[slot]; 10584e98e3e1Schristos } 1059