OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [frv/] [traps.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/* frv trap support
2
   Copyright (C) 1999, 2000, 2001, 2003, 2007, 2008
3
   Free Software Foundation, Inc.
4
   Contributed by Red Hat.
5
 
6
This file is part of the GNU simulators.
7
 
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
12
 
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
 
21
#define WANT_CPU frvbf
22
#define WANT_CPU_FRVBF
23
 
24
#include "sim-main.h"
25
#include "targ-vals.h"
26
#include "cgen-engine.h"
27
#include "cgen-par.h"
28
#include "sim-fpu.h"
29
 
30
#include "bfd.h"
31
#include "libiberty.h"
32
 
33
CGEN_ATTR_VALUE_ENUM_TYPE frv_current_fm_slot;
34
 
35
/* The semantic code invokes this for invalid (unrecognized) instructions.  */
36
 
37
SEM_PC
38
sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
39
{
40
  frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
41
  return vpc;
42
}
43
 
44
/* Process an address exception.  */
45
 
46
void
47
frv_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
48
                  unsigned int map, int nr_bytes, address_word addr,
49
                  transfer_type transfer, sim_core_signals sig)
50
{
51
  if (sig == sim_core_unaligned_signal)
52
    {
53
      if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400
54
          || STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr450)
55
        frv_queue_data_access_error_interrupt (current_cpu, addr);
56
      else
57
        frv_queue_mem_address_not_aligned_interrupt (current_cpu, addr);
58
    }
59
 
60
  frv_term (sd);
61
  sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr, transfer, sig);
62
}
63
 
64
void
65
frv_sim_engine_halt_hook (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia)
66
{
67
  int i;
68
  if (current_cpu != NULL)
69
    CIA_SET (current_cpu, cia);
70
 
71
  /* Invalidate the insn and data caches of all cpus.  */
72
  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
73
    {
74
      current_cpu = STATE_CPU (sd, i);
75
      frv_cache_invalidate_all (CPU_INSN_CACHE (current_cpu), 0);
76
      frv_cache_invalidate_all (CPU_DATA_CACHE (current_cpu), 1);
77
    }
78
  frv_term (sd);
79
}
80
 
81
/* Read/write functions for system call interface.  */
82
 
83
static int
84
syscall_read_mem (host_callback *cb, struct cb_syscall *sc,
85
                  unsigned long taddr, char *buf, int bytes)
86
{
87
  SIM_DESC sd = (SIM_DESC) sc->p1;
88
  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
89
 
90
  frv_cache_invalidate_all (CPU_DATA_CACHE (cpu), 1);
91
  return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
92
}
93
 
94
static int
95
syscall_write_mem (host_callback *cb, struct cb_syscall *sc,
96
                   unsigned long taddr, const char *buf, int bytes)
97
{
98
  SIM_DESC sd = (SIM_DESC) sc->p1;
99
  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
100
 
101
  frv_cache_invalidate_all (CPU_INSN_CACHE (cpu), 0);
102
  frv_cache_invalidate_all (CPU_DATA_CACHE (cpu), 1);
103
  return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
104
}
105
 
