xref: /netbsd-src/external/gpl3/gdb/dist/sim/frv/memory.c (revision 2a9ac006fc2a82cb2082b71083430235e8210ae2)
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