summaryrefslogtreecommitdiff
path: root/sim/arc/arc5.c
blob: 7e7910e4832f49f47c690d740308a38f93e88ac6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/* arc simulator support code
   Copyright (C) 1996, 1997, 1998, 2003, 2007, 2008, 2009
   Free Software Foundation, Inc.

   This file is part of GDB, the GNU debugger.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#define WANT_CPU a5f
#define WANT_CPU_A5F

#include "sim-main.h"
#include "cgen-mem.h"
#include "cgen-ops.h"

#include "arc-sim-registers.h"


#define STATUS_REGNUM         0
#define IDENTITY_REGNUM       4
#define BYTES_IN_REGISTER     4


/* N.B. the a5f_h_auxr_get/set functions use the GET_H_AUXR/SET_H_AUXR macros:
        these have a special case for register number 0 (STATUS) which result in
        an 'invalid insn' internal error being raised (see CR 95530). 
  
        Those macros are no doubt intended to be used in the execution of the
        object code running on the simulator (where access to the obsolete
        STATUS register, instead of the newer STATUS32 register, would indeed be
        an error), but they are also being used by this code that the debugger
        uses to interact with the simulator (via the sim_fetch_register /
        sim_store_register functions).
  
        So we wish to avoid calling a5f_h_auxr_get/set for the STATUS register.
        Fortunately, the register is read-only so we can simply ignore a write;
        for a read, we must "short-circuit" the access by going straight to the
        default case of the GET_H_AUXR macro (which is "CPU (h_auxr[index])").  */


/* The contents of BUF are in target byte order.  */

int
a5f_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
  int               hw_regnum;
  ARC_RegisterClass reg_class;
  SI                contents;

// printf("*** a5f_fetch_register %d\n", rn);

  arc_hw_register_mapping(rn, &hw_regnum, &reg_class);

  switch (reg_class)
    {
    case ARC_UNKNOWN_REGISTER:
      return 0;

    case ARC_CORE_REGISTER:
      /* R61 and R62 are reserved - so just return 0.  */
      if (hw_regnum == 61 || hw_regnum == 62)
          return 0;

      /* N.B. the simulator does not model PCL (R63) if the instruction does
	 not refer to it. - so get the current
              instruction address from PC and compute PCL from it.  */
      contents = (hw_regnum == 63) ? a5f_h_pc_get (current_cpu) & -4
                                   : a5f_h_cr_get (current_cpu, hw_regnum);
      break;

    case ARC_AUX_REGISTER:
      if (hw_regnum == IDENTITY_REGNUM)
      {
        /* Construct a value from the target CPU architecture.  */
        switch (CPU_MACH(current_cpu)->num)
          {
          case MACH_A5    : contents = 0x10;  break;
          case MACH_ARC600: contents = 0x20;  break;
          case MACH_ARC700: contents = 0x30;  break;
          default         : contents = 0x00;  break;
          }
      }
      else
        /* If it is the STATUS register, make the access directly.  */
        contents = (hw_regnum == STATUS_REGNUM) ? CPU (h_auxr[STATUS_REGNUM])
                                                : a5f_h_auxr_get (current_cpu, hw_regnum);
      break;

    case ARC_PROGRAM_COUNTER:
      contents = a5f_h_pc_get (current_cpu);
      break;
    }

  SETTWI (buf, contents);
  return BYTES_IN_REGISTER;
}


/* The contents of BUF are in target byte order.  */

int
a5f_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
  int               hw_regnum;
  ARC_RegisterClass reg_class;

// printf("*** a5f_store_register %d\n", rn);

  arc_hw_register_mapping(rn, &hw_regnum, &reg_class);

  switch (reg_class)
    {
    case ARC_UNKNOWN_REGISTER:
      break;

    case ARC_CORE_REGISTER:
      /* R61 and R62 are reserved, and R63 is PCL which is read-only - so just
         do nothing for them. */
      if (hw_regnum < 61)
      {
          a5f_h_cr_set (current_cpu, hw_regnum, GETTWI (buf));
          return BYTES_IN_REGISTER;
      }
      break;

    case ARC_AUX_REGISTER:
      /* The STATUS aux reg is read/only, so ignore the write attempt.  */
      if (hw_regnum != STATUS_REGNUM)
      {
          /* Do any required conversion on the given value before writing it to
             the register (this ensures that bits in reserved fields have the
             on-write values required by the architecture.  */
          arc_aux_register_conversion(rn, buf);

          a5f_h_auxr_set (current_cpu, hw_regnum, GETTWI (buf));
          return BYTES_IN_REGISTER;
      }
      break;

    case ARC_PROGRAM_COUNTER:
      a5f_h_pc_set (current_cpu, GETTWI (buf));
      return BYTES_IN_REGISTER;
    }

  return 0;
}


/* Initialize cycle counting for an insn.
   FIRST_P is non-zero if this is the first insn in a set of parallel
   insns.  */

void
a5f_model_insn_before (SIM_CPU *cpu, int first_p)
{
}

/* Record the cycles computed for an insn.
   LAST_P is non-zero if this is the last insn in a set of parallel insns,
   and we update the total cycle count.
   CYCLES is the cycle count of the insn.  */

void
a5f_model_insn_after (SIM_CPU *cpu, int last_p, int cycles)
{
}

int
a5f_model_A5_u_exec (SIM_CPU *cpu, const IDESC *idesc,
			     int unit_num, int referenced,
			     INT sr, INT sr2, INT dr)
{
#if 0
  check_load_stall (cpu, sr);
  check_load_stall (cpu, sr2);
#endif
  return idesc->timing->units[unit_num].done;
}