106
/* Handle TRA and TIRA insns.  */
107
void
108
frv_itrap (SIM_CPU *current_cpu, PCADDR pc, USI base, SI offset)
109
{
110
  SIM_DESC sd = CPU_STATE (current_cpu);
111
  host_callback *cb = STATE_CALLBACK (sd);
112
  USI num = ((base + offset) & 0x7f) + 0x80;
113
 
114
#ifdef SIM_HAVE_BREAKPOINTS
115
  /* Check for breakpoints "owned" by the simulator first, regardless
116
     of --environment.  */
117
  if (num == TRAP_BREAKPOINT)
118
    {
119
      /* First try sim-break.c.  If it's a breakpoint the simulator "owns"
120
         it doesn't return.  Otherwise it returns and let's us try.  */
121
      sim_handle_breakpoint (sd, current_cpu, pc);
122
      /* Fall through.  */
123
    }
124
#endif
125
 
126
  if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
127
    {
128
      frv_queue_software_interrupt (current_cpu, num);
129
      return;
130
    }
131
 
132
  switch (num)
133
    {
134
    case TRAP_SYSCALL :
135
      {
136
        CB_SYSCALL s;
137
        CB_SYSCALL_INIT (&s);
138
        s.func = GET_H_GR (7);
139
        s.arg1 = GET_H_GR (8);
140
        s.arg2 = GET_H_GR (9);
141
        s.arg3 = GET_H_GR (10);
142
 
143
        if (s.func == TARGET_SYS_exit)
144
          {
145
            sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
146
          }
147
 
148
        s.p1 = (PTR) sd;
149
        s.p2 = (PTR) current_cpu;
150
        s.read_mem = syscall_read_mem;
151
        s.write_mem = syscall_write_mem;
152
        cb_syscall (cb, &s);
153
        SET_H_GR (8, s.result);
154
        SET_H_GR (9, s.result2);
155
        SET_H_GR (10, s.errcode);
156
        break;
157
      }
158
 
159
    case TRAP_BREAKPOINT:
160
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
161
      break;
162
 
163
      /* Add support for dumping registers, either at fixed traps, or all
164
         unknown traps if configured with --enable-sim-trapdump.  */
165
    default:
166
#if !TRAPDUMP
167
      frv_queue_software_interrupt (current_cpu, num);
168
      return;
169
#endif
170
 
171
#ifdef TRAP_REGDUMP1
172
    case TRAP_REGDUMP1:
173
#endif
174
 
175
#ifdef TRAP_REGDUMP2
176
    case TRAP_REGDUMP2:
177
#endif
178
 
179
#if TRAPDUMP || (defined (TRAP_REGDUMP1)) || (defined (TRAP_REGDUMP2))
180
      {
181
        char buf[256];
182
        int i, j;
183
 
184
        buf[0] = 0;
185
        if (STATE_TEXT_SECTION (sd)
186
            && pc >= STATE_TEXT_START (sd)
187
            && pc < STATE_TEXT_END (sd))
188
          {
189
            const char *pc_filename = (const char *)0;
190
            const char *pc_function = (const char *)0;
191
            unsigned int pc_linenum = 0;
192
 
193
            if (bfd_find_nearest_line (STATE_PROG_BFD (sd),
194
                                       STATE_TEXT_SECTION (sd),
195
                                       (struct bfd_symbol **) 0,
196
                                       pc - STATE_TEXT_START (sd),
197
                                       &pc_filename, &pc_function, &pc_linenum)
198
                && (pc_function || pc_filename))
199
              {
200
                char *p = buf+2;
201
                buf[0] = ' ';
202
                buf[1] = '(';
203
                if (pc_function)
204
                  {
205
                    strcpy (p, pc_function);
206
                    p += strlen (p);
207
                  }
208
                else
209
                  {
210
                    char *q = (char *) strrchr (pc_filename, '/');
211
                    strcpy (p, (q) ? q+1 : pc_filename);
212
                    p += strlen (p);
213
                  }
214
 
215
                if (pc_linenum)
216
                  {
217
                    sprintf (p, " line %d", pc_linenum);
218
                    p += strlen (p);
219
                  }
220
 
221
                p[0] = ')';
222
                p[1] = '\0';
223
                if ((p+1) - buf > sizeof (buf))
224
                  abort ();
225
              }
226
          }
227
 
228
        sim_io_printf (sd,
229
                       "\nRegister dump,    pc = 0x%.8x%s, base = %u, offset = %d\n",
230
                       (unsigned)pc, buf, (unsigned)base, (int)offset);
231
 
232
        for (i = 0; i < 64; i += 8)
233
          {
234
            long g0 = (long)GET_H_GR (i);
235
            long g1 = (long)GET_H_GR (i+1);
236
            long g2 = (long)GET_H_GR (i+2);
237
            long g3 = (long)GET_H_GR (i+3);
238
            long g4 = (long)GET_H_GR (i+4);
239
            long g5 = (long)GET_H_GR (i+5);
240
            long g6 = (long)GET_H_GR (i+6);
241
            long g7 = (long)GET_H_GR (i+7);
242
 
243
            if ((g0 | g1 | g2 | g3 | g4 | g5 | g6 | g7) != 0)
244
              sim_io_printf (sd,
245
                             "\tgr%02d - gr%02d:   0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx\n",
246
                             i, i+7, g0, g1, g2, g3, g4, g5, g6, g7);
247
          }
248
 
249
        for (i = 0; i < 64; i += 8)
250
          {
251
            long f0 = (long)GET_H_FR (i);
252
            long f1 = (long)GET_H_FR (i+1);
253
            long f2 = (long)GET_H_FR (i+2);
254
            long f3 = (long)GET_H_FR (i+3);
255
            long f4 = (long)GET_H_FR (i+4);
256
            long f5 = (long)GET_H_FR (i+5);
257
            long f6 = (long)GET_H_FR (i+6);
258
            long f7 = (long)GET_H_FR (i+7);
259
 
260
            if ((f0 | f1 | f2 | f3 | f4 | f5 | f6 | f7) != 0)
261
              sim_io_printf (sd,
262
                             "\tfr%02d - fr%02d:   0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx\n",
263
                             i, i+7, f0, f1, f2, f3, f4, f5, f6, f7);
264
          }
265
 
266
        sim_io_printf (sd,
267
                       "\tlr/lcr/cc/ccc: 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx\n",
268
                       (long)GET_H_SPR (272),
269
                       (long)GET_H_SPR (273),
270
                       (long)GET_H_SPR (256),
271
                       (long)GET_H_SPR (263));
272
      }
273
      break;
274
#endif
275
    }
276
}
277
 
