#include "defs.h"
#include "frame.h"
#include "obstack.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
#include "value.h"
#include "dis-asm.h"
#include "gdbcore.h"
#include "regcache.h"
#define UNSIGNED_SHORT(X) ((X) & 0xffff)
static int code_size = 2;
static int data_size = 2;
#define IS_PUSH(x) (((x) & 0xff00)==0x6d00)
#define IS_LINK_8(x) ((x) == 0x17)
#define IS_LINK_16(x) ((x) == 0x1f)
#define IS_MOVE_FP(x) ((x) == 0x0d76)
#define IS_MOV_SP_FP(x) ((x) == 0x0d76)
#define IS_SUB2_SP(x) ((x) == 0x1b87)
#define IS_MOVK_R5(x) ((x) == 0x7905)
#define IS_SUB_R5SP(x) ((x) == 0x1957)
#define LINK_8 0x17
#define LINK_16 0x1f
int minimum_mode = 1;
CORE_ADDR
h8500_skip_prologue (CORE_ADDR start_pc)
{
short int w;
w = read_memory_integer (start_pc, 1);
if (w == LINK_8)
{
start_pc += 2;
w = read_memory_integer (start_pc, 1);
}
if (w == LINK_16)
{
start_pc += 3;
w = read_memory_integer (start_pc, 2);
}
return start_pc;
}
CORE_ADDR
h8500_addr_bits_remove (CORE_ADDR addr)
{
return ((addr) & 0xffffff);
}
CORE_ADDR
h8500_frame_chain (struct frame_info *thisframe)
{
if (!inside_entry_file (thisframe->pc))
return (read_memory_integer (FRAME_FP (thisframe), PTR_SIZE));
else
return 0;
}
CORE_ADDR
NEXT_PROLOGUE_INSN (CORE_ADDR addr, CORE_ADDR lim, char *pword1)
{
if (addr < lim + 8)
{
read_memory (addr, pword1, 1);
read_memory (addr, pword1 + 1, 1);
return 1;
}
return 0;
}
CORE_ADDR
frame_saved_pc (struct frame_info *frame)
{
return read_memory_integer (FRAME_FP (frame) + 2, PTR_SIZE);
}
void
h8500_pop_frame (void)
{
unsigned regnum;
struct frame_saved_regs fsr;
struct frame_info *frame = get_current_frame ();
get_frame_saved_regs (frame, &fsr);
for (regnum = 0; regnum < 8; regnum++)
{
if (fsr.regs[regnum])
write_register (regnum, read_memory_short (fsr.regs[regnum]));
flush_cached_frames ();
}
}
void
print_register_hook (int regno)
{
if (regno == CCR_REGNUM)
{
int C, Z, N, V;
unsigned char b[2];
unsigned char l;
read_relative_register_raw_bytes (regno, b);
l = b[1];
printf_unfiltered ("\t");
printf_unfiltered ("I-%d - ", (l & 0x80) != 0);
N = (l & 0x8) != 0;
Z = (l & 0x4) != 0;
V = (l & 0x2) != 0;
C = (l & 0x1) != 0;
printf_unfiltered ("N-%d ", N);
printf_unfiltered ("Z-%d ", Z);
printf_unfiltered ("V-%d ", V);
printf_unfiltered ("C-%d ", C);
if ((C | Z) == 0)
printf_unfiltered ("u> ");
if ((C | Z) == 1)
printf_unfiltered ("u<= ");
if ((C == 0))
printf_unfiltered ("u>= ");
if (C == 1)
printf_unfiltered ("u< ");
if (Z == 0)
printf_unfiltered ("!= ");
if (Z == 1)
printf_unfiltered ("== ");
if ((N ^ V) == 0)
printf_unfiltered (">= ");
if ((N ^ V) == 1)
printf_unfiltered ("< ");
if ((Z | (N ^ V)) == 0)
printf_unfiltered ("> ");
if ((Z | (N ^ V)) == 1)
printf_unfiltered ("<= ");
}
}
int
h8500_register_size (int regno)
{
switch (regno)
{
case SEG_C_REGNUM:
case SEG_D_REGNUM:
case SEG_E_REGNUM:
case SEG_T_REGNUM:
return 1;
case R0_REGNUM:
case R1_REGNUM:
case R2_REGNUM:
case R3_REGNUM:
case R4_REGNUM:
case R5_REGNUM:
case R6_REGNUM:
case R7_REGNUM:
case CCR_REGNUM:
return 2;
case PR0_REGNUM:
case PR1_REGNUM:
case PR2_REGNUM:
case PR3_REGNUM:
case PR4_REGNUM:
case PR5_REGNUM:
case PR6_REGNUM:
case PR7_REGNUM:
case PC_REGNUM:
return 4;
default:
internal_error (__FILE__, __LINE__, "failed internal consistency check");
}
}
struct type *
h8500_register_virtual_type (int regno)
{
switch (regno)
{
case SEG_C_REGNUM:
case SEG_E_REGNUM:
case SEG_D_REGNUM:
case SEG_T_REGNUM:
return builtin_type_unsigned_char;
case R0_REGNUM:
case R1_REGNUM:
case R2_REGNUM:
case R3_REGNUM:
case R4_REGNUM:
case R5_REGNUM:
case R6_REGNUM:
case R7_REGNUM:
case CCR_REGNUM:
return builtin_type_unsigned_short;
case PR0_REGNUM:
case PR1_REGNUM:
case PR2_REGNUM:
case PR3_REGNUM:
case PR4_REGNUM:
case PR5_REGNUM:
case PR6_REGNUM:
case PR7_REGNUM:
case PC_REGNUM:
return builtin_type_unsigned_long;
default:
internal_error (__FILE__, __LINE__, "failed internal consistency check");
}
}
void
frame_find_saved_regs (struct frame_info *frame_info,
struct frame_saved_regs *frame_saved_regs)
{
register int regnum;
register int regmask;
register CORE_ADDR next_addr;
register CORE_ADDR pc;
unsigned char thebyte;
memset (frame_saved_regs, '\0', sizeof *frame_saved_regs);
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4
&& (frame_info)->pc <= (frame_info)->frame)
{
next_addr = (frame_info)->frame;
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4;
}
else
{
pc = get_pc_function_start ((frame_info)->pc);
thebyte = read_memory_integer (pc, 1);
if (0x1f == thebyte)
next_addr = (frame_info)->frame + read_memory_integer (pc += 1, 2), pc += 2;
else if (0x17 == thebyte)
next_addr = (frame_info)->frame + read_memory_integer (pc += 1, 1), pc += 1;
else
goto lose;
#if 0
if ((0x0c0177777 & read_memory_integer (pc, 2)) == 0157774)
next_addr += read_memory_integer (pc += 2, 4), pc += 4;
#endif
}
thebyte = read_memory_integer (pc, 1);
if (thebyte == 0x12)
{
pc++;
regmask = read_memory_integer (pc, 1);
pc++;
for (regnum = 0; regnum < 8; regnum++, regmask >>= 1)
{
if (regmask & 1)
{
(frame_saved_regs)->regs[regnum] = (next_addr += 2) - 2;
}
}
thebyte = read_memory_integer (pc, 1);
}
while (thebyte == 0xbf)
{
pc++;
regnum = read_memory_integer (pc, 1) & 0x7;
pc++;
(frame_saved_regs)->regs[regnum] = (next_addr += 2) - 2;
thebyte = read_memory_integer (pc, 1);
}
lose:;
(frame_saved_regs)->regs[FP_REGNUM] = (frame_info)->frame;
(frame_saved_regs)->regs[SP_REGNUM] = (frame_info)->frame;
(frame_saved_regs)->regs[PC_REGNUM] = (frame_info)->frame + 2;
}
CORE_ADDR
saved_pc_after_call (void)
{
int x;
int a = read_register (SP_REGNUM);
x = read_memory_integer (a, code_size);
if (code_size == 2)
{
x &= 0xffff;
x |= read_register (SEG_C_REGNUM) << 16;
}
x &= 0xffffff;
return x;
}
void
h8500_set_pointer_size (int newsize)
{
static int oldsize = 0;
if (oldsize != newsize)
{
printf_unfiltered ("pointer size set to %d bits\n", newsize);
oldsize = newsize;
if (newsize == 32)
{
minimum_mode = 0;
}
else
{
minimum_mode = 1;
}
_initialize_gdbtypes ();
}
}
static void
big_command (char *arg, int from_tty)
{
h8500_set_pointer_size (32);
code_size = 4;
data_size = 4;
}
static void
medium_command (char *arg, int from_tty)
{
h8500_set_pointer_size (32);
code_size = 4;
data_size = 2;
}
static void
compact_command (char *arg, int from_tty)
{
h8500_set_pointer_size (32);
code_size = 2;
data_size = 4;
}
static void
small_command (char *arg, int from_tty)
{
h8500_set_pointer_size (16);
code_size = 2;
data_size = 2;
}
static struct cmd_list_element *setmemorylist;
static void
set_memory (char *args, int from_tty)
{
printf_unfiltered ("\"set memory\" must be followed by the name of a memory subcommand.\n");
help_list (setmemorylist, "set memory ", -1, gdb_stdout);
}
int
h8500_is_trapped_internalvar (char *name)
{
if (name[0] != 'p')
return 0;
if (strcmp (name + 1, "pc") == 0)
return 1;
if (name[1] == 'r'
&& name[2] >= '0'
&& name[2] <= '7'
&& name[3] == '\000')
return 1;
else
return 0;
}
struct value *
h8500_value_of_trapped_internalvar (struct internalvar *var)
{
LONGEST regval;
unsigned char regbuf[4];
int page_regnum, regnum;
regnum = var->name[2] == 'c' ? PC_REGNUM : var->name[2] - '0';
switch (var->name[2])
{
case 'c':
page_regnum = SEG_C_REGNUM;
break;
case '0':
case '1':
case '2':
case '3':
page_regnum = SEG_D_REGNUM;
break;
case '4':
case '5':
page_regnum = SEG_E_REGNUM;
break;
case '6':
case '7':
page_regnum = SEG_T_REGNUM;
break;
}
get_saved_register (regbuf, NULL, NULL, selected_frame, page_regnum, NULL);
regval = regbuf[0] << 16;
get_saved_register (regbuf, NULL, NULL, selected_frame, regnum, NULL);
regval |= regbuf[0] << 8 | regbuf[1];
xfree (var->value);
var->value = value_from_longest (builtin_type_unsigned_long, regval);
release_value (var->value);
VALUE_LVAL (var->value) = lval_internalvar;
VALUE_INTERNALVAR (var->value) = var;
return var->value;
}
void
h8500_set_trapped_internalvar (struct internalvar *var, struct value *newval,
int bitpos, int bitsize, int offset)
{
char *page_regnum, *regnum;
char expression[100];
unsigned new_regval;
struct type *type;
enum type_code newval_type_code;
type = check_typedef (VALUE_TYPE (newval));
newval_type_code = TYPE_CODE (type);
if ((newval_type_code != TYPE_CODE_INT
&& newval_type_code != TYPE_CODE_PTR)
|| TYPE_LENGTH (type) != sizeof (new_regval))
error ("Illegal type (%s) for assignment to $%s\n",
TYPE_NAME (VALUE_TYPE (newval)), var->name);
new_regval = *(long *) VALUE_CONTENTS_RAW (newval);
regnum = var->name + 1;
switch (var->name[2])
{
case 'c':
page_regnum = "cp";
break;
case '0':
case '1':
case '2':
case '3':
page_regnum = "dp";
break;
case '4':
case '5':
page_regnum = "ep";
break;
case '6':
case '7':
page_regnum = "tp";
break;
}
sprintf (expression, "$%s=%d", page_regnum, new_regval >> 16);
parse_and_eval (expression);
sprintf (expression, "$%s=%d", regnum, new_regval & 0xffff);
parse_and_eval (expression);
}
CORE_ADDR
h8500_read_sp (void)
{
return read_register (PR7_REGNUM);
}
void
h8500_write_sp (CORE_ADDR v)
{
write_register (PR7_REGNUM, v);
}
CORE_ADDR
h8500_read_pc (ptid_t ptid)
{
return read_register (PC_REGNUM);
}
void
h8500_write_pc (CORE_ADDR v, ptid_t ptid)
{
write_register (PC_REGNUM, v);
}
CORE_ADDR
h8500_read_fp (void)
{
return read_register (PR6_REGNUM);
}
void
_initialize_h8500_tdep (void)
{
tm_print_insn = print_insn_h8500;
add_prefix_cmd ("memory", no_class, set_memory,
"set the memory model", &setmemorylist, "set memory ", 0,
&setlist);
add_cmd ("small", class_support, small_command,
"Set small memory model. (16 bit code, 16 bit data)", &setmemorylist);
add_cmd ("big", class_support, big_command,
"Set big memory model. (32 bit code, 32 bit data)", &setmemorylist);
add_cmd ("medium", class_support, medium_command,
"Set medium memory model. (32 bit code, 16 bit data)", &setmemorylist);
add_cmd ("compact", class_support, compact_command,
"Set compact memory model. (16 bit code, 32 bit data)", &setmemorylist);
}