1/* OpenRISC simulator support code
2   Copyright (C) 2017-2020 Free Software Foundation, Inc.
3
4   This file is part of GDB, the GNU debugger.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19#define WANT_CPU_OR1K32BF
20#define WANT_CPU
21
22#include "sim-main.h"
23#include "symcat.h"
24#include "cgen-ops.h"
25#include "cgen-mem.h"
26#include "cpuall.h"
27
28#include <string.h>
29
30int
31or1k32bf_fetch_register (sim_cpu *current_cpu, int rn, unsigned char *buf,
32			 int len)
33{
34  if (rn < 32)
35    SETTWI (buf, GET_H_GPR (rn));
36  else
37    switch (rn)
38      {
39      case PPC_REGNUM:
40	SETTWI (buf, GET_H_SYS_PPC ());
41	break;
42      case PC_REGNUM:
43	SETTWI (buf, GET_H_PC ());
44	break;
45      case SR_REGNUM:
46	SETTWI (buf, GET_H_SYS_SR ());
47	break;
48      default:
49	return 0;
50      }
51  return sizeof (WI);		/* WI from arch.h */
52}
53
54int
55or1k32bf_store_register (sim_cpu *current_cpu, int rn, unsigned char *buf,
56			 int len)
57{
58  if (rn < 32)
59    SET_H_GPR (rn, GETTWI (buf));
60  else
61    switch (rn)
62      {
63      case PPC_REGNUM:
64	SET_H_SYS_PPC (GETTWI (buf));
65	break;
66      case PC_REGNUM:
67	SET_H_PC (GETTWI (buf));
68	break;
69      case SR_REGNUM:
70	SET_H_SYS_SR (GETTWI (buf));
71	break;
72      default:
73	return 0;
74      }
75  return sizeof (WI);		/* WI from arch.h */
76}
77
78int
79or1k32bf_model_or1200_u_exec (sim_cpu *current_cpu, const IDESC *idesc,
80			      int unit_num, int referenced)
81{
82  return -1;
83}
84
85int
86or1k32bf_model_or1200nd_u_exec (sim_cpu *current_cpu, const IDESC *idesc,
87				int unit_num, int referenced)
88{
89  return -1;
90}
91
92void
93or1k32bf_model_insn_before (sim_cpu *current_cpu, int first_p)
94{
95}
96
97void
98or1k32bf_model_insn_after (sim_cpu *current_cpu, int last_p, int cycles)
99{
100}
101
102USI
103or1k32bf_h_spr_get_raw (sim_cpu *current_cpu, USI addr)
104{
105  SIM_DESC sd = CPU_STATE (current_cpu);
106  SIM_ASSERT (addr < NUM_SPR);
107  return current_cpu->spr[addr];
108}
109
110void
111or1k32bf_h_spr_set_raw (sim_cpu *current_cpu, USI addr, USI val)
112{
113  SIM_DESC sd = CPU_STATE (current_cpu);
114  SIM_ASSERT (addr < NUM_SPR);
115  current_cpu->spr[addr] = val;
116}
117
118USI
119or1k32bf_h_spr_field_get_raw (sim_cpu *current_cpu, USI addr, int msb, int lsb)
120{
121  SIM_DESC sd = CPU_STATE (current_cpu);
122  SIM_ASSERT (addr < NUM_SPR);
123  return LSEXTRACTED (current_cpu->spr[addr], msb, lsb);
124}
125
126void
127or1k32bf_h_spr_field_set_raw (sim_cpu *current_cpu, USI addr, int msb, int lsb,
128			      USI val)
129{
130  current_cpu->spr[addr] &= ~LSMASK32 (msb, lsb);
131  current_cpu->spr[addr] |= LSINSERTED (val, msb, lsb);
132}
133
134/* Initialize a sim cpu object.  */
135void
136or1k_cpu_init (SIM_DESC sd, sim_cpu *current_cpu, const USI or1k_vr,
137	       const USI or1k_upr, const USI or1k_cpucfgr)
138{
139  /* Set the configuration registers passed from the user.  */
140  SET_H_SYS_VR (or1k_vr);
141  SET_H_SYS_UPR (or1k_upr);
142  SET_H_SYS_CPUCFGR (or1k_cpucfgr);
143
144#define CHECK_SPR_FIELD(GROUP, INDEX, FIELD, test) \
145  do \
146    { \
147      USI field = GET_H_##SYS##_##INDEX##_##FIELD (); \
148      if (!(test)) \
149	sim_io_eprintf \
150	  (sd, "WARNING: unsupported %s field in %s register: 0x%x\n", \
151	   #FIELD, #INDEX, field); \
152    } while (0)
153
154  /* Set flags indicating if we are in a delay slot or not.  */
155  current_cpu->next_delay_slot = 0;
156  current_cpu->delay_slot = 0;
157
158  /* Verify any user passed fields and warn on configurations we don't
159     support.  */
160  CHECK_SPR_FIELD (SYS, UPR, UP, field == 1);
161  CHECK_SPR_FIELD (SYS, UPR, DCP, field == 0);
162  CHECK_SPR_FIELD (SYS, UPR, ICP, field == 0);
163  CHECK_SPR_FIELD (SYS, UPR, DMP, field == 0);
164  CHECK_SPR_FIELD (SYS, UPR, MP, field == 0);
165  CHECK_SPR_FIELD (SYS, UPR, IMP, field == 0);
166  CHECK_SPR_FIELD (SYS, UPR, DUP, field == 0);
167  CHECK_SPR_FIELD (SYS, UPR, PCUP, field == 0);
168  CHECK_SPR_FIELD (SYS, UPR, PICP, field == 0);
169  CHECK_SPR_FIELD (SYS, UPR, PMP, field == 0);
170  CHECK_SPR_FIELD (SYS, UPR, TTP, field == 0);
171  CHECK_SPR_FIELD (SYS, UPR, CUP, field == 0);
172
173  CHECK_SPR_FIELD (SYS, CPUCFGR, NSGR, field == 0);
174  CHECK_SPR_FIELD (SYS, CPUCFGR, CGF, field == 0);
175  CHECK_SPR_FIELD (SYS, CPUCFGR, OB32S, field == 1);
176  CHECK_SPR_FIELD (SYS, CPUCFGR, OF32S, field == 1);
177  CHECK_SPR_FIELD (SYS, CPUCFGR, OB64S, field == 0);
178  CHECK_SPR_FIELD (SYS, CPUCFGR, OF64S, field == 0);
179  CHECK_SPR_FIELD (SYS, CPUCFGR, OV64S, field == 0);
180
181#undef CHECK_SPR_FIELD
182
183  /* Configure the fpu operations and mark fpu available.  */
184  cgen_init_accurate_fpu (current_cpu, CGEN_CPU_FPU (current_cpu),
185			  or1k32bf_fpu_error);
186  SET_H_SYS_CPUCFGR_OF32S (1);
187
188  /* Set the UPR[UP] flag, even if the user tried to unset it, as we always
189     support the Unit Present Register.  */
190  SET_H_SYS_UPR_UP (1);
191
192  /* Set the supervisor register to indicate we are in supervisor mode and
193     set the Fixed-One bit which must always be set.  */
194  SET_H_SYS_SR (SPR_FIELD_MASK_SYS_SR_SM | SPR_FIELD_MASK_SYS_SR_FO);
195
196  /* Clear the floating point control status register.  */
197  SET_H_SYS_FPCSR (0);
198}
199
200void
201or1k32bf_insn_before (sim_cpu *current_cpu, SEM_PC vpc, const IDESC *idesc)
202{
203  SIM_DESC sd = CPU_STATE (current_cpu);
204
205  current_cpu->delay_slot = current_cpu->next_delay_slot;
206  current_cpu->next_delay_slot = 0;
207
208  if (current_cpu->delay_slot &&
209      CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) &
210      CGEN_ATTR_MASK (CGEN_INSN_NOT_IN_DELAY_SLOT))
211    {
212      USI pc;
213#ifdef WITH_SCACHE
214      pc = vpc->argbuf.addr;
215#else
216      pc = vpc;
217#endif
218      sim_io_error (sd, "invalid instruction in a delay slot at PC 0x%08x",
219		    pc);
220    }
221
222}
223
224void
225or1k32bf_insn_after (sim_cpu *current_cpu, SEM_PC vpc, const IDESC *idesc)
226{
227  SIM_DESC sd = CPU_STATE (current_cpu);
228  USI ppc;
229
230#ifdef WITH_SCACHE
231  ppc = vpc->argbuf.addr;
232#else
233  ppc = vpc;
234#endif
235
236  SET_H_SYS_PPC (ppc);
237
238  if (!GET_H_SYS_CPUCFGR_ND () &&
239      CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) &
240      CGEN_ATTR_MASK (CGEN_INSN_DELAYED_CTI))
241    {
242      SIM_ASSERT (!current_cpu->delay_slot);
243      current_cpu->next_delay_slot = 1;
244    }
245}
246
247void
248or1k32bf_nop (sim_cpu *current_cpu, USI uimm16)
249{
250  SIM_DESC sd = CPU_STATE (current_cpu);
251
252  switch (uimm16)
253    {
254
255    case NOP_NOP:
256      break;
257
258    case NOP_EXIT:
259      sim_io_printf (CPU_STATE (current_cpu), "exit(%d)\n", GET_H_GPR (3));
260      /* fall through */
261    case NOP_EXIT_SILENT:
262      sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
263		       sim_exited, GET_H_GPR (3));
264      break;
265
266    case NOP_REPORT:
267      sim_io_printf (CPU_STATE (current_cpu), "report(0x%08x);\n",
268		     GET_H_GPR (3));
269      break;
270
271    case NOP_PUTC:
272      sim_io_printf (CPU_STATE (current_cpu), "%c",
273		     (char) (GET_H_GPR (3) & 0xff));
274      break;
275
276    default:
277      sim_io_eprintf (sd, "WARNING: l.nop with unsupported code 0x%08x\n",
278		      uimm16);
279      break;
280    }
281
282}
283
284/* Build an address value used for load and store instructions.  For example,
285   the instruction 'l.lws rD, I(rA)' will require to load data from the 4 byte
286   address represented by rA + I.  Here the argument base is rA, offset is I
287   and the size is the read size in bytes.  Note, OpenRISC requires that word
288   and half-word access be word and half-word aligned respectively, the check
289   for alignment is not needed here.  */
290
291USI
292or1k32bf_make_load_store_addr (sim_cpu *current_cpu, USI base, SI offset,
293			       int size)
294{
295  SIM_DESC sd = CPU_STATE (current_cpu);
296
297  USI addr = base + offset;
298
299  /* If little endian load/store is enabled we adjust the byte and half-word
300     addresses to the little endian equivalent.  */
301  if (GET_H_SYS_SR_LEE ())
302    {
303      switch (size)
304	{
305
306	case 4: /* We are retrieving the entire word no adjustment.  */
307	  break;
308
309	case 2: /* Perform half-word adjustment 0 -> 2, 2 -> 0.  */
310	  addr ^= 0x2;
311	  break;
312
313	case 1: /* Perform byte adjustment, 0 -> 3, 2 -> 3, etc.  */
314	  addr ^= 0x3;
315	  break;
316
317	default:
318	  SIM_ASSERT (0);
319	  return 0;
320	}
321    }
322
323  return addr;
324}
325
326/* The find first 1 instruction returns the location of the first set bit
327   in the argument register.  */
328
329USI
330or1k32bf_ff1 (sim_cpu *current_cpu, USI val)
331{
332  USI bit;
333  USI ret;
334  for (bit = 1, ret = 1; bit; bit <<= 1, ret++)
335    {
336      if (val & bit)
337	return ret;
338    }
339  return 0;
340}
341
342/* The find last 1 instruction returns the location of the last set bit in
343   the argument register.  */
344
345USI
346or1k32bf_fl1 (sim_cpu *current_cpu, USI val)
347{
348  USI bit;
349  USI ret;
350  for (bit = 1 << 31, ret = 32; bit; bit >>= 1, ret--)
351    {
352      if (val & bit)
353	return ret;
354    }
355  return 0;
356}
357