1/* interp.c -- Simulator for Motorola 68HC11/68HC12
2   Copyright (C) 1999-2020 Free Software Foundation, Inc.
3   Written by Stephane Carrez (stcarrez@nerim.fr)
4
5This file is part of GDB, the GNU debugger.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "sim-main.h"
21#include "sim-assert.h"
22#include "sim-hw.h"
23#include "sim-options.h"
24#include "hw-tree.h"
25#include "hw-device.h"
26#include "hw-ports.h"
27#include "elf32-m68hc1x.h"
28
29#ifndef MONITOR_BASE
30# define MONITOR_BASE (0x0C000)
31# define MONITOR_SIZE (0x04000)
32#endif
33
34static void sim_get_info (SIM_DESC sd, char *cmd);
35
36struct sim_info_list
37{
38  const char *name;
39  const char *device;
40};
41
42struct sim_info_list dev_list_68hc11[] = {
43  {"cpu", "/m68hc11"},
44  {"timer", "/m68hc11/m68hc11tim"},
45  {"sio", "/m68hc11/m68hc11sio"},
46  {"spi", "/m68hc11/m68hc11spi"},
47  {"eeprom", "/m68hc11/m68hc11eepr"},
48  {0, 0}
49};
50
51struct sim_info_list dev_list_68hc12[] = {
52  {"cpu", "/m68hc12"},
53  {"timer", "/m68hc12/m68hc12tim"},
54  {"sio", "/m68hc12/m68hc12sio"},
55  {"spi", "/m68hc12/m68hc12spi"},
56  {"eeprom", "/m68hc12/m68hc12eepr"},
57  {0, 0}
58};
59
60/* Cover function of sim_state_free to free the cpu buffers as well.  */
61
62static void
63free_state (SIM_DESC sd)
64{
65  if (STATE_MODULES (sd) != NULL)
66    sim_module_uninstall (sd);
67
68  sim_state_free (sd);
69}
70
71/* Give some information about the simulator.  */
72static void
73sim_get_info (SIM_DESC sd, char *cmd)
74{
75  sim_cpu *cpu;
76
77  cpu = STATE_CPU (sd, 0);
78  if (cmd != 0 && (cmd[0] == ' ' || cmd[0] == '-'))
79    {
80      int i;
81      struct hw *hw_dev;
82      struct sim_info_list *dev_list;
83      const struct bfd_arch_info *arch;
84
85      arch = STATE_ARCHITECTURE (sd);
86      cmd++;
87
88      if (arch->arch == bfd_arch_m68hc11)
89        dev_list = dev_list_68hc11;
90      else
91        dev_list = dev_list_68hc12;
92
93      for (i = 0; dev_list[i].name; i++)
94	if (strcmp (cmd, dev_list[i].name) == 0)
95	  break;
96
97      if (dev_list[i].name == 0)
98	{
99	  sim_io_eprintf (sd, "Device '%s' not found.\n", cmd);
100	  sim_io_eprintf (sd, "Valid devices: cpu timer sio eeprom\n");
101	  return;
102	}
103      hw_dev = sim_hw_parse (sd, dev_list[i].device);
104      if (hw_dev == 0)
105	{
106	  sim_io_eprintf (sd, "Device '%s' not found\n", dev_list[i].device);
107	  return;
108	}
109      hw_ioctl (hw_dev, 23, 0);
110      return;
111    }
112
113  cpu_info (sd, cpu);
114  interrupts_info (sd, &cpu->cpu_interrupts);
115}
116
117
118void
119sim_board_reset (SIM_DESC sd)
120{
121  struct hw *hw_cpu;
122  sim_cpu *cpu;
123  const struct bfd_arch_info *arch;
124  const char *cpu_type;
125
126  cpu = STATE_CPU (sd, 0);
127  arch = STATE_ARCHITECTURE (sd);
128
129  /*  hw_cpu = sim_hw_parse (sd, "/"); */
130  if (arch->arch == bfd_arch_m68hc11)
131    {
132      cpu->cpu_type = CPU_M6811;
133      cpu_type = "/m68hc11";
134    }
135  else
136    {
137      cpu->cpu_type = CPU_M6812;
138      cpu_type = "/m68hc12";
139    }
140
141  hw_cpu = sim_hw_parse (sd, cpu_type);
142  if (hw_cpu == 0)
143    {
144      sim_io_eprintf (sd, "%s cpu not found in device tree.", cpu_type);
145      return;
146    }
147
148  cpu_reset (cpu);
149  hw_port_event (hw_cpu, 3, 0);
150  cpu_restart (cpu);
151}
152
153static int
154sim_hw_configure (SIM_DESC sd)
155{
156  const struct bfd_arch_info *arch;
157  struct hw *device_tree;
158  sim_cpu *cpu;
159
160  arch = STATE_ARCHITECTURE (sd);
161  if (arch == 0)
162    return 0;
163
164  cpu = STATE_CPU (sd, 0);
165  cpu->cpu_configured_arch = arch;
166  device_tree = sim_hw_parse (sd, "/");
167  if (arch->arch == bfd_arch_m68hc11)
168    {
169      cpu->cpu_interpretor = cpu_interp_m6811;
170      if (hw_tree_find_property (device_tree, "/m68hc11/reg") == 0)
171	{
172	  /* Allocate core managed memory */
173
174	  /* the monitor  */
175	  sim_do_commandf (sd, "memory region 0x%lx@%d,0x%lx",
176			   /* MONITOR_BASE, MONITOR_SIZE */
177			   0x8000, M6811_RAM_LEVEL, 0x8000);
178	  sim_do_commandf (sd, "memory region 0x000@%d,0x8000",
179			   M6811_RAM_LEVEL);
180	  sim_hw_parse (sd, "/m68hc11/reg 0x1000 0x03F");
181          if (cpu->bank_start < cpu->bank_end)
182            {
183              sim_do_commandf (sd, "memory region 0x%lx@%d,0x100000",
184                               cpu->bank_virtual, M6811_RAM_LEVEL);
185              sim_hw_parse (sd, "/m68hc11/use_bank 1");
186            }
187	}
188      if (cpu->cpu_start_mode)
189        {
190          sim_hw_parse (sd, "/m68hc11/mode %s", cpu->cpu_start_mode);
191        }
192      if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11sio/reg") == 0)
193	{
194	  sim_hw_parse (sd, "/m68hc11/m68hc11sio/reg 0x2b 0x5");
195	  sim_hw_parse (sd, "/m68hc11/m68hc11sio/backend stdio");
196	  sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11sio");
197	}
198      if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11tim/reg") == 0)
199	{
200	  /* M68hc11 Timer configuration. */
201	  sim_hw_parse (sd, "/m68hc11/m68hc11tim/reg 0x1b 0x5");
202	  sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11tim");
203          sim_hw_parse (sd, "/m68hc11 > capture capture /m68hc11/m68hc11tim");
204	}
205
206      /* Create the SPI device.  */
207      if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11spi/reg") == 0)
208	{
209	  sim_hw_parse (sd, "/m68hc11/m68hc11spi/reg 0x28 0x3");
210	  sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11spi");
211	}
212      if (hw_tree_find_property (device_tree, "/m68hc11/nvram/reg") == 0)
213	{
214	  /* M68hc11 persistent ram configuration. */
215	  sim_hw_parse (sd, "/m68hc11/nvram/reg 0x0 256");
216	  sim_hw_parse (sd, "/m68hc11/nvram/file m68hc11.ram");
217	  sim_hw_parse (sd, "/m68hc11/nvram/mode save-modified");
218	  /*sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/pram"); */
219	}
220      if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11eepr/reg") == 0)
221	{
222	  sim_hw_parse (sd, "/m68hc11/m68hc11eepr/reg 0xb000 512");
223	  sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr");
224	}
225      sim_hw_parse (sd, "/m68hc11 > port-a cpu-write-port /m68hc11");
226      sim_hw_parse (sd, "/m68hc11 > port-b cpu-write-port /m68hc11");
227      sim_hw_parse (sd, "/m68hc11 > port-c cpu-write-port /m68hc11");
228      sim_hw_parse (sd, "/m68hc11 > port-d cpu-write-port /m68hc11");
229      cpu->hw_cpu = sim_hw_parse (sd, "/m68hc11");
230    }
231  else
232    {
233      cpu->cpu_interpretor = cpu_interp_m6812;
234      if (hw_tree_find_property (device_tree, "/m68hc12/reg") == 0)
235	{
236	  /* Allocate core external memory.  */
237	  sim_do_commandf (sd, "memory region 0x%lx@%d,0x%lx",
238			   0x8000, M6811_RAM_LEVEL, 0x8000);
239	  sim_do_commandf (sd, "memory region 0x000@%d,0x8000",
240			   M6811_RAM_LEVEL);
241          if (cpu->bank_start < cpu->bank_end)
242            {
243              sim_do_commandf (sd, "memory region 0x%lx@%d,0x100000",
244                               cpu->bank_virtual, M6811_RAM_LEVEL);
245              sim_hw_parse (sd, "/m68hc12/use_bank 1");
246            }
247	  sim_hw_parse (sd, "/m68hc12/reg 0x0 0x3FF");
248	}
249
250      if (!hw_tree_find_property (device_tree, "/m68hc12/m68hc12sio@1/reg"))
251	{
252	  sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/reg 0xC0 0x8");
253	  sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/backend stdio");
254	  sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12sio@1");
255	}
256      if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12tim/reg") == 0)
257	{
258	  /* M68hc11 Timer configuration. */
259	  sim_hw_parse (sd, "/m68hc12/m68hc12tim/reg 0x1b 0x5");
260	  sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12tim");
261          sim_hw_parse (sd, "/m68hc12 > capture capture /m68hc12/m68hc12tim");
262	}
263
264      /* Create the SPI device.  */
265      if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12spi/reg") == 0)
266	{
267	  sim_hw_parse (sd, "/m68hc12/m68hc12spi/reg 0x28 0x3");
268	  sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12spi");
269	}
270      if (hw_tree_find_property (device_tree, "/m68hc12/nvram/reg") == 0)
271	{
272	  /* M68hc11 persistent ram configuration. */
273	  sim_hw_parse (sd, "/m68hc12/nvram/reg 0x2000 8192");
274	  sim_hw_parse (sd, "/m68hc12/nvram/file m68hc12.ram");
275	  sim_hw_parse (sd, "/m68hc12/nvram/mode save-modified");
276	}
277      if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12eepr/reg") == 0)
278	{
279	  sim_hw_parse (sd, "/m68hc12/m68hc12eepr/reg 0x0800 2048");
280	  sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12eepr");
281	}
282
283      sim_hw_parse (sd, "/m68hc12 > port-a cpu-write-port /m68hc12");
284      sim_hw_parse (sd, "/m68hc12 > port-b cpu-write-port /m68hc12");
285      sim_hw_parse (sd, "/m68hc12 > port-c cpu-write-port /m68hc12");
286      sim_hw_parse (sd, "/m68hc12 > port-d cpu-write-port /m68hc12");
287      cpu->hw_cpu = sim_hw_parse (sd, "/m68hc12");
288    }
289  return 1;
290}
291
292/* Get the memory bank parameters by looking at the global symbols
293   defined by the linker.  */
294static int
295sim_get_bank_parameters (SIM_DESC sd)
296{
297  sim_cpu *cpu;
298  unsigned size;
299  bfd_vma addr;
300
301  cpu = STATE_CPU (sd, 0);
302
303  addr = trace_sym_value (sd, BFD_M68HC11_BANK_START_NAME);
304  if (addr != -1)
305    cpu->bank_start = addr;
306
307  size = trace_sym_value (sd, BFD_M68HC11_BANK_SIZE_NAME);
308  if (size == -1)
309    size = 0;
310
311  addr = trace_sym_value (sd, BFD_M68HC11_BANK_VIRTUAL_NAME);
312  if (addr != -1)
313    cpu->bank_virtual = addr;
314
315  cpu->bank_end = cpu->bank_start + size;
316  cpu->bank_shift = 0;
317  for (; size > 1; size >>= 1)
318    cpu->bank_shift++;
319
320  return 0;
321}
322
323static int
324sim_prepare_for_program (SIM_DESC sd, bfd* abfd)
325{
326  sim_cpu *cpu;
327  int elf_flags = 0;
328
329  cpu = STATE_CPU (sd, 0);
330
331  if (abfd != NULL)
332    {
333      asection *s;
334
335      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
336        elf_flags = elf_elfheader (abfd)->e_flags;
337
338      cpu->cpu_elf_start = bfd_get_start_address (abfd);
339      /* See if any section sets the reset address */
340      cpu->cpu_use_elf_start = 1;
341      for (s = abfd->sections; s && cpu->cpu_use_elf_start; s = s->next)
342        {
343          if (s->flags & SEC_LOAD)
344            {
345              bfd_size_type size;
346
347	      size = bfd_section_size (s);
348              if (size > 0)
349                {
350                  bfd_vma lma;
351
352                  if (STATE_LOAD_AT_LMA_P (sd))
353		    lma = bfd_section_lma (s);
354                  else
355		    lma = bfd_section_vma (s);
356
357                  if (lma <= 0xFFFE && lma+size >= 0x10000)
358                    cpu->cpu_use_elf_start = 0;
359                }
360            }
361        }
362
363      if (elf_flags & E_M68HC12_BANKS)
364        {
365          if (sim_get_bank_parameters (sd) != 0)
366            sim_io_eprintf (sd, "Memory bank parameters are not initialized\n");
367        }
368    }
369
370  if (!sim_hw_configure (sd))
371    return SIM_RC_FAIL;
372
373  /* reset all state information */
374  sim_board_reset (sd);
375
376  return SIM_RC_OK;
377}
378
379static sim_cia
380m68hc11_pc_get (sim_cpu *cpu)
381{
382  return cpu_get_pc (cpu);
383}
384
385static void
386m68hc11_pc_set (sim_cpu *cpu, sim_cia pc)
387{
388  cpu_set_pc (cpu, pc);
389}
390
391static int m68hc11_reg_fetch (SIM_CPU *, int, unsigned char *, int);
392static int m68hc11_reg_store (SIM_CPU *, int, unsigned char *, int);
393
394SIM_DESC
395sim_open (SIM_OPEN_KIND kind, host_callback *callback,
396	  bfd *abfd, char * const *argv)
397{
398  int i;
399  SIM_DESC sd;
400  sim_cpu *cpu;
401
402  sd = sim_state_alloc (kind, callback);
403
404  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
405
406  /* The cpu data is kept in a separately allocated chunk of memory.  */
407  if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
408    {
409      free_state (sd);
410      return 0;
411    }
412
413  cpu = STATE_CPU (sd, 0);
414
415  cpu_initialize (sd, cpu);
416
417  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
418    {
419      free_state (sd);
420      return 0;
421    }
422
423  /* The parser will print an error message for us, so we silently return.  */
424  if (sim_parse_args (sd, argv) != SIM_RC_OK)
425    {
426      /* Uninstall the modules to avoid memory leaks,
427         file descriptor leaks, etc.  */
428      free_state (sd);
429      return 0;
430    }
431
432  /* Check for/establish the a reference program image.  */
433  if (sim_analyze_program (sd,
434			   (STATE_PROG_ARGV (sd) != NULL
435			    ? *STATE_PROG_ARGV (sd)
436			    : NULL), abfd) != SIM_RC_OK)
437    {
438      free_state (sd);
439      return 0;
440    }
441
442  /* Establish any remaining configuration options.  */
443  if (sim_config (sd) != SIM_RC_OK)
444    {
445      free_state (sd);
446      return 0;
447    }
448
449  if (sim_post_argv_init (sd) != SIM_RC_OK)
450    {
451      /* Uninstall the modules to avoid memory leaks,
452         file descriptor leaks, etc.  */
453      free_state (sd);
454      return 0;
455    }
456  if (sim_prepare_for_program (sd, abfd) != SIM_RC_OK)
457    {
458      free_state (sd);
459      return 0;
460    }
461
462  /* CPU specific initialization.  */
463  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
464    {
465      SIM_CPU *cpu = STATE_CPU (sd, i);
466
467      CPU_REG_FETCH (cpu) = m68hc11_reg_fetch;
468      CPU_REG_STORE (cpu) = m68hc11_reg_store;
469      CPU_PC_FETCH (cpu) = m68hc11_pc_get;
470      CPU_PC_STORE (cpu) = m68hc11_pc_set;
471    }
472
473  return sd;
474}
475
476/* Generic implementation of sim_engine_run that works within the
477   sim_engine setjmp/longjmp framework. */
478
479void
480sim_engine_run (SIM_DESC sd,
481                int next_cpu_nr,	/* ignore */
482		int nr_cpus,	/* ignore */
483		int siggnal)	/* ignore */
484{
485  sim_cpu *cpu;
486
487  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
488  cpu = STATE_CPU (sd, 0);
489  while (1)
490    {
491      cpu_single_step (cpu);
492
493      /* process any events */
494      if (sim_events_tickn (sd, cpu->cpu_current_cycle))
495	{
496	  sim_events_process (sd);
497	}
498    }
499}
500
501void
502sim_info (SIM_DESC sd, int verbose)
503{
504  const char *cpu_type;
505  const struct bfd_arch_info *arch;
506
507  /* Nothing to do if there is no verbose flag set.  */
508  if (verbose == 0 && STATE_VERBOSE_P (sd) == 0)
509    return;
510
511  arch = STATE_ARCHITECTURE (sd);
512  if (arch->arch == bfd_arch_m68hc11)
513    cpu_type = "68HC11";
514  else
515    cpu_type = "68HC12";
516
517  sim_io_eprintf (sd, "Simulator info:\n");
518  sim_io_eprintf (sd, "  CPU Motorola %s\n", cpu_type);
519  sim_get_info (sd, 0);
520  sim_module_info (sd, verbose || STATE_VERBOSE_P (sd));
521}
522
523SIM_RC
524sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
525                     char * const *argv, char * const *env)
526{
527  return sim_prepare_for_program (sd, abfd);
528}
529
530static int
531m68hc11_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
532{
533  uint16 val;
534  int size = 2;
535
536  switch (rn)
537    {
538    case A_REGNUM:
539      val = cpu_get_a (cpu);
540      size = 1;
541      break;
542
543    case B_REGNUM:
544      val = cpu_get_b (cpu);
545      size = 1;
546      break;
547
548    case D_REGNUM:
549      val = cpu_get_d (cpu);
550      break;
551
552    case X_REGNUM:
553      val = cpu_get_x (cpu);
554      break;
555
556    case Y_REGNUM:
557      val = cpu_get_y (cpu);
558      break;
559
560    case SP_REGNUM:
561      val = cpu_get_sp (cpu);
562      break;
563
564    case PC_REGNUM:
565      val = cpu_get_pc (cpu);
566      break;
567
568    case PSW_REGNUM:
569      val = cpu_get_ccr (cpu);
570      size = 1;
571      break;
572
573    case PAGE_REGNUM:
574      val = cpu_get_page (cpu);
575      size = 1;
576      break;
577
578    default:
579      val = 0;
580      break;
581    }
582  if (size == 1)
583    {
584      memory[0] = val;
585    }
586  else
587    {
588      memory[0] = val >> 8;
589      memory[1] = val & 0x0FF;
590    }
591  return size;
592}
593
594static int
595m68hc11_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
596{
597  uint16 val;
598
599  val = *memory++;
600  if (length == 2)
601    val = (val << 8) | *memory;
602
603  switch (rn)
604    {
605    case D_REGNUM:
606      cpu_set_d (cpu, val);
607      break;
608
609    case A_REGNUM:
610      cpu_set_a (cpu, val);
611      return 1;
612
613    case B_REGNUM:
614      cpu_set_b (cpu, val);
615      return 1;
616
617    case X_REGNUM:
618      cpu_set_x (cpu, val);
619      break;
620
621    case Y_REGNUM:
622      cpu_set_y (cpu, val);
623      break;
624
625    case SP_REGNUM:
626      cpu_set_sp (cpu, val);
627      break;
628
629    case PC_REGNUM:
630      cpu_set_pc (cpu, val);
631      break;
632
633    case PSW_REGNUM:
634      cpu_set_ccr (cpu, val);
635      return 1;
636
637    case PAGE_REGNUM:
638      cpu_set_page (cpu, val);
639      return 1;
640
641    default:
642      break;
643    }
644
645  return 2;
646}
647