Automatic date update in version.in
[binutils-gdb.git] / sim / frv / memory.c
blob062eeaed7ad292bdff51affd505bc441b2662ed8
1 /* frv memory model.
2 Copyright (C) 1999-2023 Free Software Foundation, Inc.
3 Contributed by Red Hat
5 This file is part of the GNU simulators.
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.
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.
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/>. */
20 /* This must come before any other includes. */
21 #include "defs.h"
23 #define WANT_CPU frvbf
24 #define WANT_CPU_FRVBF
26 #include "sim-main.h"
27 #include "cgen-mem.h"
28 #include "bfd.h"
29 #include <stdlib.h>
31 /* Check for alignment and access restrictions. Return the corrected address.
33 static SI
34 fr400_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
36 /* Check access restrictions for double word loads only. */
37 if (align_mask == 7)
39 if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff)
40 frv_queue_data_access_error_interrupt (current_cpu, address);
42 return address;
45 static SI
46 fr500_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
48 if (address & align_mask)
50 frv_queue_mem_address_not_aligned_interrupt (current_cpu, address);
51 address &= ~align_mask;
54 if (((USI)address >= 0xfeff0600 && (USI)address <= 0xfeff7fff)
55 || ((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff))
56 frv_queue_data_access_error_interrupt (current_cpu, address);
58 return address;
61 static SI
62 fr550_check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
64 if (((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff)
65 || (align_mask > 0x3
66 && ((USI)address >= 0xfeff0000 && (USI)address <= 0xfeffffff)))
67 frv_queue_data_access_error_interrupt (current_cpu, address);
69 return address;
72 static SI
73 check_data_read_address (SIM_CPU *current_cpu, SI address, int align_mask)
75 SIM_DESC sd = CPU_STATE (current_cpu);
76 switch (STATE_ARCHITECTURE (sd)->mach)
78 case bfd_mach_fr400:
79 case bfd_mach_fr450:
80 address = fr400_check_data_read_address (current_cpu, address,
81 align_mask);
82 break;
83 case bfd_mach_frvtomcat:
84 case bfd_mach_fr500:
85 case bfd_mach_frv:
86 address = fr500_check_data_read_address (current_cpu, address,
87 align_mask);
88 break;
89 case bfd_mach_fr550:
90 address = fr550_check_data_read_address (current_cpu, address,
91 align_mask);
92 break;
93 default:
94 break;
97 return address;
100 static SI
101 fr400_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
103 if (address & align_mask)
105 /* Make sure that this exception is not masked. */
106 USI isr = GET_ISR ();
107 if (! GET_ISR_EMAM (isr))
109 /* Bad alignment causes a data_access_error on fr400. */
110 frv_queue_data_access_error_interrupt (current_cpu, address);
112 address &= ~align_mask;
114 /* Nothing to check. */
115 return address;
118 static SI
119 fr500_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
121 if (((USI)address >= 0xfe000000 && (USI)address <= 0xfe003fff)
122 || ((USI)address >= 0xfe004000 && (USI)address <= 0xfe3fffff)
123 || ((USI)address >= 0xfe400000 && (USI)address <= 0xfe403fff)
124 || ((USI)address >= 0xfe404000 && (USI)address <= 0xfe7fffff))
125 frv_queue_data_access_exception_interrupt (current_cpu);
127 return address;
130 static SI
131 fr550_check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
133 /* No alignment restrictions on fr550 */
135 if (((USI)address >= 0xfe000000 && (USI)address <= 0xfe3fffff)
136 || ((USI)address >= 0xfe408000 && (USI)address <= 0xfe7fffff))
137 frv_queue_data_access_exception_interrupt (current_cpu);
138 else
140 USI hsr0 = GET_HSR0 ();
141 if (! GET_HSR0_RME (hsr0)
142 && ((USI)address >= 0xfe400000 && (USI)address <= 0xfe407fff))
143 frv_queue_data_access_exception_interrupt (current_cpu);
146 return address;
149 static SI
150 check_readwrite_address (SIM_CPU *current_cpu, SI address, int align_mask)
152 SIM_DESC sd = CPU_STATE (current_cpu);
153 switch (STATE_ARCHITECTURE (sd)->mach)
155 case bfd_mach_fr400:
156 case bfd_mach_fr450:
157 address = fr400_check_readwrite_address (current_cpu, address,
158 align_mask);
159 break;
160 case bfd_mach_frvtomcat:
161 case bfd_mach_fr500:
162 case bfd_mach_frv:
163 address = fr500_check_readwrite_address (current_cpu, address,
164 align_mask);
165 break;
166 case bfd_mach_fr550:
167 address = fr550_check_readwrite_address (current_cpu, address,
168 align_mask);
169 break;
170 default:
171 break;
174 return address;
177 static PCADDR
178 fr400_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address,
179 int align_mask)
181 if (address & align_mask)
183 frv_queue_instruction_access_error_interrupt (current_cpu);
184 address &= ~align_mask;
186 else if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff)
187 frv_queue_instruction_access_error_interrupt (current_cpu);
189 return address;
192 static PCADDR
193 fr500_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address,
194 int align_mask)
196 if (address & align_mask)
198 frv_queue_mem_address_not_aligned_interrupt (current_cpu, address);
199 address &= ~align_mask;
202 if (((USI)address >= 0xfeff0600 && (USI)address <= 0xfeff7fff)
203 || ((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff))
204 frv_queue_instruction_access_error_interrupt (current_cpu);
205 else if (((USI)address >= 0xfe004000 && (USI)address <= 0xfe3fffff)
206 || ((USI)address >= 0xfe400000 && (USI)address <= 0xfe403fff)
207 || ((USI)address >= 0xfe404000 && (USI)address <= 0xfe7fffff))
208 frv_queue_instruction_access_exception_interrupt (current_cpu);
209 else
211 USI hsr0 = GET_HSR0 ();
212 if (! GET_HSR0_RME (hsr0)
213 && ((USI)address >= 0xfe000000 && (USI)address <= 0xfe003fff))
214 frv_queue_instruction_access_exception_interrupt (current_cpu);
217 return address;
220 static PCADDR
221 fr550_check_insn_read_address (SIM_CPU *current_cpu, PCADDR address,
222 int align_mask)
224 address &= ~align_mask;
226 if ((USI)address >= 0xfe800000 && (USI)address <= 0xfeffffff)
227 frv_queue_instruction_access_error_interrupt (current_cpu);
228 else if ((USI)address >= 0xfe008000 && (USI)address <= 0xfe7fffff)
229 frv_queue_instruction_access_exception_interrupt (current_cpu);
230 else
232 USI hsr0 = GET_HSR0 ();
233 if (! GET_HSR0_RME (hsr0)
234 && (USI)address >= 0xfe000000 && (USI)address <= 0xfe007fff)
235 frv_queue_instruction_access_exception_interrupt (current_cpu);
238 return address;
241 static PCADDR
242 check_insn_read_address (SIM_CPU *current_cpu, PCADDR address, int align_mask)
244 SIM_DESC sd = CPU_STATE (current_cpu);
245 switch (STATE_ARCHITECTURE (sd)->mach)
247 case bfd_mach_fr400:
248 case bfd_mach_fr450:
249 address = fr400_check_insn_read_address (current_cpu, address,
250 align_mask);
251 break;
252 case bfd_mach_frvtomcat:
253 case bfd_mach_fr500:
254 case bfd_mach_frv:
255 address = fr500_check_insn_read_address (current_cpu, address,
256 align_mask);
257 break;
258 case bfd_mach_fr550:
259 address = fr550_check_insn_read_address (current_cpu, address,
260 align_mask);
261 break;
262 default:
263 break;
266 return address;
269 /* Memory reads. */
271 frvbf_read_mem_QI (SIM_CPU *current_cpu, IADDR pc, SI address)
273 USI hsr0 = GET_HSR0 ();
274 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
276 /* Check for access exceptions. */
277 address = check_data_read_address (current_cpu, address, 0);
278 address = check_readwrite_address (current_cpu, address, 0);
280 /* If we need to count cycles, then the cache operation will be
281 initiated from the model profiling functions.
282 See frvbf_model_.... */
283 if (model_insn)
285 CPU_LOAD_ADDRESS (current_cpu) = address;
286 CPU_LOAD_LENGTH (current_cpu) = 1;
287 CPU_LOAD_SIGNED (current_cpu) = 1;
288 return 0xb7; /* any random value */
291 if (GET_HSR0_DCE (hsr0))
293 int cycles;
294 cycles = frv_cache_read (cache, 0, address);
295 if (cycles != 0)
296 return CACHE_RETURN_DATA (cache, 0, address, QI, 1);
299 return GETMEMQI (current_cpu, pc, address);
303 frvbf_read_mem_UQI (SIM_CPU *current_cpu, IADDR pc, SI address)
305 USI hsr0 = GET_HSR0 ();
306 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
308 /* Check for access exceptions. */
309 address = check_data_read_address (current_cpu, address, 0);
310 address = check_readwrite_address (current_cpu, address, 0);
312 /* If we need to count cycles, then the cache operation will be
313 initiated from the model profiling functions.
314 See frvbf_model_.... */
315 if (model_insn)
317 CPU_LOAD_ADDRESS (current_cpu) = address;
318 CPU_LOAD_LENGTH (current_cpu) = 1;
319 CPU_LOAD_SIGNED (current_cpu) = 0;
320 return 0xb7; /* any random value */
323 if (GET_HSR0_DCE (hsr0))
325 int cycles;
326 cycles = frv_cache_read (cache, 0, address);
327 if (cycles != 0)
328 return CACHE_RETURN_DATA (cache, 0, address, UQI, 1);
331 return GETMEMUQI (current_cpu, pc, address);
334 /* Read a HI which spans two cache lines */
335 static HI
336 read_mem_unaligned_HI (SIM_CPU *current_cpu, IADDR pc, SI address)
338 HI value = frvbf_read_mem_QI (current_cpu, pc, address);
339 value <<= 8;
340 value |= frvbf_read_mem_UQI (current_cpu, pc, address + 1);
341 return T2H_2 (value);
345 frvbf_read_mem_HI (SIM_CPU *current_cpu, IADDR pc, SI address)
347 USI hsr0;
348 FRV_CACHE *cache;
350 /* Check for access exceptions. */
351 address = check_data_read_address (current_cpu, address, 1);
352 address = check_readwrite_address (current_cpu, address, 1);
354 /* If we need to count cycles, then the cache operation will be
355 initiated from the model profiling functions.
356 See frvbf_model_.... */
357 hsr0 = GET_HSR0 ();
358 cache = CPU_DATA_CACHE (current_cpu);
359 if (model_insn)
361 CPU_LOAD_ADDRESS (current_cpu) = address;
362 CPU_LOAD_LENGTH (current_cpu) = 2;
363 CPU_LOAD_SIGNED (current_cpu) = 1;
364 return 0xb711; /* any random value */
367 if (GET_HSR0_DCE (hsr0))
369 int cycles;
370 /* Handle access which crosses cache line boundary */
371 SIM_DESC sd = CPU_STATE (current_cpu);
372 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
374 if (DATA_CROSSES_CACHE_LINE (cache, address, 2))
375 return read_mem_unaligned_HI (current_cpu, pc, address);
377 cycles = frv_cache_read (cache, 0, address);
378 if (cycles != 0)
379 return CACHE_RETURN_DATA (cache, 0, address, HI, 2);
382 return GETMEMHI (current_cpu, pc, address);
386 frvbf_read_mem_UHI (SIM_CPU *current_cpu, IADDR pc, SI address)
388 USI hsr0;
389 FRV_CACHE *cache;
391 /* Check for access exceptions. */
392 address = check_data_read_address (current_cpu, address, 1);
393 address = check_readwrite_address (current_cpu, address, 1);
395 /* If we need to count cycles, then the cache operation will be
396 initiated from the model profiling functions.
397 See frvbf_model_.... */
398 hsr0 = GET_HSR0 ();
399 cache = CPU_DATA_CACHE (current_cpu);
400 if (model_insn)
402 CPU_LOAD_ADDRESS (current_cpu) = address;
403 CPU_LOAD_LENGTH (current_cpu) = 2;
404 CPU_LOAD_SIGNED (current_cpu) = 0;
405 return 0xb711; /* any random value */
408 if (GET_HSR0_DCE (hsr0))
410 int cycles;
411 /* Handle access which crosses cache line boundary */
412 SIM_DESC sd = CPU_STATE (current_cpu);
413 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
415 if (DATA_CROSSES_CACHE_LINE (cache, address, 2))
416 return read_mem_unaligned_HI (current_cpu, pc, address);
418 cycles = frv_cache_read (cache, 0, address);
419 if (cycles != 0)
420 return CACHE_RETURN_DATA (cache, 0, address, UHI, 2);
423 return GETMEMUHI (current_cpu, pc, address);
426 /* Read a SI which spans two cache lines */
427 static SI
428 read_mem_unaligned_SI (SIM_CPU *current_cpu, IADDR pc, SI address)
430 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
431 unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
432 char valarray[4];
433 SI SIvalue;
434 HI HIvalue;
436 switch (hi_len)
438 case 1:
439 valarray[0] = frvbf_read_mem_QI (current_cpu, pc, address);
440 SIvalue = frvbf_read_mem_SI (current_cpu, pc, address + 1);
441 SIvalue = H2T_4 (SIvalue);
442 memcpy (valarray + 1, (char*)&SIvalue, 3);
443 break;
444 case 2:
445 HIvalue = frvbf_read_mem_HI (current_cpu, pc, address);
446 HIvalue = H2T_2 (HIvalue);
447 memcpy (valarray, (char*)&HIvalue, 2);
448 HIvalue = frvbf_read_mem_HI (current_cpu, pc, address + 2);
449 HIvalue = H2T_2 (HIvalue);
450 memcpy (valarray + 2, (char*)&HIvalue, 2);
451 break;
452 case 3:
453 SIvalue = frvbf_read_mem_SI (current_cpu, pc, address - 1);
454 SIvalue = H2T_4 (SIvalue);
455 memcpy (valarray, (char*)&SIvalue, 3);
456 valarray[3] = frvbf_read_mem_QI (current_cpu, pc, address + 3);
457 break;
458 default:
459 abort (); /* can't happen */
461 return T2H_4 (*(SI*)valarray);
465 frvbf_read_mem_SI (SIM_CPU *current_cpu, IADDR pc, SI address)
467 FRV_CACHE *cache;
468 USI hsr0;
470 /* Check for access exceptions. */
471 address = check_data_read_address (current_cpu, address, 3);
472 address = check_readwrite_address (current_cpu, address, 3);
474 hsr0 = GET_HSR0 ();
475 cache = CPU_DATA_CACHE (current_cpu);
476 /* If we need to count cycles, then the cache operation will be
477 initiated from the model profiling functions.
478 See frvbf_model_.... */
479 if (model_insn)
481 CPU_LOAD_ADDRESS (current_cpu) = address;
482 CPU_LOAD_LENGTH (current_cpu) = 4;
483 return 0x37111319; /* any random value */
486 if (GET_HSR0_DCE (hsr0))
488 int cycles;
489 /* Handle access which crosses cache line boundary */
490 SIM_DESC sd = CPU_STATE (current_cpu);
491 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
493 if (DATA_CROSSES_CACHE_LINE (cache, address, 4))
494 return read_mem_unaligned_SI (current_cpu, pc, address);
496 cycles = frv_cache_read (cache, 0, address);
497 if (cycles != 0)
498 return CACHE_RETURN_DATA (cache, 0, address, SI, 4);
501 return GETMEMSI (current_cpu, pc, address);
505 frvbf_read_mem_WI (SIM_CPU *current_cpu, IADDR pc, SI address)
507 return frvbf_read_mem_SI (current_cpu, pc, address);
510 /* Read a SI which spans two cache lines */
511 static DI
512 read_mem_unaligned_DI (SIM_CPU *current_cpu, IADDR pc, SI address)
514 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
515 unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
516 DI value, value1;
518 switch (hi_len)
520 case 1:
521 value = frvbf_read_mem_QI (current_cpu, pc, address);
522 value <<= 56;
523 value1 = frvbf_read_mem_DI (current_cpu, pc, address + 1);
524 value1 = H2T_8 (value1);
525 value |= value1 & ((DI)0x00ffffff << 32);
526 value |= value1 & 0xffffffffu;
527 break;
528 case 2:
529 value = frvbf_read_mem_HI (current_cpu, pc, address);
530 value = H2T_2 (value);
531 value <<= 48;
532 value1 = frvbf_read_mem_DI (current_cpu, pc, address + 2);
533 value1 = H2T_8 (value1);
534 value |= value1 & ((DI)0x0000ffff << 32);
535 value |= value1 & 0xffffffffu;
536 break;
537 case 3:
538 value = frvbf_read_mem_SI (current_cpu, pc, address - 1);
539 value = H2T_4 (value);
540 value <<= 40;
541 value1 = frvbf_read_mem_DI (current_cpu, pc, address + 3);
542 value1 = H2T_8 (value1);
543 value |= value1 & ((DI)0x000000ff << 32);
544 value |= value1 & 0xffffffffu;
545 break;
546 case 4:
547 value = frvbf_read_mem_SI (current_cpu, pc, address);
548 value = H2T_4 (value);
549 value <<= 32;
550 value1 = frvbf_read_mem_SI (current_cpu, pc, address + 4);
551 value1 = H2T_4 (value1);
552 value |= value1 & 0xffffffffu;
553 break;
554 case 5:
555 value = frvbf_read_mem_DI (current_cpu, pc, address - 3);
556 value = H2T_8 (value);
557 value <<= 24;
558 value1 = frvbf_read_mem_SI (current_cpu, pc, address + 5);
559 value1 = H2T_4 (value1);
560 value |= value1 & 0x00ffffff;
561 break;
562 case 6:
563 value = frvbf_read_mem_DI (current_cpu, pc, address - 2);
564 value = H2T_8 (value);
565 value <<= 16;
566 value1 = frvbf_read_mem_HI (current_cpu, pc, address + 6);
567 value1 = H2T_2 (value1);
568 value |= value1 & 0x0000ffff;
569 break;
570 case 7:
571 value = frvbf_read_mem_DI (current_cpu, pc, address - 1);
572 value = H2T_8 (value);
573 value <<= 8;
574 value1 = frvbf_read_mem_QI (current_cpu, pc, address + 7);
575 value |= value1 & 0x000000ff;
576 break;
577 default:
578 abort (); /* can't happen */
580 return T2H_8 (value);
584 frvbf_read_mem_DI (SIM_CPU *current_cpu, IADDR pc, SI address)
586 USI hsr0;
587 FRV_CACHE *cache;
589 /* Check for access exceptions. */
590 address = check_data_read_address (current_cpu, address, 7);
591 address = check_readwrite_address (current_cpu, address, 7);
593 /* If we need to count cycles, then the cache operation will be
594 initiated from the model profiling functions.
595 See frvbf_model_.... */
596 hsr0 = GET_HSR0 ();
597 cache = CPU_DATA_CACHE (current_cpu);
598 if (model_insn)
600 CPU_LOAD_ADDRESS (current_cpu) = address;
601 CPU_LOAD_LENGTH (current_cpu) = 8;
602 return 0x37111319; /* any random value */
605 if (GET_HSR0_DCE (hsr0))
607 int cycles;
608 /* Handle access which crosses cache line boundary */
609 SIM_DESC sd = CPU_STATE (current_cpu);
610 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
612 if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
613 return read_mem_unaligned_DI (current_cpu, pc, address);
615 cycles = frv_cache_read (cache, 0, address);
616 if (cycles != 0)
617 return CACHE_RETURN_DATA (cache, 0, address, DI, 8);
620 return GETMEMDI (current_cpu, pc, address);
624 frvbf_read_mem_DF (SIM_CPU *current_cpu, IADDR pc, SI address)
626 USI hsr0;
627 FRV_CACHE *cache;
629 /* Check for access exceptions. */
630 address = check_data_read_address (current_cpu, address, 7);
631 address = check_readwrite_address (current_cpu, address, 7);
633 /* If we need to count cycles, then the cache operation will be
634 initiated from the model profiling functions.
635 See frvbf_model_.... */
636 hsr0 = GET_HSR0 ();
637 cache = CPU_DATA_CACHE (current_cpu);
638 if (model_insn)
640 CPU_LOAD_ADDRESS (current_cpu) = address;
641 CPU_LOAD_LENGTH (current_cpu) = 8;
642 return 0x37111319; /* any random value */
645 if (GET_HSR0_DCE (hsr0))
647 int cycles;
648 /* Handle access which crosses cache line boundary */
649 SIM_DESC sd = CPU_STATE (current_cpu);
650 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
652 if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
653 return read_mem_unaligned_DI (current_cpu, pc, address);
655 cycles = frv_cache_read (cache, 0, address);
656 if (cycles != 0)
657 return CACHE_RETURN_DATA (cache, 0, address, DF, 8);
660 return GETMEMDF (current_cpu, pc, address);
664 frvbf_read_imem_USI (SIM_CPU *current_cpu, PCADDR vpc)
666 USI hsr0;
667 vpc = check_insn_read_address (current_cpu, vpc, 3);
669 hsr0 = GET_HSR0 ();
670 if (GET_HSR0_ICE (hsr0))
672 FRV_CACHE *cache;
673 USI value;
675 /* We don't want this to show up in the cache statistics. That read
676 is done in frvbf_simulate_insn_prefetch. So read the cache or memory
677 passively here. */
678 cache = CPU_INSN_CACHE (current_cpu);
679 if (frv_cache_read_passive_SI (cache, vpc, &value))
680 return value;
682 return sim_core_read_unaligned_4 (current_cpu, vpc, read_map, vpc);
685 static SI
686 fr400_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
688 if (align_mask == 7
689 && address >= 0xfe800000 && address <= 0xfeffffff)
690 frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR);
692 return address;
695 static SI
696 fr500_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
698 if (address & align_mask)
700 struct frv_interrupt_queue_element *item =
701 frv_queue_mem_address_not_aligned_interrupt (current_cpu, address);
702 /* Record the correct vliw slot with the interrupt. */
703 if (item != NULL)
704 item->slot = frv_interrupt_state.slot;
705 address &= ~align_mask;
707 if ((address >= 0xfeff0600 && address <= 0xfeff7fff)
708 || (address >= 0xfe800000 && address <= 0xfefeffff))
709 frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR);
711 return address;
714 static SI
715 fr550_check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
717 if (((USI)address >= 0xfe800000 && (USI)address <= 0xfefeffff)
718 || (align_mask > 0x3
719 && ((USI)address >= 0xfeff0000 && (USI)address <= 0xfeffffff)))
720 frv_queue_program_interrupt (current_cpu, FRV_DATA_STORE_ERROR);
722 return address;
725 static SI
726 check_write_address (SIM_CPU *current_cpu, SI address, int align_mask)
728 SIM_DESC sd = CPU_STATE (current_cpu);
729 switch (STATE_ARCHITECTURE (sd)->mach)
731 case bfd_mach_fr400:
732 case bfd_mach_fr450:
733 address = fr400_check_write_address (current_cpu, address, align_mask);
734 break;
735 case bfd_mach_frvtomcat:
736 case bfd_mach_fr500:
737 case bfd_mach_frv:
738 address = fr500_check_write_address (current_cpu, address, align_mask);
739 break;
740 case bfd_mach_fr550:
741 address = fr550_check_write_address (current_cpu, address, align_mask);
742 break;
743 default:
744 break;
746 return address;
749 void
750 frvbf_write_mem_QI (SIM_CPU *current_cpu, IADDR pc, SI address, QI value)
752 USI hsr0;
753 hsr0 = GET_HSR0 ();
754 if (GET_HSR0_DCE (hsr0))
755 sim_queue_fn_mem_qi_write (current_cpu, frvbf_mem_set_QI, address, value);
756 else
757 sim_queue_mem_qi_write (current_cpu, address, value);
758 frv_set_write_queue_slot (current_cpu);
761 void
762 frvbf_write_mem_UQI (SIM_CPU *current_cpu, IADDR pc, SI address, UQI value)
764 frvbf_write_mem_QI (current_cpu, pc, address, value);
767 void
768 frvbf_write_mem_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value)
770 USI hsr0;
771 hsr0 = GET_HSR0 ();
772 if (GET_HSR0_DCE (hsr0))
773 sim_queue_fn_mem_hi_write (current_cpu, frvbf_mem_set_HI, address, value);
774 else
775 sim_queue_mem_hi_write (current_cpu, address, value);
776 frv_set_write_queue_slot (current_cpu);
779 void
780 frvbf_write_mem_UHI (SIM_CPU *current_cpu, IADDR pc, SI address, UHI value)
782 frvbf_write_mem_HI (current_cpu, pc, address, value);
785 void
786 frvbf_write_mem_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
788 USI hsr0;
789 hsr0 = GET_HSR0 ();
790 if (GET_HSR0_DCE (hsr0))
791 sim_queue_fn_mem_si_write (current_cpu, frvbf_mem_set_SI, address, value);
792 else
793 sim_queue_mem_si_write (current_cpu, address, value);
794 frv_set_write_queue_slot (current_cpu);
797 void
798 frvbf_write_mem_WI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
800 frvbf_write_mem_SI (current_cpu, pc, address, value);
803 void
804 frvbf_write_mem_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value)
806 USI hsr0;
807 hsr0 = GET_HSR0 ();
808 if (GET_HSR0_DCE (hsr0))
809 sim_queue_fn_mem_di_write (current_cpu, frvbf_mem_set_DI, address, value);
810 else
811 sim_queue_mem_di_write (current_cpu, address, value);
812 frv_set_write_queue_slot (current_cpu);
815 void
816 frvbf_write_mem_DF (SIM_CPU *current_cpu, IADDR pc, SI address, DF value)
818 USI hsr0;
819 hsr0 = GET_HSR0 ();
820 if (GET_HSR0_DCE (hsr0))
821 sim_queue_fn_mem_df_write (current_cpu, frvbf_mem_set_DF, address, value);
822 else
823 sim_queue_mem_df_write (current_cpu, address, value);
824 frv_set_write_queue_slot (current_cpu);
827 /* Memory writes. These do the actual writing through the cache. */
828 void
829 frvbf_mem_set_QI (SIM_CPU *current_cpu, IADDR pc, SI address, QI value)
831 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
833 /* Check for access errors. */
834 address = check_write_address (current_cpu, address, 0);
835 address = check_readwrite_address (current_cpu, address, 0);
837 /* If we need to count cycles, then submit the write request to the cache
838 and let it prioritize the request. Otherwise perform the write now. */
839 if (model_insn)
841 int slot = UNIT_I0;
842 frv_cache_request_store (cache, address, slot, (char *)&value,
843 sizeof (value));
845 else
846 frv_cache_write (cache, address, (char *)&value, sizeof (value));
849 /* Write a HI which spans two cache lines */
850 static void
851 mem_set_unaligned_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value)
853 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
854 /* value is already in target byte order */
855 frv_cache_write (cache, address, (char *)&value, 1);
856 frv_cache_write (cache, address + 1, ((char *)&value + 1), 1);
859 void
860 frvbf_mem_set_HI (SIM_CPU *current_cpu, IADDR pc, SI address, HI value)
862 FRV_CACHE *cache;
864 /* Check for access errors. */
865 address = check_write_address (current_cpu, address, 1);
866 address = check_readwrite_address (current_cpu, address, 1);
868 /* If we need to count cycles, then submit the write request to the cache
869 and let it prioritize the request. Otherwise perform the write now. */
870 value = H2T_2 (value);
871 cache = CPU_DATA_CACHE (current_cpu);
872 if (model_insn)
874 int slot = UNIT_I0;
875 frv_cache_request_store (cache, address, slot,
876 (char *)&value, sizeof (value));
878 else
880 /* Handle access which crosses cache line boundary */
881 SIM_DESC sd = CPU_STATE (current_cpu);
882 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
884 if (DATA_CROSSES_CACHE_LINE (cache, address, 2))
886 mem_set_unaligned_HI (current_cpu, pc, address, value);
887 return;
890 frv_cache_write (cache, address, (char *)&value, sizeof (value));
894 /* Write a SI which spans two cache lines */
895 static void
896 mem_set_unaligned_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
898 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
899 unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
900 /* value is already in target byte order */
901 frv_cache_write (cache, address, (char *)&value, hi_len);
902 frv_cache_write (cache, address + hi_len, (char *)&value + hi_len, 4 - hi_len);
905 void
906 frvbf_mem_set_SI (SIM_CPU *current_cpu, IADDR pc, SI address, SI value)
908 FRV_CACHE *cache;
910 /* Check for access errors. */
911 address = check_write_address (current_cpu, address, 3);
912 address = check_readwrite_address (current_cpu, address, 3);
914 /* If we need to count cycles, then submit the write request to the cache
915 and let it prioritize the request. Otherwise perform the write now. */
916 cache = CPU_DATA_CACHE (current_cpu);
917 value = H2T_4 (value);
918 if (model_insn)
920 int slot = UNIT_I0;
921 frv_cache_request_store (cache, address, slot,
922 (char *)&value, sizeof (value));
924 else
926 /* Handle access which crosses cache line boundary */
927 SIM_DESC sd = CPU_STATE (current_cpu);
928 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
930 if (DATA_CROSSES_CACHE_LINE (cache, address, 4))
932 mem_set_unaligned_SI (current_cpu, pc, address, value);
933 return;
936 frv_cache_write (cache, address, (char *)&value, sizeof (value));
940 /* Write a DI which spans two cache lines */
941 static void
942 mem_set_unaligned_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value)
944 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
945 unsigned hi_len = cache->line_size - (address & (cache->line_size - 1));
946 /* value is already in target byte order */
947 frv_cache_write (cache, address, (char *)&value, hi_len);
948 frv_cache_write (cache, address + hi_len, (char *)&value + hi_len, 8 - hi_len);
951 void
952 frvbf_mem_set_DI (SIM_CPU *current_cpu, IADDR pc, SI address, DI value)
954 FRV_CACHE *cache;
956 /* Check for access errors. */
957 address = check_write_address (current_cpu, address, 7);
958 address = check_readwrite_address (current_cpu, address, 7);
960 /* If we need to count cycles, then submit the write request to the cache
961 and let it prioritize the request. Otherwise perform the write now. */
962 value = H2T_8 (value);
963 cache = CPU_DATA_CACHE (current_cpu);
964 if (model_insn)
966 int slot = UNIT_I0;
967 frv_cache_request_store (cache, address, slot,
968 (char *)&value, sizeof (value));
970 else
972 /* Handle access which crosses cache line boundary */
973 SIM_DESC sd = CPU_STATE (current_cpu);
974 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
976 if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
978 mem_set_unaligned_DI (current_cpu, pc, address, value);
979 return;
982 frv_cache_write (cache, address, (char *)&value, sizeof (value));
986 void
987 frvbf_mem_set_DF (SIM_CPU *current_cpu, IADDR pc, SI address, DF value)
989 FRV_CACHE *cache;
991 /* Check for access errors. */
992 address = check_write_address (current_cpu, address, 7);
993 address = check_readwrite_address (current_cpu, address, 7);
995 /* If we need to count cycles, then submit the write request to the cache
996 and let it prioritize the request. Otherwise perform the write now. */
997 value = H2T_8 (value);
998 cache = CPU_DATA_CACHE (current_cpu);
999 if (model_insn)
1001 int slot = UNIT_I0;
1002 frv_cache_request_store (cache, address, slot,
1003 (char *)&value, sizeof (value));
1005 else
1007 /* Handle access which crosses cache line boundary */
1008 SIM_DESC sd = CPU_STATE (current_cpu);
1009 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
1011 if (DATA_CROSSES_CACHE_LINE (cache, address, 8))
1013 mem_set_unaligned_DI (current_cpu, pc, address, value);
1014 return;
1017 frv_cache_write (cache, address, (char *)&value, sizeof (value));
1021 void
1022 frvbf_mem_set_XI (SIM_CPU *current_cpu, IADDR pc, SI address, SI *value)
1024 int i;
1025 FRV_CACHE *cache;
1027 /* Check for access errors. */
1028 address = check_write_address (current_cpu, address, 0xf);
1029 address = check_readwrite_address (current_cpu, address, 0xf);
1031 /* TODO -- reverse word order as well? */
1032 for (i = 0; i < 4; ++i)
1033 value[i] = H2T_4 (value[i]);
1035 /* If we need to count cycles, then submit the write request to the cache
1036 and let it prioritize the request. Otherwise perform the write now. */
1037 cache = CPU_DATA_CACHE (current_cpu);
1038 if (model_insn)
1040 int slot = UNIT_I0;
1041 frv_cache_request_store (cache, address, slot, (char*)value, 16);
1043 else
1044 frv_cache_write (cache, address, (char*)value, 16);
1047 /* Record the current VLIW slot on the element at the top of the write queue.
1049 void
1050 frv_set_write_queue_slot (SIM_CPU *current_cpu)
1052 FRV_VLIW *vliw = CPU_VLIW (current_cpu);
1053 int slot = vliw->next_slot - 1;
1054 CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu);
1055 int ix = CGEN_WRITE_QUEUE_INDEX (q) - 1;
1056 CGEN_WRITE_QUEUE_ELEMENT *item = CGEN_WRITE_QUEUE_ELEMENT (q, ix);
1057 CGEN_WRITE_QUEUE_ELEMENT_PIPE (item) = (*vliw->current_vliw)[slot];