278
/* Handle the MTRAP insn.  */
279
void
280
frv_mtrap (SIM_CPU *current_cpu)
281
{
282
  SIM_DESC sd = CPU_STATE (current_cpu);
283
 
284
  /* Check the status of media exceptions in MSR0.  */
285
  SI msr = GET_MSR (0);
286
  if (GET_MSR_AOVF (msr) || GET_MSR_MTT (msr) && STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
287
    frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION);
288
}
289
 
290
/* Handle the BREAK insn.  */
291
void
292
frv_break (SIM_CPU *current_cpu)
293
{
294
  IADDR pc;
295
  SIM_DESC sd = CPU_STATE (current_cpu);
296
 
297
#ifdef SIM_HAVE_BREAKPOINTS
298
  /* First try sim-break.c.  If it's a breakpoint the simulator "owns"
299
     it doesn't return.  Otherwise it returns and let's us try.  */
300
  pc = GET_H_PC ();
301
  sim_handle_breakpoint (sd, current_cpu, pc);
302
  /* Fall through.  */
303
#endif
304
 
305
  if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
306
    {
307
      /* Invalidate the insn cache because the debugger will presumably
308
         replace the breakpoint insn with the real one.  */
309
#ifndef SIM_HAVE_BREAKPOINTS
310
      pc = GET_H_PC ();
311
#endif
312
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
313
    }
314
 
315
  frv_queue_break_interrupt (current_cpu);
316
}
317
 
318
/* Return from trap.  */
319
USI
320
frv_rett (SIM_CPU *current_cpu, PCADDR pc, BI debug_field)
321
{
322
  USI new_pc;
323
  /* if (normal running mode and debug_field==0
324
       PC=PCSR
325
       PSR.ET=1
326
       PSR.S=PSR.PS
327
     else if (debug running mode and debug_field==1)
328
       PC=(BPCSR)
329
       PSR.ET=BPSR.BET
330
       PSR.S=BPSR.BS
331
       change to normal running mode
332
  */
333
  int psr_s = GET_H_PSR_S ();
334
  int psr_et = GET_H_PSR_ET ();
335
 
336
  /* Check for exceptions in the priority order listed in the FRV Architecture
337
     Volume 2.  */
338
  if (! psr_s)
339
    {
340
      /* Halt if PSR.ET is not set.  See chapter 6 of the LSI.  */
341
      if (! psr_et)
342
        {
343
          SIM_DESC sd = CPU_STATE (current_cpu);
344
          sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
345
        }
346
 
347
      /* privileged_instruction interrupt will have already been queued by
348
         frv_detect_insn_access_interrupts.  */
349
      new_pc = pc + 4;
350
    }
351
  else if (psr_et)
352
    {
353
      /* Halt if PSR.S is set.  See chapter 6 of the LSI.  */
354
      if (psr_s)
355
        {
356
          SIM_DESC sd = CPU_STATE (current_cpu);
357
          sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
358
        }
359
 
360
      frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
361
      new_pc = pc + 4;
362
    }
363
  else if (! CPU_DEBUG_STATE (current_cpu) && debug_field == 0)
364
    {
365
      USI psr = GET_PSR ();
366
      /* Return from normal running state.  */
367
      new_pc = GET_H_SPR (H_SPR_PCSR);
368
      SET_PSR_ET (psr, 1);
369
      SET_PSR_S (psr, GET_PSR_PS (psr));
370
      sim_queue_fn_si_write (current_cpu, frvbf_h_spr_set, H_SPR_PSR, psr);
371
    }
372
  else if (CPU_DEBUG_STATE (current_cpu) && debug_field == 1)
373
    {
374
      USI psr = GET_PSR ();
375
      /* Return from debug state.  */
376
      new_pc = GET_H_SPR (H_SPR_BPCSR);
377
      SET_PSR_ET (psr, GET_H_BPSR_BET ());
378
      SET_PSR_S (psr, GET_H_BPSR_BS ());
379
      sim_queue_fn_si_write (current_cpu, frvbf_h_spr_set, H_SPR_PSR, psr);
380
      CPU_DEBUG_STATE (current_cpu) = 0;
381
    }
382
  else
383
    new_pc = pc + 4;
384
 
385
  return new_pc;
386
}
387
 
