Automatic date update in version.in
[external/binutils.git] / sim / microblaze / interp.c
1 /* Simulator for Xilinx MicroBlaze processor
2    Copyright 2009-2019 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 #include "config.h"
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include "bfd.h"
25 #include "gdb/callback.h"
26 #include "libiberty.h"
27 #include "gdb/remote-sim.h"
28
29 #include "sim-main.h"
30 #include "sim-options.h"
31
32 #include "microblaze-dis.h"
33
34 #define target_big_endian (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
35
36 static unsigned long
37 microblaze_extract_unsigned_integer (unsigned char *addr, int len)
38 {
39   unsigned long retval;
40   unsigned char *p;
41   unsigned char *startaddr = (unsigned char *)addr;
42   unsigned char *endaddr = startaddr + len;
43
44   if (len > (int) sizeof (unsigned long))
45     printf ("That operation is not available on integers of more than "
46             "%zu bytes.", sizeof (unsigned long));
47
48   /* Start at the most significant end of the integer, and work towards
49      the least significant.  */
50   retval = 0;
51
52   if (!target_big_endian)
53     {
54       for (p = endaddr; p > startaddr;)
55         retval = (retval << 8) | * -- p;
56     }
57   else
58     {
59       for (p = startaddr; p < endaddr;)
60         retval = (retval << 8) | * p ++;
61     }
62
63   return retval;
64 }
65
66 static void
67 microblaze_store_unsigned_integer (unsigned char *addr, int len,
68                                    unsigned long val)
69 {
70   unsigned char *p;
71   unsigned char *startaddr = (unsigned char *)addr;
72   unsigned char *endaddr = startaddr + len;
73
74   if (!target_big_endian)
75     {
76       for (p = startaddr; p < endaddr;)
77         {
78           *p++ = val & 0xff;
79           val >>= 8;
80         }
81     }
82   else
83     {
84       for (p = endaddr; p > startaddr;)
85         {
86           *--p = val & 0xff;
87           val >>= 8;
88         }
89     }
90 }
91
92 static void
93 set_initial_gprs (SIM_CPU *cpu)
94 {
95   int i;
96   long space;
97
98   /* Set up machine just out of reset.  */
99   PC = 0;
100   MSR = 0;
101
102   /* Clean out the GPRs */
103   for (i = 0; i < 32; i++)
104     CPU.regs[i] = 0;
105   CPU.insts = 0;
106   CPU.cycles = 0;
107   CPU.imm_enable = 0;
108 }
109
110 static int tracing = 0;
111
112 void
113 sim_engine_run (SIM_DESC sd,
114                 int next_cpu_nr, /* ignore  */
115                 int nr_cpus, /* ignore  */
116                 int siggnal) /* ignore  */
117 {
118   SIM_CPU *cpu = STATE_CPU (sd, 0);
119   int needfetch;
120   word inst;
121   enum microblaze_instr op;
122   int memops;
123   int bonus_cycles;
124   int insts;
125   int w;
126   int cycs;
127   word WLhash;
128   ubyte carry;
129   int imm_unsigned;
130   short ra, rb, rd;
131   long immword;
132   uword oldpc, newpc;
133   short delay_slot_enable;
134   short branch_taken;
135   short num_delay_slot; /* UNUSED except as reqd parameter */
136   enum microblaze_instr_type insn_type;
137
138   memops = 0;
139   bonus_cycles = 0;
140   insts = 0;
141
142   while (1)
143     {
144       /* Fetch the initial instructions that we'll decode. */
145       inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
146
147       op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
148                                 &num_delay_slot);
149
150       if (op == invalid_inst)
151         fprintf (stderr, "Unknown instruction 0x%04x", inst);
152
153       if (tracing)
154         fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
155
156       rd = GET_RD;
157       rb = GET_RB;
158       ra = GET_RA;
159       /*      immword = IMM_W; */
160
161       oldpc = PC;
162       delay_slot_enable = 0;
163       branch_taken = 0;
164       if (op == microblaze_brk)
165         sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
166       else if (inst == MICROBLAZE_HALT_INST)
167         {
168           insts += 1;
169           bonus_cycles++;
170           sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_exited, RETREG);
171         }
172       else
173         {
174           switch(op)
175             {
176 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION)         \
177             case NAME:                                  \
178               ACTION;                                   \
179               break;
180 #include "microblaze.isa"
181 #undef INSTRUCTION
182
183             default:
184               sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
185                                SIM_SIGILL);
186               fprintf (stderr, "ERROR: Unknown opcode\n");
187             }
188           /* Make R0 consistent */
189           CPU.regs[0] = 0;
190
191           /* Check for imm instr */
192           if (op == imm)
193             IMM_ENABLE = 1;
194           else
195             IMM_ENABLE = 0;
196
197           /* Update cycle counts */
198           insts ++;
199           if (insn_type == memory_store_inst || insn_type == memory_load_inst)
200             memops++;
201           if (insn_type == mult_inst)
202             bonus_cycles++;
203           if (insn_type == barrel_shift_inst)
204             bonus_cycles++;
205           if (insn_type == anyware_inst)
206             bonus_cycles++;
207           if (insn_type == div_inst)
208             bonus_cycles += 33;
209
210           if ((insn_type == branch_inst || insn_type == return_inst)
211               && branch_taken)
212             {
213               /* Add an extra cycle for taken branches */
214               bonus_cycles++;
215               /* For branch instructions handle the instruction in the delay slot */
216               if (delay_slot_enable)
217                 {
218                   newpc = PC;
219                   PC = oldpc + INST_SIZE;
220                   inst = MEM_RD_WORD (PC & 0xFFFFFFFC);
221                   op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
222                                             &num_delay_slot);
223                   if (op == invalid_inst)
224                     fprintf (stderr, "Unknown instruction 0x%04x", inst);
225                   if (tracing)
226                     fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
227                   rd = GET_RD;
228                   rb = GET_RB;
229                   ra = GET_RA;
230                   /*          immword = IMM_W; */
231                   if (op == microblaze_brk)
232                     {
233                       if (STATE_VERBOSE_P (sd))
234                         fprintf (stderr, "Breakpoint set in delay slot "
235                                  "(at address 0x%x) will not be honored\n", PC);
236                       /* ignore the breakpoint */
237                     }
238                   else if (insn_type == branch_inst || insn_type == return_inst)
239                     {
240                       if (STATE_VERBOSE_P (sd))
241                         fprintf (stderr, "Cannot have branch or return instructions "
242                                  "in delay slot (at address 0x%x)\n", PC);
243                       sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_signalled,
244                                        SIM_SIGILL);
245                     }
246                   else
247                     {
248                       switch(op)
249                         {
250 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION)         \
251                         case NAME:                      \
252                           ACTION;                       \
253                           break;
254 #include "microblaze.isa"
255 #undef INSTRUCTION
256
257                         default:
258                           sim_engine_halt (sd, NULL, NULL, NULL_CIA,
259                                            sim_signalled, SIM_SIGILL);
260                           fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
261                         }
262                       /* Update cycle counts */
263                       insts++;
264                       if (insn_type == memory_store_inst
265                           || insn_type == memory_load_inst)
266                         memops++;
267                       if (insn_type == mult_inst)
268                         bonus_cycles++;
269                       if (insn_type == barrel_shift_inst)
270                         bonus_cycles++;
271                       if (insn_type == anyware_inst)
272                         bonus_cycles++;
273                       if (insn_type == div_inst)
274                         bonus_cycles += 33;
275                     }
276                   /* Restore the PC */
277                   PC = newpc;
278                   /* Make R0 consistent */
279                   CPU.regs[0] = 0;
280                   /* Check for imm instr */
281                   if (op == imm)
282                     IMM_ENABLE = 1;
283                   else
284                     IMM_ENABLE = 0;
285                 }
286               else
287                 /* no delay slot: increment cycle count */
288                 bonus_cycles++;
289             }
290         }
291
292       if (tracing)
293         fprintf (stderr, "\n");
294
295       if (sim_events_tick (sd))
296         sim_events_process (sd);
297     }
298
299   /* Hide away the things we've cached while executing.  */
300   /*  CPU.pc = pc; */
301   CPU.insts += insts;           /* instructions done ... */
302   CPU.cycles += insts;          /* and each takes a cycle */
303   CPU.cycles += bonus_cycles;   /* and extra cycles for branches */
304   CPU.cycles += memops;         /* and memop cycle delays */
305 }
306
307 static int
308 microblaze_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
309 {
310   if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
311     {
312       if (length == 4)
313         {
314           /* misalignment safe */
315           long ival = microblaze_extract_unsigned_integer (memory, 4);
316           if (rn < NUM_REGS)
317             CPU.regs[rn] = ival;
318           else
319             CPU.spregs[rn-NUM_REGS] = ival;
320           return 4;
321         }
322       else
323         return 0;
324     }
325   else
326     return 0;
327 }
328
329 static int
330 microblaze_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
331 {
332   long ival;
333
334   if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
335     {
336       if (length == 4)
337         {
338           if (rn < NUM_REGS)
339             ival = CPU.regs[rn];
340           else
341             ival = CPU.spregs[rn-NUM_REGS];
342
343           /* misalignment-safe */
344           microblaze_store_unsigned_integer (memory, 4, ival);
345           return 4;
346         }
347       else
348         return 0;
349     }
350   else
351     return 0;
352 }
353
354 void
355 sim_info (SIM_DESC sd, int verbose)
356 {
357   SIM_CPU *cpu = STATE_CPU (sd, 0);
358   host_callback *callback = STATE_CALLBACK (sd);
359
360   callback->printf_filtered (callback, "\n\n# instructions executed  %10d\n",
361                              CPU.insts);
362   callback->printf_filtered (callback, "# cycles                 %10d\n",
363                              (CPU.cycles) ? CPU.cycles+2 : 0);
364 }
365
366 static sim_cia
367 microblaze_pc_get (sim_cpu *cpu)
368 {
369   return cpu->microblaze_cpu.spregs[0];
370 }
371
372 static void
373 microblaze_pc_set (sim_cpu *cpu, sim_cia pc)
374 {
375   cpu->microblaze_cpu.spregs[0] = pc;
376 }
377
378 static void
379 free_state (SIM_DESC sd)
380 {
381   if (STATE_MODULES (sd) != NULL)
382     sim_module_uninstall (sd);
383   sim_cpu_free_all (sd);
384   sim_state_free (sd);
385 }
386
387 SIM_DESC
388 sim_open (SIM_OPEN_KIND kind, host_callback *cb,
389           struct bfd *abfd, char * const *argv)
390 {
391   int i;
392   SIM_DESC sd = sim_state_alloc (kind, cb);
393   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
394
395   /* The cpu data is kept in a separately allocated chunk of memory.  */
396   if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
397     {
398       free_state (sd);
399       return 0;
400     }
401
402   if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
403     {
404       free_state (sd);
405       return 0;
406     }
407
408   /* The parser will print an error message for us, so we silently return.  */
409   if (sim_parse_args (sd, argv) != SIM_RC_OK)
410     {
411       free_state (sd);
412       return 0;
413     }
414
415   /* Check for/establish the a reference program image.  */
416   if (sim_analyze_program (sd,
417                            (STATE_PROG_ARGV (sd) != NULL
418                             ? *STATE_PROG_ARGV (sd)
419                             : NULL), abfd) != SIM_RC_OK)
420     {
421       free_state (sd);
422       return 0;
423     }
424
425   /* Configure/verify the target byte order and other runtime
426      configuration options.  */
427   if (sim_config (sd) != SIM_RC_OK)
428     {
429       sim_module_uninstall (sd);
430       return 0;
431     }
432
433   if (sim_post_argv_init (sd) != SIM_RC_OK)
434     {
435       /* Uninstall the modules to avoid memory leaks,
436          file descriptor leaks, etc.  */
437       sim_module_uninstall (sd);
438       return 0;
439     }
440
441   /* CPU specific initialization.  */
442   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
443     {
444       SIM_CPU *cpu = STATE_CPU (sd, i);
445
446       CPU_REG_FETCH (cpu) = microblaze_reg_fetch;
447       CPU_REG_STORE (cpu) = microblaze_reg_store;
448       CPU_PC_FETCH (cpu) = microblaze_pc_get;
449       CPU_PC_STORE (cpu) = microblaze_pc_set;
450
451       set_initial_gprs (cpu);
452     }
453
454   /* Default to a 8 Mbyte (== 2^23) memory space.  */
455   sim_do_commandf (sd, "memory-size 0x800000");
456
457   return sd;
458 }
459
460 SIM_RC
461 sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
462                      char * const *argv, char * const *env)
463 {
464   SIM_CPU *cpu = STATE_CPU (sd, 0);
465
466   PC = bfd_get_start_address (prog_bfd);
467
468   return SIM_RC_OK;
469 }