1/* frv memory model.
2   Copyright (C) 1999, 2000, 2001, 2003, 2007 Free Software Foundation, Inc.
3   Contributed by Red Hat
4
5This file is part of the GNU simulators.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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 */
29static SI
30fr400_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
41static SI
42fr500_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
57static SI
58fr550_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
68static SI
69check_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
96static SI
97fr400_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
114static SI
115fr500_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
126static SI
127fr550_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
145static SI
146check_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
173static PCADDR
174fr400_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
188static PCADDR
189fr500_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
216static PCADDR
217fr550_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
237static PCADDR
238check_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.  */
266QI
267frvbf_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
298UQI
299frvbf_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 */
331static HI
332read_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
340HI
341frvbf_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
381UHI
382frvbf_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 */
423static SI
424read_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
460SI
461frvbf_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
500SI
501frvbf_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 */
507static DI
508read_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
579DI
580frvbf_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
619DF
620frvbf_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
659USI
660frvbf_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
681static SI
682fr400_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
691static SI
692fr500_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
710static SI
711fr550_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
721static SI
722check_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
745void
746frvbf_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
757void
758frvbf_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
763void
764frvbf_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
775void
776frvbf_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
781void
782frvbf_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
793void
794frvbf_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
799void
800frvbf_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
811void
812frvbf_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.  */
824void
825frvbf_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 */
846static void
847mem_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
855void
856frvbf_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 */
891static void
892mem_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
901void
902frvbf_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 */
937static void
938mem_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
947void
948frvbf_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
982void
983frvbf_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
1017void
1018frvbf_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*/
1045void
1046frv_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