388
/* Functions for handling non-excepting instruction side effects.  */
389
static SI next_available_nesr (SIM_CPU *current_cpu, SI current_index)
390
{
391
  FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu);
392
  if (control->spr[H_SPR_NECR].implemented)
393
    {
394
      int limit;
395
      USI necr = GET_NECR ();
396
 
397
      /* See if any NESRs are implemented. First need to check the validity of
398
         the NECR.  */
399
      if (! GET_NECR_VALID (necr))
400
        return NO_NESR;
401
 
402
      limit = GET_NECR_NEN (necr);
403
      for (++current_index; current_index < limit; ++current_index)
404
        {
405
          SI nesr = GET_NESR (current_index);
406
          if (! GET_NESR_VALID (nesr))
407
            return current_index;
408
        }
409
    }
410
  return NO_NESR;
411
}
412
 
413
static SI next_valid_nesr (SIM_CPU *current_cpu, SI current_index)
414
{
415
  FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu);
416
  if (control->spr[H_SPR_NECR].implemented)
417
    {
418
      int limit;
419
      USI necr = GET_NECR ();
420
 
421
      /* See if any NESRs are implemented. First need to check the validity of
422
         the NECR.  */
423
      if (! GET_NECR_VALID (necr))
424
        return NO_NESR;
425
 
426
      limit = GET_NECR_NEN (necr);
427
      for (++current_index; current_index < limit; ++current_index)
428
        {
429
          SI nesr = GET_NESR (current_index);
430
          if (GET_NESR_VALID (nesr))
431
            return current_index;
432
        }
433
    }
434
  return NO_NESR;
435
}
436
 
437
BI
438
frvbf_check_non_excepting_load (
439
  SIM_CPU *current_cpu, SI base_index, SI disp_index, SI target_index,
440
  SI immediate_disp, QI data_size, BI is_float
441
)
442
{
443
  BI rc = 1; /* perform the load.  */
444
  SIM_DESC sd = CPU_STATE (current_cpu);
445
  int daec = 0;
446
  int rec  = 0;
447
  int ec   = 0;
448
  USI necr;
449
  int do_elos;
450
  SI NE_flags[2];
451
  SI NE_base;
452
  SI nesr;
453
  SI ne_index;
454
  FRV_REGISTER_CONTROL *control;
455
 
456
  SI address = GET_H_GR (base_index);
457
  if (disp_index >= 0)
458
    address += GET_H_GR (disp_index);
459
  else
460
    address += immediate_disp;
461
 
462
  /* Check for interrupt factors.  */
463
  switch (data_size)
464
    {
465
    case NESR_UQI_SIZE:
466
    case NESR_QI_SIZE:
467
      break;
468
    case NESR_UHI_SIZE:
469
    case NESR_HI_SIZE:
470
      if (address & 1)
471
        ec = 1;
472
      break;
473
    case NESR_SI_SIZE:
474
      if (address & 3)
475
        ec = 1;
476
      break;
477
    case NESR_DI_SIZE:
478
      if (address & 7)
479
        ec = 1;
480
      if (target_index & 1)
481
        rec = 1;
482
      break;
483
    case NESR_XI_SIZE:
484
      if (address & 0xf)
485
        ec = 1;
486
      if (target_index & 3)
487
        rec = 1;
488
      break;
489
    default:
490
      {
491
        IADDR pc = GET_H_PC ();
492
        sim_engine_abort (sd, current_cpu, pc,
493
                          "check_non_excepting_load: Incorrect data_size\n");
494
        break;
495
      }
496
    }
497
 
498
  control = CPU_REGISTER_CONTROL (current_cpu);
499
  if (control->spr[H_SPR_NECR].implemented)
500
    {
501
      necr = GET_NECR ();
502
      do_elos = GET_NECR_VALID (necr) && GET_NECR_ELOS (necr);
503
    }
504
  else
505
    do_elos = 0;
506
 
507
  /* NECR, NESR, NEEAR are only implemented for the full frv machine.  */
508
  if (do_elos)
509
    {
510
      ne_index = next_available_nesr (current_cpu, NO_NESR);
511
      if (ne_index == NO_NESR)
512
        {
513
          IADDR pc = GET_H_PC ();
514
          sim_engine_abort (sd, current_cpu, pc,
515
                            "No available NESR register\n");
516
        }
517
 
518
      /* Fill in the basic fields of the NESR.  */
519
      nesr = GET_NESR (ne_index);
520
      SET_NESR_VALID (nesr);
521
      SET_NESR_EAV (nesr);
522
      SET_NESR_DRN (nesr, target_index);
523
      SET_NESR_SIZE (nesr, data_size);
524
      SET_NESR_NEAN (nesr, ne_index);
525
      if (is_float)
526
        SET_NESR_FR (nesr);
527
      else
528
        CLEAR_NESR_FR (nesr);
529
 
530
      /* Set the corresponding NEEAR.  */
531
      SET_NEEAR (ne_index, address);
532
 
533
      SET_NESR_DAEC (nesr, 0);
534
      SET_NESR_REC (nesr, 0);
535
      SET_NESR_EC (nesr, 0);
536
    }
537
 
538
  /* Set the NE flag corresponding to the target register if an interrupt
539
     factor was detected.
540
     daec is not checked here yet, but is declared for future reference.  */
541
  if (is_float)
542
    NE_base = H_SPR_FNER0;
543
  else
544
    NE_base = H_SPR_GNER0;
545
 
546
  GET_NE_FLAGS (NE_flags, NE_base);
547
  if (rec)
548
    {
549
      SET_NE_FLAG (NE_flags, target_index);
550
      if (do_elos)
551
        SET_NESR_REC (nesr, NESR_REGISTER_NOT_ALIGNED);
552
    }
553
 
554
  if (ec)
555
    {
556
      SET_NE_FLAG (NE_flags, target_index);
557
      if (do_elos)
558
        SET_NESR_EC (nesr, NESR_MEM_ADDRESS_NOT_ALIGNED);
559
    }
560
 
561
  if (do_elos)
562
    SET_NESR (ne_index, nesr);
563
 
564
  /* If no interrupt factor was detected then set the NE flag on the
565
     target register if the NE flag on one of the input registers
566
     is already set.  */
567
  if (! rec && ! ec && ! daec)
568
    {
569
      BI ne_flag = GET_NE_FLAG (NE_flags, base_index);
570
      if (disp_index >= 0)
571
        ne_flag |= GET_NE_FLAG (NE_flags, disp_index);
572
      if (ne_flag)
573
        {
574
          SET_NE_FLAG (NE_flags, target_index);
575
          rc = 0; /* Do not perform the load.  */
576
        }
577
      else
578
        CLEAR_NE_FLAG (NE_flags, target_index);
579
    }
580
 
581
  SET_NE_FLAGS (NE_base, NE_flags);
582
 
583
  return rc; /* perform the load?  */
584
}
585
 
