xref: /netbsd-src/external/gpl3/gdb/dist/sim/frv/memory.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* frv memory model.
2    Copyright (C) 1999-2014 Free Software Foundation, Inc.
3    Contributed by Red Hat
4 
5 This file is part of the GNU simulators.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #define WANT_CPU frvbf
21 #define WANT_CPU_FRVBF
22 
23 #include "sim-main.h"
24 #include "cgen-mem.h"
25 #include "bfd.h"
26 
27 /* Check for alignment and access restrictions.  Return the corrected address.
28  */
29 static SI
30 fr400_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
31 {
32   /* Check access restrictions for double word loads only.  */
33   if (align_mask == 7)
34     {
35       if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff)
36 	frv_queue_data_access_error_interrupt (current_cpu, address);
37     }
38   return address;
39 }
40 
41 static SI
42 fr500_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
43 {
44   if (address & align_mask)
45     {
46       frv_queue_mem_address_not_aligned_interrupt (current_cpu, address);
47       address &= ~align_mask;
48     }
49 
50   if ((USI)address >= 0xfeff0600 && (USI)address <= 0xfeff7fff
51       || (USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff)
52     frv_queue_data_access_error_interrupt (current_cpu, address);
53 
54   return address;
55 }
56 
57 static SI
58 fr550_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
59 {
60   if ((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff
61       || (align_mask > 0x3
62 	  && ((USI)address >= 0xfeff0000 && (USI)address <= 0xfeffffff)))
63     frv_queue_data_access_error_interrupt (current_cpu, address);
64 
65   return address;
66 }
67 
68 static SI
69 check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
70 {
71   SIM_DESC sd = CPU_STATE (current_cpu);
72   switch (STATE_ARCHITECTURE (sd)->mach)
73     {
74     case bfd_mach_fr400:
75     case bfd_mach_fr450:
76       address = fr400_check_data_read_address (current_cpu, address,
77 					       align_mask);
78       break;
79     case bfd_mach_frvtomcat:
80     case bfd_mach_fr500:
81     case bfd_mach_frv:
82       address = fr500_check_data_read_address (current_cpu, address,
83 					       align_mask);
84       break;
85     case bfd_mach_fr550:
86       address = fr550_check_data_read_address (current_cpu, address,
87 					       align_mask);
88       break;
89     default:
90       break;
91     }
92 
93   return address;
94 }
95 
96 static SI
97 fr400_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
98 {
99   if (address & align_mask)
100     {
101       /* Make sure that this exception is not masked.  */
102       USI isr = GET_ISR ();
103       if (! GET_ISR_EMAM (isr))
104 	{
105 	  /* Bad alignment causes a data_access_error on fr400.  */
106 	  frv_queue_data_access_error_interrupt (current_cpu, address);
107 	}
108       address &= ~align_mask;
109     }
110   /* Nothing to check.  */
111   return address;
112 }
113 
114 static SI
115 fr500_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
116 {
117   if ((USI)address >= 0xfe000000 && (USI)address <= 0xfe003fff
118       || (USI)address >= 0xfe004000 && (USI)address <= 0xfe3fffff
119       || (USI)address >= 0xfe400000 && (USI)address <= 0xfe403fff
120       || (USI)address >= 0xfe404000 && (USI)address <= 0xfe7fffff)
121     frv_queue_data_access_exception_interrupt (current_cpu);
122 
123   return address;
124 }
125 
126 static SI
127 fr550_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
128 {
129   /* No alignment restrictions on fr550 */
130 
131   if ((USI)address >= 0xfe000000 && (USI)address <= 0xfe3fffff
132       || (USI)address >= 0xfe408000 && (USI)address <= 0xfe7fffff)
133     frv_queue_data_access_exception_interrupt (current_cpu);
134   else
135     {
136       USI hsr0 = GET_HSR0 ();
137       if (! GET_HSR0_RME (hsr0)
138 	  && (USI)address >= 0xfe400000 && (USI)address <= 0xfe407fff)
139 	frv_queue_data_access_exception_interrupt (current_cpu);
140     }
141 
142   return address;
143 }
144 
145 static SI
146 check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
147 {
148   SIM_DESC sd = CPU_STATE (current_cpu);
149   switch (STATE_ARCHITECTURE (sd)->mach)
150     {
151     case bfd_mach_fr400:
152     case bfd_mach_fr450:
153       address = fr400_check_readwrite_address (current_cpu, address,
154 						    align_mask);
155       break;
156     case bfd_mach_frvtomcat:
157     case bfd_mach_fr500:
158     case bfd_mach_frv:
159       address = fr500_check_readwrite_address (current_cpu, address,
160 						    align_mask);
161       break;
162     case bfd_mach_fr550:
163       address = fr550_check_readwrite_address (current_cpu, address,
164 					       align_mask);
165       break;
166     default:
167       break;
168     }
169 
170   return address;
171 }
172 
173 static PCADDR
174 fr400_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address,
175 			       int align_mask)
176 {
177   if (address & align_mask)
178     {
179       frv_queue_instruction_access_error_interrupt (current_cpu);
180       address &= ~align_mask;
181     }
182   else if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff)
183     frv_queue_instruction_access_error_interrupt (current_cpu);
184 
185   return address;
186 }
187 
188 static PCADDR
189 fr500_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address,
190 			       int align_mask)
191 {
192   if (address & align_mask)
193     {
194       frv_queue_mem_address_not_aligned_interrupt (current_cpu, address);
195       address &= ~align_mask;
196     }
197 
198   if ((USI)address >= 0xfeff0600 && (USI)address <= 0xfeff7fff
199       || (USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff)
200     frv_queue_instruction_access_error_interrupt (current_cpu);
201   else if ((USI)address >= 0xfe004000 && (USI)address <= 0xfe3fffff
202 	   || (USI)address >= 0xfe400000 && (USI)address <= 0xfe403fff
203 	   || (USI)address >= 0xfe404000 && (USI)address <= 0xfe7fffff)
204     frv_queue_instruction_access_exception_interrupt (current_cpu);
205   else
206     {
207       USI hsr0 = GET_HSR0 ();
208       if (! GET_HSR0_RME (hsr0)
209 	  && (USI)address >= 0xfe000000 && (USI)address <= 0xfe003fff)
210 	frv_queue_instruction_access_exception_interrupt (current_cpu);
211     }
212 
213   return address;
214 }
215 
216 static PCADDR
217 fr550_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address,
218 			       int align_mask)
219 {
220   address &= ~align_mask;
221 
222   if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff)
223     frv_queue_instruction_access_error_interrupt (current_cpu);
224   else if ((USI)address >= 0xfe008000 && (USI)address <= 0xfe7fffff)
225     frv_queue_instruction_access_exception_interrupt (current_cpu);
226   else
227     {
228       USI hsr0 = GET_HSR0 ();
229       if (! GET_HSR0_RME (hsr0)
230 	  && (USI)address >= 0xfe000000 && (USI)address <= 0xfe007fff)
231 	frv_queue_instruction_access_exception_interrupt (current_cpu);
232     }
233 
234   return address;
235 }
236 
237 static PCADDR
238 check_insn_read_address (SIM_CPU *current_cpu, PCADDR address, int align_mask)
239 {
240   SIM_DESC sd = CPU_STATE (current_cpu);
241   switch (STATE_ARCHITECTURE (sd)->mach)
242     {
243     case bfd_mach_fr400:
244     case bfd_mach_fr450:
245       address = fr400_check_insn_read_address (current_cpu, address,
246 					       align_mask);
247       break;
248     case bfd_mach_frvtomcat:
249     case bfd_mach_fr500:
250     case bfd_mach_frv:
251       address = fr500_check_insn_read_address (current_cpu, address,
252 					       align_mask);
253       break;
254     case bfd_mach_fr550:
255       address = fr550_check_insn_read_address (current_cpu, address,
256 					       align_mask);
257       break;
258     default:
259       break;
260     }
261 
262   return address;
263 }
264 
265 /* Memory reads.  */
266 QI
267 frvbf_read_mem_QI (SIM_CPU *current_cpu, IADDR pc, SI address)
268 {
269   USI hsr0 = GET_HSR0 ();
270   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
271 
272   /* Check for access exceptions.  */
273   address = check_data_read_address (current_cpu, address, 0);
274   address = check_readwrite_address (current_cpu, address, 0);
275 
276   /* If we need to count cycles, then the cache operation will be
277      initiated from the model profiling functions.
278      See frvbf_model_....  */
279   if (model_insn)
280     {
281       CPU_LOAD_ADDRESS (current_cpu) = address;
282       CPU_LOAD_LENGTH (current_cpu) = 1;
283       CPU_LOAD_SIGNED (current_cpu) = 1;
284       return 0xb7; /* any random value */
285     }
286 
287   if (GET_HSR0_DCE (hsr0))
288     {
289       int cycles;
290       cycles = frv_cache_read (cache, 0, address);
291       if (cycles != 0)
292 	return CACHE_RETURN_DATA (cache, 0, address, QI, 1);
293     }
294 
295   return GETMEMQI (current_cpu, pc, address);
296 }
297 
298 UQI
299 frvbf_read_mem_UQI (SIM_CPU *current_cpu, IADDR pc, SI address)
300 {
301   USI hsr0 = GET_HSR0 ();
302   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
303 
304   /* Check for access exceptions.  */
305   address = check_data_read_address (current_cpu, address, 0);
306   address = check_readwrite_address (current_cpu, address, 0);
307 
308   /* If we need to count cycles, then the cache operation will be
309      initiated from the model profiling functions.
310      See frvbf_model_....  */
311   if (model_insn)
312     {
313       CPU_LOAD_ADDRESS (current_cpu) = address;
314       CPU_LOAD_LENGTH (current_cpu) = 1;
315       CPU_LOAD_SIGNED (current_cpu) = 0;
316       return 0xb7; /* any random value */
317     }
318 
319   if (GET_HSR0_DCE (hsr0))
320     {
321       int cycles;
322       cycles = frv_cache_read (cache, 0, address);
323       if (cycles != 0)
324 	return CACHE_RETURN_DATA (cache, 0, address, UQI, 1);
325     }
326 
327   return GETMEMUQI (current_cpu, pc, address);
328 }
329 
330 /* Read a HI which spans two cache lines */
331 static HI
332 read_mem_unaligned_HI (SIM_CPU *current_cpu, IADDR pc, SI address)
333 {
334   HI value = frvbf_read_mem_QI (current_cpu, pc, address);
335   value <<= 8;
336   value |= frvbf_read_mem_UQI (current_cpu, pc, address + 1);
337   return T2H_2 (value);
338 }
339 
340 HI
341 frvbf_read_mem_HI (SIM_CPU *current_cpu, IADDR pc, SI address)
342 {
343   USI hsr0;
344   FRV_CACHE *cache;
345 
346   /* Check for access exceptions.  */
347   address = check_data_read_address (current_cpu, address, 1);
348   address = check_readwrite_address (current_cpu, address, 1);
349 
350   /* If we need to count cycles, then the cache operation will be
351      initiated from the model profiling functions.
352      See frvbf_model_....  */
353   hsr0 = GET_HSR0 ();
354   cache = CPU_DATA_CACHE (current_cpu);
355   if (model_insn)
356     {
357       CPU_LOAD_ADDRESS (current_cpu) = address;
358       CPU_LOAD_LENGTH (current_cpu) = 2;
359       CPU_LOAD_SIGNED (current_cpu) = 1;
360       return 0xb711; /* any random value */
361     }
362 
363   if (GET_HSR0_DCE (hsr0))
364     {
365       int cycles;
366       /* Handle access which crosses cache line boundary */
367       SIM_DESC sd = CPU_STATE (current_cpu);
368       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
369 	{
370 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 2))
371 	    return read_mem_unaligned_HI (current_cpu, pc, address);
372 	}
373       cycles = frv_cache_read (cache, 0, address);
374       if (cycles != 0)
375 	return CACHE_RETURN_DATA (cache, 0, address, HI, 2);
376     }
377 
378   return GETMEMHI (current_cpu, pc, address);
379 }
380 
381 UHI
382 frvbf_read_mem_UHI (SIM_CPU *current_cpu, IADDR pc, SI address)
383 {
384   USI hsr0;
385   FRV_CACHE *cache;
386 
387   /* Check for access exceptions.  */
388   address = check_data_read_address (current_cpu, address, 1);
389   address = check_readwrite_address (current_cpu, address, 1);
390 
391   /* If we need to count cycles, then the cache operation will be
392      initiated from the model profiling functions.
393      See frvbf_model_....  */
394   hsr0 = GET_HSR0 ();
395   cache = CPU_DATA_CACHE (current_cpu);
396   if (model_insn)
397     {
398       CPU_LOAD_ADDRESS (current_cpu) = address;
399       CPU_LOAD_LENGTH (current_cpu) = 2;
400       CPU_LOAD_SIGNED (current_cpu) = 0;
401       return 0xb711; /* any random value */
402     }
403 
404   if (GET_HSR0_DCE (hsr0))
405     {
406       int cycles;
407       /* Handle access which crosses cache line boundary */
408       SIM_DESC sd = CPU_STATE (current_cpu);
409       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
410 	{
411 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 2))
412 	    return read_mem_unaligned_HI (current_cpu, pc, address);
413 	}
414       cycles = frv_cache_read (cache, 0, address);
415       if (cycles != 0)
416 	return CACHE_RETURN_DATA (cache, 0, address, UHI, 2);
417     }
418 
419   return GETMEMUHI (current_cpu, pc, address);
420 }
421 
422 /* Read a SI which spans two cache lines */
423 static SI
424 read_mem_unaligned_SI (SIM_CPU *current_cpu, IADDR pc, SI address)
425 {
426   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
427   unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
428   char valarray[4];
429   SI SIvalue;
430   HI HIvalue;
431 
432   switch (hi_len)
433     {
434     case 1:
435       valarray[0] = frvbf_read_mem_QI (current_cpu, pc, address);
436       SIvalue = frvbf_read_mem_SI (current_cpu, pc, address + 1);
437       SIvalue = H2T_4 (SIvalue);
438       memcpy (valarray + 1, (char*)&SIvalue, 3);
439       break;
440     case 2:
441       HIvalue = frvbf_read_mem_HI (current_cpu, pc, address);
442       HIvalue = H2T_2 (HIvalue);
443       memcpy (valarray, (char*)&HIvalue, 2);
444       HIvalue = frvbf_read_mem_HI (current_cpu, pc, address + 2);
445       HIvalue = H2T_2 (HIvalue);
446       memcpy (valarray + 2, (char*)&HIvalue, 2);
447       break;
448     case 3:
449       SIvalue = frvbf_read_mem_SI (current_cpu, pc, address - 1);
450       SIvalue = H2T_4 (SIvalue);
451       memcpy (valarray, (char*)&SIvalue, 3);
452       valarray[3] = frvbf_read_mem_QI (current_cpu, pc, address + 3);
453       break;
454     default:
455       abort (); /* can't happen */
456     }
457   return T2H_4 (*(SI*)valarray);
458 }
459 
460 SI
461 frvbf_read_mem_SI (SIM_CPU *current_cpu, IADDR pc, SI address)
462 {
463   FRV_CACHE *cache;
464   USI hsr0;
465 
466   /* Check for access exceptions.  */
467   address = check_data_read_address (current_cpu, address, 3);
468   address = check_readwrite_address (current_cpu, address, 3);
469 
470   hsr0 = GET_HSR0 ();
471   cache = CPU_DATA_CACHE (current_cpu);
472   /* If we need to count cycles, then the cache operation will be
473      initiated from the model profiling functions.
474      See frvbf_model_....  */
475   if (model_insn)
476     {
477       CPU_LOAD_ADDRESS (current_cpu) = address;
478       CPU_LOAD_LENGTH (current_cpu) = 4;
479       return 0x37111319; /* any random value */
480     }
481 
482   if (GET_HSR0_DCE (hsr0))
483     {
484       int cycles;
485       /* Handle access which crosses cache line boundary */
486       SIM_DESC sd = CPU_STATE (current_cpu);
487       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
488 	{
489 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 4))
490 	    return read_mem_unaligned_SI (current_cpu, pc, address);
491 	}
492       cycles = frv_cache_read (cache, 0, address);
493       if (cycles != 0)
494 	return CACHE_RETURN_DATA (cache, 0, address, SI, 4);
495     }
496 
497   return GETMEMSI (current_cpu, pc, address);
498 }
499 
500 SI
501 frvbf_read_mem_WI (SIM_CPU *current_cpu, IADDR pc, SI address)
502 {
503   return frvbf_read_mem_SI (current_cpu, pc, address);
504 }
505 
506 /* Read a SI which spans two cache lines */
507 static DI
508 read_mem_unaligned_DI (SIM_CPU *current_cpu, IADDR pc, SI address)
509 {
510   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
511   unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
512   DI value, value1;
513 
514   switch (hi_len)
515     {
516     case 1:
517       value = frvbf_read_mem_QI (current_cpu, pc, address);
518       value <<= 56;
519       value1 = frvbf_read_mem_DI (current_cpu, pc, address + 1);
520       value1 = H2T_8 (value1);
521       value |= value1 & ((DI)0x00ffffff << 32);
522       value |= value1 & 0xffffffffu;
523       break;
524     case 2:
525       value = frvbf_read_mem_HI (current_cpu, pc, address);
526       value = H2T_2 (value);
527       value <<= 48;
528       value1 = frvbf_read_mem_DI (current_cpu, pc, address + 2);
529       value1 = H2T_8 (value1);
530       value |= value1 & ((DI)0x0000ffff << 32);
531       value |= value1 & 0xffffffffu;
532       break;
533     case 3:
534       value = frvbf_read_mem_SI (current_cpu, pc, address - 1);
535       value = H2T_4 (value);
536       value <<= 40;
537       value1 = frvbf_read_mem_DI (current_cpu, pc, address + 3);
538       value1 = H2T_8 (value1);
539       value |= value1 & ((DI)0x000000ff << 32);
540       value |= value1 & 0xffffffffu;
541       break;
542     case 4:
543       value = frvbf_read_mem_SI (current_cpu, pc, address);
544       value = H2T_4 (value);
545       value <<= 32;
546       value1 = frvbf_read_mem_SI (current_cpu, pc, address + 4);
547       value1 = H2T_4 (value1);
548       value |= value1 & 0xffffffffu;
549       break;
550     case 5:
551       value = frvbf_read_mem_DI (current_cpu, pc, address - 3);
552       value = H2T_8 (value);
553       value <<= 24;
554       value1 = frvbf_read_mem_SI (current_cpu, pc, address + 5);
555       value1 = H2T_4 (value1);
556       value |= value1 & 0x00ffffff;
557       break;
558     case 6:
559       value = frvbf_read_mem_DI (current_cpu, pc, address - 2);
560       value = H2T_8 (value);
561       value <<= 16;
562       value1 = frvbf_read_mem_HI (current_cpu, pc, address + 6);
563       value1 = H2T_2 (value1);
564       value |= value1 & 0x0000ffff;
565       break;
566     case 7:
567       value = frvbf_read_mem_DI (current_cpu, pc, address - 1);
568       value = H2T_8 (value);
569       value <<= 8;
570       value1 = frvbf_read_mem_QI (current_cpu, pc, address + 7);
571       value |= value1 & 0x000000ff;
572       break;
573     default:
574       abort (); /* can't happen */
575     }
576   return T2H_8 (value);
577 }
578 
579 DI
580 frvbf_read_mem_DI (SIM_CPU *current_cpu, IADDR pc, SI address)
581 {
582   USI hsr0;
583   FRV_CACHE *cache;
584 
585   /* Check for access exceptions.  */
586   address = check_data_read_address (current_cpu, address, 7);
587   address = check_readwrite_address (current_cpu, address, 7);
588 
589   /* If we need to count cycles, then the cache operation will be
590      initiated from the model profiling functions.
591      See frvbf_model_....  */
592   hsr0 = GET_HSR0 ();
593   cache = CPU_DATA_CACHE (current_cpu);
594   if (model_insn)
595     {
596       CPU_LOAD_ADDRESS (current_cpu) = address;
597       CPU_LOAD_LENGTH (current_cpu) = 8;
598       return 0x37111319; /* any random value */
599     }
600 
601   if (GET_HSR0_DCE (hsr0))
602     {
603       int cycles;
604       /* Handle access which crosses cache line boundary */
605       SIM_DESC sd = CPU_STATE (current_cpu);
606       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
607 	{
608 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
609 	    return read_mem_unaligned_DI (current_cpu, pc, address);
610 	}
611       cycles = frv_cache_read (cache, 0, address);
612       if (cycles != 0)
613 	return CACHE_RETURN_DATA (cache, 0, address, DI, 8);
614     }
615 
616   return GETMEMDI (current_cpu, pc, address);
617 }
618 
619 DF
620 frvbf_read_mem_DF (SIM_CPU *current_cpu, IADDR pc, SI address)
621 {
622   USI hsr0;
623   FRV_CACHE *cache;
624 
625   /* Check for access exceptions.  */
626   address = check_data_read_address (current_cpu, address, 7);
627   address = check_readwrite_address (current_cpu, address, 7);
628 
629   /* If we need to count cycles, then the cache operation will be
630      initiated from the model profiling functions.
631      See frvbf_model_....  */
632   hsr0 = GET_HSR0 ();
633   cache = CPU_DATA_CACHE (current_cpu);
634   if (model_insn)
635     {
636       CPU_LOAD_ADDRESS (current_cpu) = address;
637       CPU_LOAD_LENGTH (current_cpu) = 8;
638       return 0x37111319; /* any random value */
639     }
640 
641   if (GET_HSR0_DCE (hsr0))
642     {
643       int cycles;
644       /* Handle access which crosses cache line boundary */
645       SIM_DESC sd = CPU_STATE (current_cpu);
646       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
647 	{
648 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
649 	    return read_mem_unaligned_DI (current_cpu, pc, address);
650 	}
651       cycles = frv_cache_read (cache, 0, address);
652       if (cycles != 0)
653 	return CACHE_RETURN_DATA (cache, 0, address, DF, 8);
654     }
655 
656   return GETMEMDF (current_cpu, pc, address);
657 }
658 
659 USI
660 frvbf_read_imem_USI (SIM_CPU *current_cpu, PCADDR vpc)
661 {
662   USI hsr0;
663   vpc = check_insn_read_address (current_cpu, vpc, 3);
664 
665   hsr0 = GET_HSR0 ();
666   if (GET_HSR0_ICE (hsr0))
667     {
668       FRV_CACHE *cache;
669       USI value;
670 
671       /* We don't want this to show up in the cache statistics.  That read
672 	 is done in frvbf_simulate_insn_prefetch.  So read the cache or memory
673 	 passively here.  */
674       cache = CPU_INSN_CACHE (current_cpu);
675       if (frv_cache_read_passive_SI (cache, vpc, &value))
676 	return value;
677     }
678   return sim_core_read_unaligned_4 (current_cpu, vpc, read_map, vpc);
679 }
680 
681 static SI
682 fr400_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
683 {
684   if (align_mask == 7
685       && address >= 0xfe800000 && address <= 0xfeffffff)
686     frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR);
687 
688   return address;
689 }
690 
691 static SI
692 fr500_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
693 {
694   if (address & align_mask)
695     {
696       struct frv_interrupt_queue_element *item =
697 	frv_queue_mem_address_not_aligned_interrupt (current_cpu, address);
698       /* Record the correct vliw slot with the interrupt.  */
699       if (item != NULL)
700 	item->slot = frv_interrupt_state.slot;
701       address &= ~align_mask;
702     }
703   if (address >= 0xfeff0600 && address <= 0xfeff7fff
704       || address >= 0xfe800000 && address <= 0xfefeffff)
705     frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR);
706 
707   return address;
708 }
709 
710 static SI
711 fr550_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
712 {
713   if ((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff
714       || (align_mask > 0x3
715 	  && ((USI)address >= 0xfeff0000 && (USI)address <= 0xfeffffff)))
716     frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR);
717 
718   return address;
719 }
720 
721 static SI
722 check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
723 {
724   SIM_DESC sd = CPU_STATE (current_cpu);
725   switch (STATE_ARCHITECTURE (sd)->mach)
726     {
727     case bfd_mach_fr400:
728     case bfd_mach_fr450:
729       address = fr400_check_write_address (current_cpu, address, align_mask);
730       break;
731     case bfd_mach_frvtomcat:
732     case bfd_mach_fr500:
733     case bfd_mach_frv:
734       address = fr500_check_write_address (current_cpu, address, align_mask);
735       break;
736     case bfd_mach_fr550:
737       address = fr550_check_write_address (current_cpu, address, align_mask);
738       break;
739     default:
740       break;
741     }
742   return address;
743 }
744 
745 void
746 frvbf_write_mem_QI (SIM_CPU *current_cpu, IADDR pc, SI address, QI value)
747 {
748   USI hsr0;
749   hsr0 = GET_HSR0 ();
750   if (GET_HSR0_DCE (hsr0))
751     sim_queue_fn_mem_qi_write (current_cpu, frvbf_mem_set_QI, address, value);
752   else
753     sim_queue_mem_qi_write (current_cpu, address, value);
754   frv_set_write_queue_slot (current_cpu);
755 }
756 
757 void
758 frvbf_write_mem_UQI (SIM_CPU *current_cpu, IADDR pc, SI address, UQI value)
759 {
760   frvbf_write_mem_QI (current_cpu, pc, address, value);
761 }
762 
763 void
764 frvbf_write_mem_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value)
765 {
766   USI hsr0;
767   hsr0 = GET_HSR0 ();
768   if (GET_HSR0_DCE (hsr0))
769     sim_queue_fn_mem_hi_write (current_cpu, frvbf_mem_set_HI, address, value);
770   else
771     sim_queue_mem_hi_write (current_cpu, address, value);
772   frv_set_write_queue_slot (current_cpu);
773 }
774 
775 void
776 frvbf_write_mem_UHI (SIM_CPU *current_cpu, IADDR pc, SI address, UHI value)
777 {
778   frvbf_write_mem_HI (current_cpu, pc, address, value);
779 }
780 
781 void
782 frvbf_write_mem_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
783 {
784   USI hsr0;
785   hsr0 = GET_HSR0 ();
786   if (GET_HSR0_DCE (hsr0))
787     sim_queue_fn_mem_si_write (current_cpu, frvbf_mem_set_SI, address, value);
788   else
789     sim_queue_mem_si_write (current_cpu, address, value);
790   frv_set_write_queue_slot (current_cpu);
791 }
792 
793 void
794 frvbf_write_mem_WI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
795 {
796   frvbf_write_mem_SI (current_cpu, pc, address, value);
797 }
798 
799 void
800 frvbf_write_mem_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value)
801 {
802   USI hsr0;
803   hsr0 = GET_HSR0 ();
804   if (GET_HSR0_DCE (hsr0))
805     sim_queue_fn_mem_di_write (current_cpu, frvbf_mem_set_DI, address, value);
806   else
807     sim_queue_mem_di_write (current_cpu, address, value);
808   frv_set_write_queue_slot (current_cpu);
809 }
810 
811 void
812 frvbf_write_mem_DF (SIM_CPU *current_cpu, IADDR pc, SI address, DF value)
813 {
814   USI hsr0;
815   hsr0 = GET_HSR0 ();
816   if (GET_HSR0_DCE (hsr0))
817     sim_queue_fn_mem_df_write (current_cpu, frvbf_mem_set_DF, address, value);
818   else
819     sim_queue_mem_df_write (current_cpu, address, value);
820   frv_set_write_queue_slot (current_cpu);
821 }
822 
823 /* Memory writes.  These do the actual writing through the cache.  */
824 void
825 frvbf_mem_set_QI (SIM_CPU *current_cpu, IADDR pc, SI address, QI value)
826 {
827   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
828 
829   /* Check for access errors.  */
830   address = check_write_address (current_cpu, address, 0);
831   address = check_readwrite_address (current_cpu, address, 0);
832 
833   /* If we need to count cycles, then submit the write request to the cache
834      and let it prioritize the request.  Otherwise perform the write now.  */
835   if (model_insn)
836     {
837       int slot = UNIT_I0;
838       frv_cache_request_store (cache, address, slot, (char *)&value,
839 			       sizeof (value));
840     }
841   else
842     frv_cache_write (cache, address, (char *)&value, sizeof (value));
843 }
844 
845 /* Write a HI which spans two cache lines */
846 static void
847 mem_set_unaligned_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value)
848 {
849   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
850   /* value is already in target byte order */
851   frv_cache_write (cache, address, (char *)&value, 1);
852   frv_cache_write (cache, address + 1, ((char *)&value + 1), 1);
853 }
854 
855 void
856 frvbf_mem_set_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value)
857 {
858   FRV_CACHE *cache;
859 
860   /* Check for access errors.  */
861   address = check_write_address (current_cpu, address, 1);
862   address = check_readwrite_address (current_cpu, address, 1);
863 
864   /* If we need to count cycles, then submit the write request to the cache
865      and let it prioritize the request.  Otherwise perform the write now.  */
866   value = H2T_2 (value);
867   cache = CPU_DATA_CACHE (current_cpu);
868   if (model_insn)
869     {
870       int slot = UNIT_I0;
871       frv_cache_request_store (cache, address, slot,
872 			       (char *)&value, sizeof (value));
873     }
874   else
875     {
876       /* Handle access which crosses cache line boundary */
877       SIM_DESC sd = CPU_STATE (current_cpu);
878       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
879 	{
880 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 2))
881 	    {
882 	      mem_set_unaligned_HI (current_cpu, pc, address, value);
883 	      return;
884 	    }
885 	}
886       frv_cache_write (cache, address, (char *)&value, sizeof (value));
887     }
888 }
889 
890 /* Write a SI which spans two cache lines */
891 static void
892 mem_set_unaligned_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
893 {
894   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
895   unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
896   /* value is already in target byte order */
897   frv_cache_write (cache, address, (char *)&value, hi_len);
898   frv_cache_write (cache, address + hi_len, (char *)&value + hi_len, 4 - hi_len);
899 }
900 
901 void
902 frvbf_mem_set_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
903 {
904   FRV_CACHE *cache;
905 
906   /* Check for access errors.  */
907   address = check_write_address (current_cpu, address, 3);
908   address = check_readwrite_address (current_cpu, address, 3);
909 
910   /* If we need to count cycles, then submit the write request to the cache
911      and let it prioritize the request.  Otherwise perform the write now.  */
912   cache = CPU_DATA_CACHE (current_cpu);
913   value = H2T_4 (value);
914   if (model_insn)
915     {
916       int slot = UNIT_I0;
917       frv_cache_request_store (cache, address, slot,
918 			       (char *)&value, sizeof (value));
919     }
920   else
921     {
922       /* Handle access which crosses cache line boundary */
923       SIM_DESC sd = CPU_STATE (current_cpu);
924       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
925 	{
926 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 4))
927 	    {
928 	      mem_set_unaligned_SI (current_cpu, pc, address, value);
929 	      return;
930 	    }
931 	}
932       frv_cache_write (cache, address, (char *)&value, sizeof (value));
933     }
934 }
935 
936 /* Write a DI which spans two cache lines */
937 static void
938 mem_set_unaligned_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value)
939 {
940   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
941   unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
942   /* value is already in target byte order */
943   frv_cache_write (cache, address, (char *)&value, hi_len);
944   frv_cache_write (cache, address + hi_len, (char *)&value + hi_len, 8 - hi_len);
945 }
946 
947 void
948 frvbf_mem_set_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value)
949 {
950   FRV_CACHE *cache;
951 
952   /* Check for access errors.  */
953   address = check_write_address (current_cpu, address, 7);
954   address = check_readwrite_address (current_cpu, address, 7);
955 
956   /* If we need to count cycles, then submit the write request to the cache
957      and let it prioritize the request.  Otherwise perform the write now.  */
958   value = H2T_8 (value);
959   cache = CPU_DATA_CACHE (current_cpu);
960   if (model_insn)
961     {
962       int slot = UNIT_I0;
963       frv_cache_request_store (cache, address, slot,
964 			       (char *)&value, sizeof (value));
965     }
966   else
967     {
968       /* Handle access which crosses cache line boundary */
969       SIM_DESC sd = CPU_STATE (current_cpu);
970       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
971 	{
972 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
973 	    {
974 	      mem_set_unaligned_DI (current_cpu, pc, address, value);
975 	      return;
976 	    }
977 	}
978       frv_cache_write (cache, address, (char *)&value, sizeof (value));
979     }
980 }
981 
982 void
983 frvbf_mem_set_DF (SIM_CPU *current_cpu, IADDR pc, SI address, DF value)
984 {
985   FRV_CACHE *cache;
986 
987   /* Check for access errors.  */
988   address = check_write_address (current_cpu, address, 7);
989   address = check_readwrite_address (current_cpu, address, 7);
990 
991   /* If we need to count cycles, then submit the write request to the cache
992      and let it prioritize the request.  Otherwise perform the write now.  */
993   value = H2T_8 (value);
994   cache = CPU_DATA_CACHE (current_cpu);
995   if (model_insn)
996     {
997       int slot = UNIT_I0;
998       frv_cache_request_store (cache, address, slot,
999 			       (char *)&value, sizeof (value));
1000     }
1001   else
1002     {
1003       /* Handle access which crosses cache line boundary */
1004       SIM_DESC sd = CPU_STATE (current_cpu);
1005       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
1006 	{
1007 	  if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
1008 	    {
1009 	      mem_set_unaligned_DI (current_cpu, pc, address, value);
1010 	      return;
1011 	    }
1012 	}
1013       frv_cache_write (cache, address, (char *)&value, sizeof (value));
1014     }
1015 }
1016 
1017 void
1018 frvbf_mem_set_XI (SIM_CPU *current_cpu, IADDR pc, SI address, SI *value)
1019 {
1020   int i;
1021   FRV_CACHE *cache;
1022 
1023   /* Check for access errors.  */
1024   address = check_write_address (current_cpu, address, 0xf);
1025   address = check_readwrite_address (current_cpu, address, 0xf);
1026 
1027   /* TODO -- reverse word order as well?  */
1028   for (i = 0; i < 4; ++i)
1029     value[i] = H2T_4 (value[i]);
1030 
1031   /* If we need to count cycles, then submit the write request to the cache
1032      and let it prioritize the request.  Otherwise perform the write now.  */
1033   cache = CPU_DATA_CACHE (current_cpu);
1034   if (model_insn)
1035     {
1036       int slot = UNIT_I0;
1037       frv_cache_request_store (cache, address, slot, (char*)value, 16);
1038     }
1039   else
1040     frv_cache_write (cache, address, (char*)value, 16);
1041 }
1042 
1043 /* Record the current VLIW slot on the element at the top of the write queue.
1044 */
1045 void
1046 frv_set_write_queue_slot (SIM_CPU *current_cpu)
1047 {
1048   FRV_VLIW *vliw = CPU_VLIW (current_cpu);
1049   int slot = vliw->next_slot - 1;
1050   CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu);
1051   int ix = CGEN_WRITE_QUEUE_INDEX (q) - 1;
1052   CGEN_WRITE_QUEUE_ELEMENT *item = CGEN_WRITE_QUEUE_ELEMENT (q, ix);
1053   CGEN_WRITE_QUEUE_ELEMENT_PIPE (item) = (*vliw->current_vliw)[slot];
1054 }
1055