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