586
/* Record state for media exception: media_cr_not_aligned.  */
587
void
588
frvbf_media_cr_not_aligned (SIM_CPU *current_cpu)
589
{
590
  SIM_DESC sd = CPU_STATE (current_cpu);
591
 
592
  /* On some machines this generates an illegal_instruction interrupt.  */
593
  switch (STATE_ARCHITECTURE (sd)->mach)
594
    {
595
      /* Note: there is a discrepancy between V2.2 of the FR400
596
         instruction manual and the various FR4xx LSI specs.  The former
597
         claims that unaligned registers cause an mp_exception while the
598
         latter say it's an illegal_instruction.  The LSI specs appear
599
         to be correct since MTT is fixed at 1.  */
600
    case bfd_mach_fr400:
601
    case bfd_mach_fr450:
602
    case bfd_mach_fr550:
603
      frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
604
      break;
605
    default:
606
      frv_set_mp_exception_registers (current_cpu, MTT_CR_NOT_ALIGNED, 0);
607
      break;
608
    }
609
}
610
 
611
/* Record state for media exception: media_acc_not_aligned.  */
612
void
613
frvbf_media_acc_not_aligned (SIM_CPU *current_cpu)
614
{
615
  SIM_DESC sd = CPU_STATE (current_cpu);
616
 
617
  /* On some machines this generates an illegal_instruction interrupt.  */
618
  switch (STATE_ARCHITECTURE (sd)->mach)
619
    {
620
      /* See comment in frvbf_cr_not_aligned().  */
621
    case bfd_mach_fr400:
622
    case bfd_mach_fr450:
623
    case bfd_mach_fr550:
624
      frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
625
      break;
626
    default:
627
      frv_set_mp_exception_registers (current_cpu, MTT_ACC_NOT_ALIGNED, 0);
628
      break;
629
    }
630
}
631
 
