xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/m68hc11/interp.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
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 
5 This file is part of GDB, the GNU debugger.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along 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 
37 static void sim_get_info (SIM_DESC sd, char *cmd);
38 
39 struct sim_info_list
40 {
41   const char *name;
42   const char *device;
43 };
44 
45 struct 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 
54 struct 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 
65 static void
66 free_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.  */
75 static void
76 sim_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 
121 void
122 sim_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 
156 static int
157 sim_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.  */
297 static int
298 sim_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 
326 static int
327 sim_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 
382 static sim_cia
383 m68hc11_pc_get (sim_cpu *cpu)
384 {
385   return cpu_get_pc (cpu);
386 }
387 
388 static void
389 m68hc11_pc_set (sim_cpu *cpu, sim_cia pc)
390 {
391   cpu_set_pc (cpu, pc);
392 }
393 
394 static int m68hc11_reg_fetch (SIM_CPU *, int, void *, int);
395 static int m68hc11_reg_store (SIM_CPU *, int, const void *, int);
396 
397 SIM_DESC
398 sim_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 
482 void
483 sim_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 
504 void
505 sim_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 
526 SIM_RC
527 sim_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 
533 static int
534 m68hc11_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 
598 static int
599 m68hc11_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