* configure.host: Change irix5 to irix[56]*.
[deliverable/binutils-gdb.git] / gdb / h8300-tdep.c
1 /* Target-machine dependent code for Hitachi H8/300, for GDB.
2 Copyright (C) 1988, 1990, 1991 Free Software Foundation, Inc.
3
4 This file is part of GDB.
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 2 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, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20 /*
21 Contributed by Steve Chamberlain
22 sac@cygnus.com
23 */
24
25 #include "defs.h"
26 #include "frame.h"
27 #include "obstack.h"
28 #include "symtab.h"
29 #include "dis-asm.h"
30 #include "gdbcmd.h"
31 #include "gdbtypes.h"
32 #include "gdbcore.h"
33 #include "gdb_string.h"
34 #include "value.h"
35
36
37 #undef NUM_REGS
38 #define NUM_REGS 11
39
40 #define UNSIGNED_SHORT(X) ((X) & 0xffff)
41
42 #define IS_PUSH(x) ((x & 0xfff0)==0x6df0)
43 #define IS_PUSH_FP(x) (x == 0x6df6)
44 #define IS_MOVE_FP(x) (x == 0x0d76 || x == 0x0ff6)
45 #define IS_MOV_SP_FP(x) (x == 0x0d76 || x == 0x0ff6)
46 #define IS_SUB2_SP(x) (x==0x1b87)
47 #define IS_SUB4_SP(x) (x==0x1b97)
48 #define IS_SUBL_SP(x) (x==0x7a37)
49 #define IS_MOVK_R5(x) (x==0x7905)
50 #define IS_SUB_R5SP(x) (x==0x1957)
51
52 /* Local function declarations. */
53
54 static CORE_ADDR examine_prologue ();
55 static void set_machine_hook PARAMS ((char *filename));
56
57 void frame_find_saved_regs ();
58 CORE_ADDR
59 h8300_skip_prologue (start_pc)
60 CORE_ADDR start_pc;
61 {
62 short int w;
63 int adjust = 0;
64
65 /* Skip past all push and stm insns. */
66 while (1)
67 {
68 w = read_memory_unsigned_integer (start_pc, 2);
69 /* First look for push insns. */
70 if (w == 0x0100 || w == 0x0110 || w == 0x0120 || w == 0x0130)
71 {
72 w = read_memory_unsigned_integer (start_pc + 2, 2);
73 adjust = 2;
74 }
75
76 if (IS_PUSH (w))
77 {
78 start_pc += 2 + adjust;
79 w = read_memory_unsigned_integer (start_pc, 2);
80 continue;
81 }
82 adjust = 0;
83 break;
84 }
85
86 /* Skip past a move to FP, either word or long sized */
87 w = read_memory_unsigned_integer (start_pc, 2);
88 if (w == 0x0100)
89 {
90 w = read_memory_unsigned_integer (start_pc + 2, 2);
91 adjust += 2;
92 }
93
94 if (IS_MOVE_FP (w))
95 {
96 start_pc += 2 + adjust;
97 w = read_memory_unsigned_integer (start_pc, 2);
98 }
99
100 /* Check for loading either a word constant into r5;
101 long versions are handled by the SUBL_SP below. */
102 if (IS_MOVK_R5 (w))
103 {
104 start_pc += 2;
105 w = read_memory_unsigned_integer (start_pc, 2);
106 }
107
108 /* Now check for subtracting r5 from sp, word sized only. */
109 if (IS_SUB_R5SP (w))
110 {
111 start_pc += 2 + adjust;
112 w = read_memory_unsigned_integer (start_pc, 2);
113 }
114
115 /* Check for subs #2 and subs #4. */
116 while (IS_SUB2_SP (w) || IS_SUB4_SP (w))
117 {
118 start_pc += 2 + adjust;
119 w = read_memory_unsigned_integer (start_pc, 2);
120 }
121
122 /* Check for a 32bit subtract. */
123 if (IS_SUBL_SP (w))
124 start_pc += 6 + adjust;
125
126 return start_pc;
127 }
128
129 int
130 gdb_print_insn_h8300 (memaddr, info)
131 bfd_vma memaddr;
132 disassemble_info *info;
133 {
134 if (h8300smode)
135 return print_insn_h8300s (memaddr, info);
136 else if (h8300hmode)
137 return print_insn_h8300h (memaddr, info);
138 else
139 return print_insn_h8300 (memaddr, info);
140 }
141
142 /* Given a GDB frame, determine the address of the calling function's frame.
143 This will be used to create a new GDB frame struct, and then
144 INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
145
146 For us, the frame address is its stack pointer value, so we look up
147 the function prologue to determine the caller's sp value, and return it. */
148
149 CORE_ADDR
150 h8300_frame_chain (thisframe)
151 struct frame_info *thisframe;
152 {
153 frame_find_saved_regs (thisframe, (struct frame_saved_regs *) 0);
154 return thisframe->fsr->regs[SP_REGNUM];
155 }
156
157 /* Put here the code to store, into a struct frame_saved_regs,
158 the addresses of the saved registers of frame described by FRAME_INFO.
159 This includes special registers such as pc and fp saved in special
160 ways in the stack frame. sp is even more special:
161 the address we return for it IS the sp for the next frame.
162
163 We cache the result of doing this in the frame_cache_obstack, since
164 it is fairly expensive. */
165
166 void
167 frame_find_saved_regs (fi, fsr)
168 struct frame_info *fi;
169 struct frame_saved_regs *fsr;
170 {
171 register struct frame_saved_regs *cache_fsr;
172 extern struct obstack frame_cache_obstack;
173 CORE_ADDR ip;
174 struct symtab_and_line sal;
175 CORE_ADDR limit;
176
177 if (!fi->fsr)
178 {
179 cache_fsr = (struct frame_saved_regs *)
180 obstack_alloc (&frame_cache_obstack,
181 sizeof (struct frame_saved_regs));
182 memset (cache_fsr, '\0', sizeof (struct frame_saved_regs));
183
184 fi->fsr = cache_fsr;
185
186 /* Find the start and end of the function prologue. If the PC
187 is in the function prologue, we only consider the part that
188 has executed already. */
189
190 ip = get_pc_function_start (fi->pc);
191 sal = find_pc_line (ip, 0);
192 limit = (sal.end && sal.end < fi->pc) ? sal.end : fi->pc;
193
194 /* This will fill in fields in *fi as well as in cache_fsr. */
195 examine_prologue (ip, limit, fi->frame, cache_fsr, fi);
196 }
197
198 if (fsr)
199 *fsr = *fi->fsr;
200 }
201
202 /* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or
203 is not the address of a valid instruction, the address of the next
204 instruction beyond ADDR otherwise. *PWORD1 receives the first word
205 of the instruction.*/
206
207 CORE_ADDR
208 NEXT_PROLOGUE_INSN (addr, lim, pword1)
209 CORE_ADDR addr;
210 CORE_ADDR lim;
211 INSN_WORD *pword1;
212 {
213 char buf[2];
214 if (addr < lim + 8)
215 {
216 read_memory (addr, buf, 2);
217 *pword1 = extract_signed_integer (buf, 2);
218
219 return addr + 2;
220 }
221 return 0;
222 }
223
224 /* Examine the prologue of a function. `ip' points to the first instruction.
225 `limit' is the limit of the prologue (e.g. the addr of the first
226 linenumber, or perhaps the program counter if we're stepping through).
227 `frame_sp' is the stack pointer value in use in this frame.
228 `fsr' is a pointer to a frame_saved_regs structure into which we put
229 info about the registers saved by this frame.
230 `fi' is a struct frame_info pointer; we fill in various fields in it
231 to reflect the offsets of the arg pointer and the locals pointer. */
232
233 static CORE_ADDR
234 examine_prologue (ip, limit, after_prolog_fp, fsr, fi)
235 register CORE_ADDR ip;
236 register CORE_ADDR limit;
237 CORE_ADDR after_prolog_fp;
238 struct frame_saved_regs *fsr;
239 struct frame_info *fi;
240 {
241 register CORE_ADDR next_ip;
242 int r;
243 int have_fp = 0;
244 INSN_WORD insn_word;
245 /* Number of things pushed onto stack, starts at 2/4, 'cause the
246 PC is already there */
247 unsigned int reg_save_depth = h8300hmode ? 4 : 2;
248
249 unsigned int auto_depth = 0; /* Number of bytes of autos */
250
251 char in_frame[11]; /* One for each reg */
252
253 int adjust = 0;
254
255 memset (in_frame, 1, 11);
256 for (r = 0; r < 8; r++)
257 {
258 fsr->regs[r] = 0;
259 }
260 if (after_prolog_fp == 0)
261 {
262 after_prolog_fp = read_register (SP_REGNUM);
263 }
264
265 /* If the PC isn't valid, quit now. */
266 if (ip == 0 || ip & (h8300hmode ? ~0xffffff : ~0xffff))
267 return 0;
268
269 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
270
271 if (insn_word == 0x0100)
272 {
273 insn_word = read_memory_unsigned_integer (ip + 2, 2);
274 adjust = 2;
275 }
276
277 /* Skip over any fp push instructions */
278 fsr->regs[6] = after_prolog_fp;
279 while (next_ip && IS_PUSH_FP (insn_word))
280 {
281 ip = next_ip + adjust;
282
283 in_frame[insn_word & 0x7] = reg_save_depth;
284 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
285 reg_save_depth += 2 + adjust;
286 }
287
288 /* Is this a move into the fp */
289 if (next_ip && IS_MOV_SP_FP (insn_word))
290 {
291 ip = next_ip;
292 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
293 have_fp = 1;
294 }
295
296 /* Skip over any stack adjustment, happens either with a number of
297 sub#2,sp or a mov #x,r5 sub r5,sp */
298
299 if (next_ip && (IS_SUB2_SP (insn_word) || IS_SUB4_SP (insn_word)))
300 {
301 while (next_ip && (IS_SUB2_SP (insn_word) || IS_SUB4_SP (insn_word)))
302 {
303 auto_depth += IS_SUB2_SP (insn_word) ? 2 : 4;
304 ip = next_ip;
305 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
306 }
307 }
308 else
309 {
310 if (next_ip && IS_MOVK_R5 (insn_word))
311 {
312 ip = next_ip;
313 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
314 auto_depth += insn_word;
315
316 next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn_word);
317 auto_depth += insn_word;
318 }
319 if (next_ip && IS_SUBL_SP (insn_word))
320 {
321 ip = next_ip;
322 auto_depth += read_memory_unsigned_integer (ip, 4);
323 ip += 4;
324
325 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
326 }
327 }
328
329 /* Now examine the push insns to determine where everything lives
330 on the stack. */
331 while (1)
332 {
333 adjust = 0;
334 if (!next_ip)
335 break;
336
337 if (insn_word == 0x0100)
338 {
339 ip = next_ip;
340 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
341 adjust = 2;
342 }
343
344 if (IS_PUSH (insn_word))
345 {
346 ip = next_ip;
347 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
348 fsr->regs[r] = after_prolog_fp + auto_depth;
349 auto_depth += 2 + adjust;
350 continue;
351 }
352
353 /* Now check for push multiple insns. */
354 if (insn_word == 0x0110 || insn_word == 0x0120 || insn_word == 0x0130)
355 {
356 int count = ((insn_word >> 4) & 0xf) + 1;
357 int start, i;
358
359 ip = next_ip;
360 next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
361 start = insn_word & 0x7;
362
363 for (i = start; i <= start + count; i++)
364 {
365 fsr->regs[i] = after_prolog_fp + auto_depth;
366 auto_depth += 4;
367 }
368 }
369 break;
370 }
371
372 /* The args are always reffed based from the stack pointer */
373 fi->args_pointer = after_prolog_fp;
374 /* Locals are always reffed based from the fp */
375 fi->locals_pointer = after_prolog_fp;
376 /* The PC is at a known place */
377 fi->from_pc = read_memory_unsigned_integer (after_prolog_fp + BINWORD, BINWORD);
378
379 /* Rememeber any others too */
380 in_frame[PC_REGNUM] = 0;
381
382 if (have_fp)
383 /* We keep the old FP in the SP spot */
384 fsr->regs[SP_REGNUM] = read_memory_unsigned_integer (fsr->regs[6], BINWORD);
385 else
386 fsr->regs[SP_REGNUM] = after_prolog_fp + auto_depth;
387
388 return (ip);
389 }
390
391 void
392 init_extra_frame_info (fromleaf, fi)
393 int fromleaf;
394 struct frame_info *fi;
395 {
396 fi->fsr = 0; /* Not yet allocated */
397 fi->args_pointer = 0; /* Unknown */
398 fi->locals_pointer = 0; /* Unknown */
399 fi->from_pc = 0;
400 }
401
402 /* Return the saved PC from this frame.
403
404 If the frame has a memory copy of SRP_REGNUM, use that. If not,
405 just use the register SRP_REGNUM itself. */
406
407 CORE_ADDR
408 frame_saved_pc (frame)
409 struct frame_info *frame;
410 {
411 return frame->from_pc;
412 }
413
414 CORE_ADDR
415 frame_locals_address (fi)
416 struct frame_info *fi;
417 {
418 if (!fi->locals_pointer)
419 {
420 struct frame_saved_regs ignore;
421
422 get_frame_saved_regs (fi, &ignore);
423
424 }
425 return fi->locals_pointer;
426 }
427
428 /* Return the address of the argument block for the frame
429 described by FI. Returns 0 if the address is unknown. */
430
431 CORE_ADDR
432 frame_args_address (fi)
433 struct frame_info *fi;
434 {
435 if (!fi->args_pointer)
436 {
437 struct frame_saved_regs ignore;
438
439 get_frame_saved_regs (fi, &ignore);
440
441 }
442
443 return fi->args_pointer;
444 }
445
446 void
447 h8300_pop_frame ()
448 {
449 unsigned regnum;
450 struct frame_saved_regs fsr;
451 struct frame_info *frame = get_current_frame ();
452
453 get_frame_saved_regs (frame, &fsr);
454
455 for (regnum = 0; regnum < 8; regnum++)
456 {
457 /* Don't forget SP_REGNUM is a frame_saved_regs struct is the
458 actual value we want, not the address of the value we want. */
459 if (fsr.regs[regnum] && regnum != SP_REGNUM)
460 write_register (regnum, read_memory_integer(fsr.regs[regnum], BINWORD));
461 else if (fsr.regs[regnum] && regnum == SP_REGNUM)
462 write_register (regnum, fsr.regs[regnum]);
463 }
464
465 /* Don't forget the update the PC too! */
466 write_pc (frame->from_pc);
467 flush_cached_frames ();
468 }
469
470
471 struct cmd_list_element *setmemorylist;
472
473 static void
474 h8300_command(args, from_tty)
475 {
476 extern int h8300hmode;
477 h8300hmode = 0;
478 h8300smode = 0;
479 }
480
481 static void
482 h8300h_command(args, from_tty)
483 {
484 extern int h8300hmode;
485 h8300hmode = 1;
486 h8300smode = 0;
487 }
488 static void
489 h8300s_command(args, from_tty)
490 {
491 extern int h8300smode;
492 extern int h8300hmode;
493 h8300smode = 1;
494 h8300hmode = 1;
495 }
496
497
498 static void
499 set_machine (args, from_tty)
500 char *args;
501 int from_tty;
502 {
503 printf_unfiltered ("\"set machine\" must be followed by h8300, h8300h");
504 printf_unfiltered ("or h8300s");
505 help_list (setmemorylist, "set memory ", -1, gdb_stdout);
506 }
507
508 /* set_machine_hook is called as the exec file is being opened, but
509 before the symbol file is opened. This allows us to set the
510 h8300hmode flag based on the machine type specified in the exec
511 file. This in turn will cause subsequently defined pointer types
512 to be 16 or 32 bits as appropriate for the machine. */
513
514 static void
515 set_machine_hook (filename)
516 char *filename;
517 {
518 if (bfd_get_mach (exec_bfd) == bfd_mach_h8300s)
519 {
520 h8300smode = 1;
521 h8300hmode = 1;
522 }
523 else
524 if (bfd_get_mach (exec_bfd) == bfd_mach_h8300h)
525 {
526 h8300smode = 0;
527 h8300hmode = 1;
528 }
529 else
530 {
531 h8300smode = 0;
532 h8300hmode = 0;
533 }
534 }
535
536 void
537 _initialize_h8300m ()
538 {
539 add_prefix_cmd ("machine", no_class, set_machine,
540 "set the machine type", &setmemorylist, "set machine ", 0,
541 &setlist);
542
543 add_cmd ("h8300", class_support, h8300_command,
544 "Set machine to be H8/300.", &setmemorylist);
545
546 add_cmd ("h8300h", class_support, h8300h_command,
547 "Set machine to be H8/300H.", &setmemorylist);
548
549 add_cmd ("h8300s", class_support, h8300s_command,
550 "Set machine to be H8/300S.", &setmemorylist);
551
552 /* Add a hook to set the machine type when we're loading a file. */
553
554 specify_exec_file_hook(set_machine_hook);
555 }
556
557
558
559 void
560 print_register_hook (regno)
561 {
562 if (regno == 8)
563 {
564 /* CCR register */
565 int C, Z, N, V;
566 unsigned char b[4];
567 unsigned char l;
568 read_relative_register_raw_bytes (regno, b);
569 l = b[REGISTER_VIRTUAL_SIZE(8) -1];
570 printf_unfiltered ("\t");
571 printf_unfiltered ("I-%d - ", (l & 0x80) != 0);
572 printf_unfiltered ("H-%d - ", (l & 0x20) != 0);
573 N = (l & 0x8) != 0;
574 Z = (l & 0x4) != 0;
575 V = (l & 0x2) != 0;
576 C = (l & 0x1) != 0;
577 printf_unfiltered ("N-%d ", N);
578 printf_unfiltered ("Z-%d ", Z);
579 printf_unfiltered ("V-%d ", V);
580 printf_unfiltered ("C-%d ", C);
581 if ((C | Z) == 0)
582 printf_unfiltered ("u> ");
583 if ((C | Z) == 1)
584 printf_unfiltered ("u<= ");
585 if ((C == 0))
586 printf_unfiltered ("u>= ");
587 if (C == 1)
588 printf_unfiltered ("u< ");
589 if (Z == 0)
590 printf_unfiltered ("!= ");
591 if (Z == 1)
592 printf_unfiltered ("== ");
593 if ((N ^ V) == 0)
594 printf_unfiltered (">= ");
595 if ((N ^ V) == 1)
596 printf_unfiltered ("< ");
597 if ((Z | (N ^ V)) == 0)
598 printf_unfiltered ("> ");
599 if ((Z | (N ^ V)) == 1)
600 printf_unfiltered ("<= ");
601 }
602 }
603
604 void
605 _initialize_h8300_tdep ()
606 {
607 tm_print_insn = gdb_print_insn_h8300;
608 }
This page took 0.049956 seconds and 4 git commands to generate.