632
/* Record state for media exception: media_register_not_aligned.  */
633
void
634
frvbf_media_register_not_aligned (SIM_CPU *current_cpu)
635
{
636
  SIM_DESC sd = CPU_STATE (current_cpu);
637
 
638
  /* On some machines this generates an illegal_instruction interrupt.  */
639
  switch (STATE_ARCHITECTURE (sd)->mach)
640
    {
641
      /* See comment in frvbf_cr_not_aligned().  */
642
    case bfd_mach_fr400:
643
    case bfd_mach_fr450:
644
    case bfd_mach_fr550:
645
      frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
646
      break;
647
    default:
648
      frv_set_mp_exception_registers (current_cpu, MTT_INVALID_FR, 0);
649
      break;
650
    }
651
}
652
 
653
/* Record state for media exception: media_overflow.  */
654
void
655
frvbf_media_overflow (SIM_CPU *current_cpu, int sie)
656
{
657
  frv_set_mp_exception_registers (current_cpu, MTT_OVERFLOW, sie);
658
}
659
 
660
/* Queue a division exception.  */
661
enum frv_dtt
662
frvbf_division_exception (SIM_CPU *current_cpu, enum frv_dtt dtt,
663
                          int target_index, int non_excepting)
664
{
665
  /* If there was an overflow and it is masked, then record it in
666
     ISR.AEXC.  */
667
  USI isr = GET_ISR ();
668
  if ((dtt & FRV_DTT_OVERFLOW) && GET_ISR_EDE (isr))
669
    {
670
      dtt &= ~FRV_DTT_OVERFLOW;
671
      SET_ISR_AEXC (isr);
672
      SET_ISR (isr);
673
    }
674
  if (dtt != FRV_DTT_NO_EXCEPTION)
675
    {
676
      if (non_excepting)
677
        {
678
          /* Non excepting instruction, simply set the NE flag for the target
679
             register.  */
680
          SI NE_flags[2];
681
          GET_NE_FLAGS (NE_flags, H_SPR_GNER0);
682
          SET_NE_FLAG (NE_flags, target_index);
683
          SET_NE_FLAGS (H_SPR_GNER0, NE_flags);
684
        }
685
      else
686
        frv_queue_division_exception_interrupt (current_cpu, dtt);
687
    }
688
  return dtt;
689
}
690
 
691
void
692
frvbf_check_recovering_store (
693
  SIM_CPU *current_cpu, PCADDR address, SI regno, int size, int is_float
694
)
695
{
696
  FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
697
  int reg_ix;
698
 
699
  CPU_RSTR_INVALIDATE(current_cpu) = 0;
700
 
701
  for (reg_ix = next_valid_nesr (current_cpu, NO_NESR);
702
       reg_ix != NO_NESR;
703
       reg_ix = next_valid_nesr (current_cpu, reg_ix))
704
    {
705
      if (address == GET_H_SPR (H_SPR_NEEAR0 + reg_ix))
706
        {
707
          SI nesr = GET_NESR (reg_ix);
708
          int nesr_drn = GET_NESR_DRN (nesr);
709
          BI nesr_fr = GET_NESR_FR (nesr);
710
          SI remain;
711
 
712
          /* Invalidate cache block containing this address.
713
             If we need to count cycles, then the cache operation will be
714
             initiated from the model profiling functions.
715
             See frvbf_model_....  */
716
          if (model_insn)
717
            {
718
              CPU_RSTR_INVALIDATE(current_cpu) = 1;
719
              CPU_LOAD_ADDRESS (current_cpu) = address;
720
            }
721
          else
722
            frv_cache_invalidate (cache, address, 1/* flush */);
723
 
724
          /* Copy the stored value to the register indicated by NESR.DRN.  */
725
          for (remain = size; remain > 0; remain -= 4)
726
            {
727
              SI value;
728
 
729
              if (is_float)
730
                value = GET_H_FR (regno);
731
              else
732
                value = GET_H_GR (regno);
733
 
734
              switch (size)
735
                {
736
                case 1:
737
                  value &= 0xff;
738
                  break;
739
                case 2:
740
                  value &= 0xffff;
741
                  break;
742
                default:
743
                  break;
744
                }
745
 
746
              if (nesr_fr)
747
                sim_queue_fn_sf_write (current_cpu, frvbf_h_fr_set, nesr_drn,
748
                                       value);
749
              else
750
                sim_queue_fn_si_write (current_cpu, frvbf_h_gr_set, nesr_drn,
751
                                       value);
752
 
753
              nesr_drn++;
754
              regno++;
755
            }
756
          break; /* Only consider the first matching register.  */
757
        }
758
    } /* loop over active neear registers.  */
759
}
760
 
761
SI
762
frvbf_check_acc_range (SIM_CPU *current_cpu, SI regno)
763
{
764
  /* Only applicable to fr550 */
765
  SIM_DESC sd = CPU_STATE (current_cpu);
766
  if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
767
    return;
768
 
769
  /* On the fr550, media insns in slots 0 and 2 can only access
770
     accumulators acc0-acc3. Insns in slots 1 and 3 can only access
771
     accumulators acc4-acc7 */
772
  switch (frv_current_fm_slot)
773
    {
774
    case UNIT_FM0:
775
    case UNIT_FM2:
776
      if (regno <= 3)
777
        return 1; /* all is ok */
778
      break;
779
    case UNIT_FM1:
780
    case UNIT_FM3:
781
      if (regno >= 4)
782
        return 1; /* all is ok */
783
      break;
784
    }
785
 
786
  /* The specified accumulator is out of range. Queue an illegal_instruction
787
     interrupt.  */
788
  frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
789
  return 0;
790
}
791
 
792
void
793
frvbf_check_swap_address (SIM_CPU *current_cpu, SI address)
794
{
795
  /* Only applicable to fr550 */
796
  SIM_DESC sd = CPU_STATE (current_cpu);
797
  if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
798
    return;
799
 
800
  /* Adress must be aligned on a word boundary.  */
801
  if (address & 0x3)
802
    frv_queue_data_access_exception_interrupt (current_cpu);
803
}
804
 
805
static void
806
clear_nesr_neear (SIM_CPU *current_cpu, SI target_index, BI is_float)
807
{
808
  int reg_ix;
809
 
810
  /* Only implemented for full frv.  */
811
  SIM_DESC sd = CPU_STATE (current_cpu);
812
  if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_frv)
813
    return;
814
 
815
  /* Clear the appropriate NESR and NEEAR registers.  */
816
  for (reg_ix = next_valid_nesr (current_cpu, NO_NESR);
817
       reg_ix != NO_NESR;
818
       reg_ix = next_valid_nesr (current_cpu, reg_ix))
819
    {
820
      SI nesr;
821
      /* The register is available, now check if it is active.  */
822
      nesr = GET_NESR (reg_ix);
823
      if (GET_NESR_FR (nesr) == is_float)
824
        {
825
          if (target_index < 0 || GET_NESR_DRN (nesr) == target_index)
826
            {
827
              SET_NESR (reg_ix, 0);
828
              SET_NEEAR (reg_ix, 0);
829
            }
830
        }
831
    }
832
}
833
 
834
static void
835
clear_ne_flags (
836
  SIM_CPU *current_cpu,
837
  SI target_index,
838
  int hi_available,
839
  int lo_available,
840
  SI NE_base
841
)
842
{
843
  SI NE_flags[2];
844
  int exception;
845
 
846
  GET_NE_FLAGS (NE_flags, NE_base);
847
  if (target_index >= 0)
848
    CLEAR_NE_FLAG (NE_flags, target_index);
849
  else
850
    {
851
      if (lo_available)
852
        NE_flags[1] = 0;
853
      if (hi_available)
854
        NE_flags[0] = 0;
855
    }
856
  SET_NE_FLAGS (NE_base, NE_flags);
857
}
858
 
859
/* Return 1 if the given register is available, 0 otherwise.  TARGET_INDEX==-1
860
   means to check for any register available.  */
861
static void
862
which_registers_available (
863
  SIM_CPU *current_cpu, int *hi_available, int *lo_available, int is_float
864
)
865
{
866
  if (is_float)
867
    frv_fr_registers_available (current_cpu, hi_available, lo_available);
868
  else
869
    frv_gr_registers_available (current_cpu, hi_available, lo_available);
870
}
871
 
872
void
873
frvbf_clear_ne_flags (SIM_CPU *current_cpu, SI target_index, BI is_float)
874
{
875
  int hi_available;
876
  int lo_available;
877
  int exception;
878
  SI NE_base;
879
  USI necr;
880
  FRV_REGISTER_CONTROL *control;
881
 
882
  /* Check for availability of the target register(s).  */
883
  which_registers_available (current_cpu, & hi_available, & lo_available,
884
                             is_float);
885
 
886
  /* Check to make sure that the target register is available.  */
887
  if (! frv_check_register_access (current_cpu, target_index,
888
                                   hi_available, lo_available))
889
    return;
890
 
891
  /* Determine whether we're working with GR or FR registers.  */
892
  if (is_float)
893
    NE_base = H_SPR_FNER0;
894
  else
895
    NE_base = H_SPR_GNER0;
896
 
897
  /* Always clear the appropriate NE flags.  */
898
  clear_ne_flags (current_cpu, target_index, hi_available, lo_available,
899
                  NE_base);
900
 
901
  /* Clear the appropriate NESR and NEEAR registers.  */
902
  control = CPU_REGISTER_CONTROL (current_cpu);
903
  if (control->spr[H_SPR_NECR].implemented)
904
    {
905
      necr = GET_NECR ();
906
      if (GET_NECR_VALID (necr) && GET_NECR_ELOS (necr))
907
        clear_nesr_neear (current_cpu, target_index, is_float);
908
    }
909
}
910
 
911
void
912
frvbf_commit (SIM_CPU *current_cpu, SI target_index, BI is_float)
913
{
914
  SI NE_base;
915
  SI NE_flags[2];
916
  BI NE_flag;
917
  int exception;
918
  int hi_available;
919
  int lo_available;
920
  USI necr;
921
  FRV_REGISTER_CONTROL *control;
922
 
923
  /* Check for availability of the target register(s).  */
924
  which_registers_available (current_cpu, & hi_available, & lo_available,
925
                             is_float);
926
 
927
  /* Check to make sure that the target register is available.  */
928
  if (! frv_check_register_access (current_cpu, target_index,
929
                                   hi_available, lo_available))
930
    return;
931
 
932
  /* Determine whether we're working with GR or FR registers.  */
933
  if (is_float)
934
    NE_base = H_SPR_FNER0;
935
  else
936
    NE_base = H_SPR_GNER0;
937
 
938
  /* Determine whether a ne exception is pending.  */
939
  GET_NE_FLAGS (NE_flags, NE_base);
940
  if (target_index >= 0)
941
    NE_flag = GET_NE_FLAG (NE_flags, target_index);
942
  else
943
    {
944
      NE_flag =
945
        hi_available && NE_flags[0] != 0 || lo_available && NE_flags[1] != 0;
946
    }
947
 
948
  /* Always clear the appropriate NE flags.  */
949
  clear_ne_flags (current_cpu, target_index, hi_available, lo_available,
950
                  NE_base);
951
 
952
  control = CPU_REGISTER_CONTROL (current_cpu);
953
  if (control->spr[H_SPR_NECR].implemented)
954
    {
955
      necr = GET_NECR ();
956
      if (GET_NECR_VALID (necr) && GET_NECR_ELOS (necr) && NE_flag)
957
        {
958
          /* Clear the appropriate NESR and NEEAR registers.  */
959
          clear_nesr_neear (current_cpu, target_index, is_float);
960
          frv_queue_program_interrupt (current_cpu, FRV_COMMIT_EXCEPTION);
961
        }
962
    }
963
}
964
 
965
/* Generate the appropriate fp_exception(s) based on the given status code.  */
966
void
967
frvbf_fpu_error (CGEN_FPU* fpu, int status)
968
{
969
  struct frv_fp_exception_info fp_info = {
970
    FSR_NO_EXCEPTION, FTT_IEEE_754_EXCEPTION
971
  };
972
 
973
  if (status &
974
      (sim_fpu_status_invalid_snan |
975
       sim_fpu_status_invalid_qnan |
976
       sim_fpu_status_invalid_isi |
977
       sim_fpu_status_invalid_idi |
978
       sim_fpu_status_invalid_zdz |
979
       sim_fpu_status_invalid_imz |
980
       sim_fpu_status_invalid_cvi |
981
       sim_fpu_status_invalid_cmp |
982
       sim_fpu_status_invalid_sqrt))
983
    fp_info.fsr_mask |= FSR_INVALID_OPERATION;
984
 
985
  if (status & sim_fpu_status_invalid_div0)
986
    fp_info.fsr_mask |= FSR_DIVISION_BY_ZERO;
987
 
988
  if (status & sim_fpu_status_inexact)
989
    fp_info.fsr_mask |= FSR_INEXACT;
990
 
991
  if (status & sim_fpu_status_overflow)
992
    fp_info.fsr_mask |= FSR_OVERFLOW;
993
 
994
  if (status & sim_fpu_status_underflow)
995
    fp_info.fsr_mask |= FSR_UNDERFLOW;
996
 
997
  if (status & sim_fpu_status_denorm)
998
    {
999
      fp_info.fsr_mask |= FSR_DENORMAL_INPUT;
1000
      fp_info.ftt = FTT_DENORMAL_INPUT;
1001
    }
1002
 
1003
  if (fp_info.fsr_mask != FSR_NO_EXCEPTION)
1004
    {
1005
      SIM_CPU *current_cpu = (SIM_CPU *)fpu->owner;
1006
      frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
1007
    }
1008
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.