provide a new interface (using read_memory_func) to call the disassemblers
which copes with errors in a plausible way
This commit is contained in:
parent
79337c85b8
commit
5d0734a7d7
|
@ -1,3 +1,7 @@
|
||||||
|
Wed Mar 31 10:25:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
|
||||||
|
|
||||||
|
* objdump.c (disassemble_data): Use new read_memory_func stuff.
|
||||||
|
|
||||||
Thu Mar 25 10:38:11 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
|
Thu Mar 25 10:38:11 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
|
||||||
|
|
||||||
* objdump.c (fprintf): Declaration of variadic function had better
|
* objdump.c (fprintf): Declaration of variadic function had better
|
||||||
|
|
|
@ -440,8 +440,12 @@ disassemble_data (abfd)
|
||||||
|
|
||||||
bfd_get_section_contents (abfd, section, data, 0, bfd_get_section_size_before_reloc (section));
|
bfd_get_section_contents (abfd, section, data, 0, bfd_get_section_size_before_reloc (section));
|
||||||
|
|
||||||
|
disasm_info.buffer = data;
|
||||||
|
disasm_info.buffer_vma = section->vma;
|
||||||
|
disasm_info.buffer_length =
|
||||||
|
bfd_get_section_size_before_reloc (section);
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < bfd_get_section_size_before_reloc (section))
|
while (i < disasm_info.buffer_length)
|
||||||
{
|
{
|
||||||
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 &&
|
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 &&
|
||||||
data[i + 3] == 0)
|
data[i + 3] == 0)
|
||||||
|
@ -489,9 +493,13 @@ disassemble_data (abfd)
|
||||||
printf (" ");
|
printf (" ");
|
||||||
|
|
||||||
if (disassemble) /* New style */
|
if (disassemble) /* New style */
|
||||||
i += (*disassemble)(section->vma + i,
|
{
|
||||||
data + i,
|
int bytes = (*disassemble)(section->vma + i,
|
||||||
&disasm_info);
|
&disasm_info);
|
||||||
|
if (bytes < 0)
|
||||||
|
break;
|
||||||
|
i += bytes;
|
||||||
|
}
|
||||||
else /* Old style */
|
else /* Old style */
|
||||||
i += print (section->vma + i,
|
i += print (section->vma + i,
|
||||||
data + i,
|
data + i,
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
Wed Mar 31 12:52:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
|
||||||
|
|
||||||
|
* core.c (dis_asm_{read_memory,memory_error}): New functions.
|
||||||
|
m68k-pinsn.c, h8500-tdep.c, i386-pinsn.c, mips-pinsn.c, z8k-tdep.c:
|
||||||
|
Use read_memory_func interface to disassembler.
|
||||||
|
|
||||||
Tue Mar 30 15:46:14 1993 K. Richard Pixley (rich@rtl.cygnus.com)
|
Tue Mar 30 15:46:14 1993 K. Richard Pixley (rich@rtl.cygnus.com)
|
||||||
|
|
||||||
Teach sparc solaris to next over shared library functions.
|
Teach sparc solaris to next over shared library functions.
|
||||||
|
|
22
gdb/core.c
22
gdb/core.c
|
@ -28,6 +28,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "bfd.h"
|
#include "bfd.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "gdbcore.h"
|
#include "gdbcore.h"
|
||||||
|
#include "dis-asm.h"
|
||||||
|
|
||||||
extern char registers[];
|
extern char registers[];
|
||||||
|
|
||||||
|
@ -160,6 +161,27 @@ read_memory (memaddr, myaddr, len)
|
||||||
memory_error (status, memaddr);
|
memory_error (status, memaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Like target_read_memory, but slightly different parameters. */
|
||||||
|
int
|
||||||
|
dis_asm_read_memory (memaddr, myaddr, len, info)
|
||||||
|
bfd_vma memaddr;
|
||||||
|
bfd_byte *myaddr;
|
||||||
|
int len;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
return target_read_memory (memaddr, myaddr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like memory_error with slightly different parameters. */
|
||||||
|
void
|
||||||
|
dis_asm_memory_error (status, memaddr, info)
|
||||||
|
int status;
|
||||||
|
bfd_vma memaddr;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
memory_error (status, memaddr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Same as target_write_memory, but report an error if can't write. */
|
/* Same as target_write_memory, but report an error if can't write. */
|
||||||
void
|
void
|
||||||
write_memory (memaddr, myaddr, len)
|
write_memory (memaddr, myaddr, len)
|
||||||
|
|
|
@ -110,12 +110,9 @@ print_insn (memaddr, stream)
|
||||||
CORE_ADDR memaddr;
|
CORE_ADDR memaddr;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
{
|
{
|
||||||
/* Nothing is bigger than 8 bytes */
|
|
||||||
char data[8];
|
|
||||||
disassemble_info info;
|
disassemble_info info;
|
||||||
read_memory (memaddr, data, sizeof (data));
|
|
||||||
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
||||||
return print_insn_h8500 (memaddr, data, &info);
|
return print_insn_h8500 (memaddr, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given a GDB frame, determine the address of the calling function's frame.
|
/* Given a GDB frame, determine the address of the calling function's frame.
|
||||||
|
|
|
@ -20,9 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "dis-asm.h"
|
#include "dis-asm.h"
|
||||||
|
|
||||||
#define MAXLEN 20
|
|
||||||
|
|
||||||
/* Print the m68k instruction at address MEMADDR in debugged memory,
|
/* Print the instruction at address MEMADDR in debugged memory,
|
||||||
on STREAM. Returns length of the instruction, in bytes. */
|
on STREAM. Returns length of the instruction, in bytes. */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -30,16 +29,9 @@ print_insn (memaddr, stream)
|
||||||
CORE_ADDR memaddr;
|
CORE_ADDR memaddr;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
{
|
{
|
||||||
unsigned char buffer[MAXLEN];
|
|
||||||
register int i;
|
|
||||||
register unsigned char *p;
|
|
||||||
register char *d;
|
|
||||||
register int bestmask;
|
|
||||||
int best;
|
|
||||||
disassemble_info info;
|
disassemble_info info;
|
||||||
|
|
||||||
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
||||||
|
|
||||||
read_memory (memaddr, (char *) buffer, MAXLEN);
|
return print_insn_i386 (memaddr, &info);
|
||||||
return print_insn_i386 (memaddr, buffer, &info);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "dis-asm.h"
|
#include "dis-asm.h"
|
||||||
|
|
||||||
/* m68k instructions are never longer than this many bytes. */
|
|
||||||
#define MAXLEN 22
|
|
||||||
|
|
||||||
/* Print the m68k instruction at address MEMADDR in debugged memory,
|
/* Print the m68k instruction at address MEMADDR in debugged memory,
|
||||||
on STREAM. Returns length of the instruction, in bytes. */
|
on STREAM. Returns length of the instruction, in bytes. */
|
||||||
|
|
||||||
|
@ -31,16 +28,9 @@ print_insn (memaddr, stream)
|
||||||
CORE_ADDR memaddr;
|
CORE_ADDR memaddr;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
{
|
{
|
||||||
unsigned char buffer[MAXLEN];
|
|
||||||
register int i;
|
|
||||||
register unsigned char *p;
|
|
||||||
register char *d;
|
|
||||||
register int bestmask;
|
|
||||||
int best;
|
|
||||||
disassemble_info info;
|
disassemble_info info;
|
||||||
|
|
||||||
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
||||||
|
|
||||||
read_memory (memaddr, (char *) buffer, MAXLEN);
|
return print_insn_m68k (memaddr, &info);
|
||||||
return print_insn_m68k (memaddr, buffer, &info);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "dis-asm.h"
|
#include "dis-asm.h"
|
||||||
|
|
||||||
/* Mips instructions are never longer than this many bytes. */
|
|
||||||
#define MAXLEN 4
|
|
||||||
|
|
||||||
/* Print the mips instruction at address MEMADDR in debugged memory,
|
/* Print the mips instruction at address MEMADDR in debugged memory,
|
||||||
on STREAM. Returns length of the instruction, in bytes, which
|
on STREAM. Returns length of the instruction, in bytes, which
|
||||||
is always 4. */
|
is always 4. */
|
||||||
|
@ -32,16 +29,13 @@ print_insn (memaddr, stream)
|
||||||
CORE_ADDR memaddr;
|
CORE_ADDR memaddr;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
{
|
{
|
||||||
unsigned char buffer[MAXLEN];
|
|
||||||
disassemble_info info;
|
disassemble_info info;
|
||||||
|
|
||||||
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
||||||
|
|
||||||
read_memory (memaddr, buffer, MAXLEN);
|
|
||||||
|
|
||||||
/* print_insn_mips is in opcodes/mips-dis.c. */
|
/* print_insn_mips is in opcodes/mips-dis.c. */
|
||||||
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
|
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
|
||||||
print_insn_big_mips (memaddr, buffer, &info);
|
print_insn_big_mips (memaddr, &info);
|
||||||
else
|
else
|
||||||
print_insn_little_mips (memaddr, buffer, &info);
|
print_insn_little_mips (memaddr, &info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,19 +208,17 @@ print_insn (memaddr, stream)
|
||||||
CORE_ADDR memaddr;
|
CORE_ADDR memaddr;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
{
|
{
|
||||||
char temp[20];
|
|
||||||
disassemble_info info;
|
disassemble_info info;
|
||||||
|
|
||||||
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
GDB_INIT_DISASSEMBLE_INFO(info, stream);
|
||||||
|
|
||||||
read_memory (memaddr, temp, 20);
|
|
||||||
if (BIG)
|
if (BIG)
|
||||||
{
|
{
|
||||||
return print_insn_z8001 (memaddr, temp, &info);
|
return print_insn_z8001 (memaddr, &info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return print_insn_z8002 (memaddr, temp, &info);
|
return print_insn_z8002 (memaddr, &info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
Tue Mar 30 19:09:23 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
|
||||||
|
|
||||||
|
* dis-asm.h (disassembler_info): Add read_memory_func,
|
||||||
|
memory_error_func, buffer, buffer_length, and buffer_vma.
|
||||||
|
({GDB_,}INIT_DISASSEMBLE_INFO): Set them.
|
||||||
|
print_insn_*: Remove second argument.
|
||||||
|
|
||||||
|
Tue Mar 30 14:48:55 1993 Steve Chamberlain (sac@thepub.cygnus.com)
|
||||||
|
|
||||||
|
* bfd.h: Update for lma field of section.
|
||||||
|
|
||||||
Tue Mar 30 12:22:55 1993 Jim Kingdon (kingdon@cygnus.com)
|
Tue Mar 30 12:22:55 1993 Jim Kingdon (kingdon@cygnus.com)
|
||||||
|
|
||||||
* ansidecl.h: Use ANSI versions on AIX regardless of __STDC__.
|
* ansidecl.h: Use ANSI versions on AIX regardless of __STDC__.
|
||||||
|
|
|
@ -7,26 +7,76 @@ typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
|
||||||
typedef struct disassemble_info {
|
typedef struct disassemble_info {
|
||||||
fprintf_ftype fprintf_func;
|
fprintf_ftype fprintf_func;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
|
|
||||||
|
/* For use by the disassembler. */
|
||||||
int flags;
|
int flags;
|
||||||
|
PTR private_data;
|
||||||
|
|
||||||
|
/* Function used to get bytes to disassemble. MEMADDR is the
|
||||||
|
address of the stuff to be disassembled, MYADDR is the address to
|
||||||
|
put the bytes in, and LENGTH is the number of bytes to read.
|
||||||
|
INFO is a pointer to this struct.
|
||||||
|
Returns an errno value or 0 for success. */
|
||||||
|
int (*read_memory_func)
|
||||||
|
PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||||
|
struct disassemble_info *info));
|
||||||
|
|
||||||
|
/* Function which should be called if we get an error that we can't
|
||||||
|
recover from. STATUS is the errno value from read_memory_func and
|
||||||
|
MEMADDR is the address that we were trying to read. INFO is a
|
||||||
|
pointer to this struct. */
|
||||||
|
void (*memory_error_func)
|
||||||
|
PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
|
||||||
|
|
||||||
|
/* These are for buffer_read_memory. */
|
||||||
|
bfd_byte *buffer;
|
||||||
|
bfd_vma buffer_vma;
|
||||||
|
int buffer_length;
|
||||||
} disassemble_info;
|
} disassemble_info;
|
||||||
|
|
||||||
typedef int (*disassembler_ftype)
|
/* Here is a function which callers may wish to use for read_memory_func.
|
||||||
PARAMS((bfd_vma, bfd_byte *, disassemble_info *));
|
It gets bytes from a buffer. */
|
||||||
|
extern int buffer_read_memory
|
||||||
|
PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
|
||||||
|
|
||||||
|
/* This function goes with buffer_read_memory.
|
||||||
|
It prints a message using info->fprintf_func and info->stream. */
|
||||||
|
extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
|
||||||
|
|
||||||
#define INIT_DISASSEMBLE_INFO(INFO, STREAM) \
|
#define INIT_DISASSEMBLE_INFO(INFO, STREAM) \
|
||||||
INFO.fprintf_func = (fprintf_ftype)fprintf, \
|
(INFO).fprintf_func = (fprintf_ftype)fprintf, \
|
||||||
INFO.stream = (STREAM)
|
(INFO).stream = (STREAM), \
|
||||||
|
(INFO).buffer = NULL, \
|
||||||
|
(INFO).buffer_vma = 0, \
|
||||||
|
(INFO).buffer_length = 0, \
|
||||||
|
(INFO).read_memory_func = buffer_read_memory, \
|
||||||
|
(INFO).memory_error_func = perror_memory
|
||||||
|
|
||||||
|
/* GDB--Like target_read_memory, but slightly different parameters. */
|
||||||
|
extern int
|
||||||
|
dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int len));
|
||||||
|
|
||||||
|
/* GDB--Like memory_error with slightly different parameters. */
|
||||||
|
extern void
|
||||||
|
dis_asm_memory_error
|
||||||
|
PARAMS ((int status, bfd_vma memaddr, disassembler_info *info));
|
||||||
|
|
||||||
#define GDB_INIT_DISASSEMBLE_INFO(INFO, STREAM) \
|
#define GDB_INIT_DISASSEMBLE_INFO(INFO, STREAM) \
|
||||||
INFO.fprintf_func = (fprintf_ftype)fprintf_filtered, \
|
(INFO).fprintf_func = (fprintf_ftype)fprintf_filtered, \
|
||||||
INFO.stream = (STREAM)
|
(INFO).stream = (STREAM), \
|
||||||
|
(INFO).read_memory_func = dis_asm_read_memory, \
|
||||||
|
(INFO).memory_error_func = dis_asm_memory_error
|
||||||
|
|
||||||
/* Standard dis-assemblers. */
|
|
||||||
|
|
||||||
extern int print_insn_big_mips PARAMS ((bfd_vma, bfd_byte*,disassemble_info*));
|
/* Standard disassemblers. Disassemble one instruction at the given
|
||||||
extern int print_insn_little_mips
|
target address. Return number of bytes processed. */
|
||||||
PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
|
typedef int (*disassembler_ftype)
|
||||||
extern int print_insn_i386 PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
|
PARAMS((bfd_vma, disassemble_info *));
|
||||||
extern int print_insn_m68k PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
|
|
||||||
extern int print_insn_z8001 PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
|
extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
|
||||||
extern int print_insn_z8002 PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
|
extern int print_insn_little_mips PARAMS ((bfd_vma,disassemble_info*));
|
||||||
|
extern int print_insn_i386 PARAMS ((bfd_vma,disassemble_info*));
|
||||||
|
extern int print_insn_m68k PARAMS ((bfd_vma,disassemble_info*));
|
||||||
|
extern int print_insn_z8001 PARAMS ((bfd_vma,disassemble_info*));
|
||||||
|
extern int print_insn_z8002 PARAMS ((bfd_vma,disassemble_info*));
|
||||||
|
extern int print_insn_h8500 PARAMS ((bfd_vma,disassemble_info*));
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
Wed Mar 31 10:07:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
|
||||||
|
|
||||||
|
* dis-buf.c: New file, for new read_memory_func interface.
|
||||||
|
Makefile.in (OFILES): Include it.
|
||||||
|
m68k-dis.c, i386-dis.c, h8500-dis.c, mips-dis.c, z8k-dis.c:
|
||||||
|
Use new read_memory_func interface.
|
||||||
|
|
||||||
|
Mon Mar 29 14:02:17 1993 Steve Chamberlain (sac@thepub.cygnus.com)
|
||||||
|
|
||||||
|
* h8500-dis.c (print_insn_h8500): Get sign of fp offsets right.
|
||||||
|
* h8500-opc.h: Fix couple of opcodes.
|
||||||
|
|
||||||
|
Wed Mar 24 02:03:36 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com)
|
||||||
|
|
||||||
|
* Makefile.in: add dvi & installcheck targets
|
||||||
|
|
||||||
Mon Mar 22 18:55:04 1993 John Gilmore (gnu@cygnus.com)
|
Mon Mar 22 18:55:04 1993 John Gilmore (gnu@cygnus.com)
|
||||||
|
|
||||||
* Makefile.in: Update for h8500-dis.c.
|
* Makefile.in: Update for h8500-dis.c.
|
||||||
|
|
|
@ -62,7 +62,7 @@ DEP = mkdep
|
||||||
TARGETLIB = libopcodes.a
|
TARGETLIB = libopcodes.a
|
||||||
|
|
||||||
|
|
||||||
DIS_LIBS = i386-dis.o z8k-dis.o m68k-dis.o mips-dis.o h8500-dis.o
|
DIS_LIBS = i386-dis.o z8k-dis.o m68k-dis.o mips-dis.o h8500-dis.o dis-buf.o
|
||||||
|
|
||||||
OFILES = $(DIS_LIBS) sparc-opc.o m68881-ext.o
|
OFILES = $(DIS_LIBS) sparc-opc.o m68881-ext.o
|
||||||
#### host and target dependent Makefile fragments come in here.
|
#### host and target dependent Makefile fragments come in here.
|
||||||
|
@ -95,11 +95,12 @@ all: $(TARGETLIB)
|
||||||
|
|
||||||
.NOEXPORT:
|
.NOEXPORT:
|
||||||
|
|
||||||
check:
|
installcheck check:
|
||||||
|
|
||||||
info:
|
info:
|
||||||
clean-info:
|
clean-info:
|
||||||
install-info:
|
install-info:
|
||||||
|
dvi:
|
||||||
|
|
||||||
# HDEPFILES comes from the host config; TDEPFILES from the target config.
|
# HDEPFILES comes from the host config; TDEPFILES from the target config.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,330 @@
|
||||||
|
/* Disassemble h8500 instructions.
|
||||||
|
Copyright (C) 1993 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DISASSEMBLER_TABLE
|
||||||
|
#define DEFINE_TABLE
|
||||||
|
|
||||||
|
#include "h8500-opc.h"
|
||||||
|
#include "dis-asm.h"
|
||||||
|
|
||||||
|
/* Maximum length of an instruction. */
|
||||||
|
#define MAXLEN 8
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
struct private
|
||||||
|
{
|
||||||
|
/* Points to first byte not fetched. */
|
||||||
|
bfd_byte *max_fetched;
|
||||||
|
bfd_byte the_buffer[MAXLEN];
|
||||||
|
bfd_vma insn_start;
|
||||||
|
jmp_buf bailout;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
|
||||||
|
to ADDR (exclusive) are valid. Returns 1 for success, longjmps
|
||||||
|
on error. */
|
||||||
|
#define FETCH_DATA(info, addr) \
|
||||||
|
((addr) <= ((struct private *)(info->private_data))->max_fetched \
|
||||||
|
? 1 : fetch_data ((info), (addr)))
|
||||||
|
|
||||||
|
static int
|
||||||
|
fetch_data (info, addr)
|
||||||
|
struct disassemble_info *info;
|
||||||
|
bfd_byte *addr;
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
struct private *priv = (struct private *)info->private_data;
|
||||||
|
bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
|
||||||
|
|
||||||
|
status = (*info->read_memory_func) (start,
|
||||||
|
priv->max_fetched,
|
||||||
|
addr - priv->max_fetched,
|
||||||
|
info);
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
(*info->memory_error_func) (status, start, info);
|
||||||
|
longjmp (priv->bailout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
priv->max_fetched = addr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *crname[] =
|
||||||
|
{"sr", "ccr", "*", "br", "ep", "dp", "*", "tp"};
|
||||||
|
|
||||||
|
int
|
||||||
|
print_insn_h8500 (addr, info)
|
||||||
|
unsigned long addr;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
h8500_opcode_info *opcode;
|
||||||
|
void *stream = info->stream;
|
||||||
|
fprintf_ftype func = info->fprintf_func;
|
||||||
|
|
||||||
|
struct private priv;
|
||||||
|
bfd_byte *buffer = priv.the_buffer;
|
||||||
|
|
||||||
|
info->private_data = (PTR) &priv;
|
||||||
|
priv.max_fetched = priv.the_buffer;
|
||||||
|
priv.insn_start = addr;
|
||||||
|
if (setjmp (priv.bailout) != 0)
|
||||||
|
/* Error return. */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Run down the table to find the one which matches */
|
||||||
|
for (opcode = h8500_table; opcode->name; opcode++)
|
||||||
|
{
|
||||||
|
int byte;
|
||||||
|
int rn;
|
||||||
|
int rd;
|
||||||
|
int rs;
|
||||||
|
int disp;
|
||||||
|
int abs;
|
||||||
|
int imm;
|
||||||
|
int pcrel;
|
||||||
|
int qim;
|
||||||
|
int i;
|
||||||
|
int cr;
|
||||||
|
for (byte = 0; byte < opcode->length; byte++)
|
||||||
|
{
|
||||||
|
FETCH_DATA (info, buffer + byte + 1);
|
||||||
|
if ((buffer[byte] & opcode->bytes[byte].mask)
|
||||||
|
!= (opcode->bytes[byte].contents))
|
||||||
|
{
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* extract any info parts */
|
||||||
|
switch (opcode->bytes[byte].insert)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case FP:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
func (stream, "can't cope with insert %d\n",
|
||||||
|
opcode->bytes[byte].insert);
|
||||||
|
break;
|
||||||
|
case RN:
|
||||||
|
rn = buffer[byte] & 0x7;
|
||||||
|
break;
|
||||||
|
case RS:
|
||||||
|
rs = buffer[byte] & 0x7;
|
||||||
|
break;
|
||||||
|
case CRB:
|
||||||
|
cr = buffer[byte] & 0x7;
|
||||||
|
if (cr == 0)
|
||||||
|
goto next;
|
||||||
|
break;
|
||||||
|
case CRW:
|
||||||
|
cr = buffer[byte] & 0x7;
|
||||||
|
if (cr != 0)
|
||||||
|
goto next;
|
||||||
|
break;
|
||||||
|
case DISP16:
|
||||||
|
FETCH_DATA (info, buffer + byte + 2);
|
||||||
|
disp = (buffer[byte] << 8) | (buffer[byte + 1]);
|
||||||
|
break;
|
||||||
|
case FPIND_D8:
|
||||||
|
case DISP8:
|
||||||
|
disp = ((char) (buffer[byte]));
|
||||||
|
break;
|
||||||
|
case RD:
|
||||||
|
case RDIND:
|
||||||
|
rd = buffer[byte] & 0x7;
|
||||||
|
break;
|
||||||
|
case ABS24:
|
||||||
|
FETCH_DATA (info, buffer + byte + 3);
|
||||||
|
abs =
|
||||||
|
(buffer[byte] << 16)
|
||||||
|
| (buffer[byte + 1] << 8)
|
||||||
|
| (buffer[byte + 2]);
|
||||||
|
break;
|
||||||
|
case ABS16:
|
||||||
|
FETCH_DATA (info, buffer + byte + 2);
|
||||||
|
abs = (buffer[byte] << 8) | (buffer[byte + 1]);
|
||||||
|
break;
|
||||||
|
case ABS8:
|
||||||
|
abs = (buffer[byte]);
|
||||||
|
break;
|
||||||
|
case IMM16:
|
||||||
|
FETCH_DATA (info, buffer + byte + 2);
|
||||||
|
imm = (buffer[byte] << 8) | (buffer[byte + 1]);
|
||||||
|
break;
|
||||||
|
case IMM4:
|
||||||
|
imm = (buffer[byte]) & 0xf;
|
||||||
|
break;
|
||||||
|
case IMM8:
|
||||||
|
case RLIST:
|
||||||
|
imm = (buffer[byte]);
|
||||||
|
break;
|
||||||
|
case PCREL16:
|
||||||
|
FETCH_DATA (info, buffer + byte + 2);
|
||||||
|
pcrel = (buffer[byte] << 8) | (buffer[byte + 1]);
|
||||||
|
break;
|
||||||
|
case PCREL8:
|
||||||
|
pcrel = (buffer[byte]);
|
||||||
|
break;
|
||||||
|
case QIM:
|
||||||
|
switch (buffer[byte] & 0x7)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
qim = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
qim = 2;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
qim = -1;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
qim = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* We get here when all the masks have passed so we can output the
|
||||||
|
operands*/
|
||||||
|
FETCH_DATA (info, buffer + opcode->length);
|
||||||
|
for (i = 0; i < opcode->length; i++)
|
||||||
|
{
|
||||||
|
(func) (stream, "%02x ", buffer[i]);
|
||||||
|
}
|
||||||
|
for (; i < 6; i++)
|
||||||
|
{
|
||||||
|
(func) (stream, " ");
|
||||||
|
}
|
||||||
|
(func) (stream, "%s\t", opcode->name);
|
||||||
|
for (i = 0; i < opcode->nargs; i++)
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
|
(func) (stream, ",");
|
||||||
|
switch (opcode->arg_type[i])
|
||||||
|
{
|
||||||
|
case FP:
|
||||||
|
func (stream, "fp");
|
||||||
|
break;
|
||||||
|
case RNIND_D16:
|
||||||
|
func (stream, "@(0x%x:16,r%d)", disp, rn);
|
||||||
|
break;
|
||||||
|
case RNIND_D8:
|
||||||
|
func (stream, "@(0x%x:8 (%d),r%d)", disp & 0xff, disp, rn);
|
||||||
|
break;
|
||||||
|
case RDIND_D16:
|
||||||
|
func (stream, "@(0x%x:16,r%d)", disp, rd);
|
||||||
|
break;
|
||||||
|
case RDIND_D8:
|
||||||
|
func (stream, "@(0x%x:8 (%d), r%d)", disp & 0xff, disp, rd);
|
||||||
|
break;
|
||||||
|
case FPIND_D8:
|
||||||
|
func (stream, "@(0x%x:8 (%d), fp)", disp & 0xff, disp, rn);
|
||||||
|
break;
|
||||||
|
case CRB:
|
||||||
|
case CRW:
|
||||||
|
func (stream, "%s", crname[cr]);
|
||||||
|
break;
|
||||||
|
case RN:
|
||||||
|
func (stream, "r%d", rn);
|
||||||
|
break;
|
||||||
|
case RD:
|
||||||
|
func (stream, "r%d", rd);
|
||||||
|
break;
|
||||||
|
case RS:
|
||||||
|
func (stream, "r%d", rs);
|
||||||
|
break;
|
||||||
|
case RNDEC:
|
||||||
|
func (stream, "@-r%d", rn);
|
||||||
|
break;
|
||||||
|
case RNINC:
|
||||||
|
func (stream, "@r%d+", rn);
|
||||||
|
break;
|
||||||
|
case RNIND:
|
||||||
|
func (stream, "@r%d", rn);
|
||||||
|
break;
|
||||||
|
case RDIND:
|
||||||
|
func (stream, "@r%d", rd);
|
||||||
|
break;
|
||||||
|
case SPINC:
|
||||||
|
func (stream, "@sp+");
|
||||||
|
break;
|
||||||
|
case SPDEC:
|
||||||
|
func (stream, "@-sp");
|
||||||
|
break;
|
||||||
|
case ABS24:
|
||||||
|
func (stream, "@0x%0x:24", abs);
|
||||||
|
break;
|
||||||
|
case ABS16:
|
||||||
|
func (stream, "@0x%0x:16", abs & 0xffff);
|
||||||
|
break;
|
||||||
|
case ABS8:
|
||||||
|
func (stream, "@0x%0x:8", abs & 0xff);
|
||||||
|
break;
|
||||||
|
case IMM16:
|
||||||
|
func (stream, "#0x%0x:16", imm & 0xffff);
|
||||||
|
break;
|
||||||
|
case RLIST:
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int nc = 0;
|
||||||
|
func (stream, "(");
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if (imm & (1 << i))
|
||||||
|
{
|
||||||
|
if (nc)
|
||||||
|
func (stream, ",");
|
||||||
|
nc += 1;
|
||||||
|
}
|
||||||
|
func (stream, "r%d", i);
|
||||||
|
}
|
||||||
|
func (stream, ")");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IMM8:
|
||||||
|
func (stream, "#0x%0x:8", imm & 0xff);
|
||||||
|
break;
|
||||||
|
case PCREL16:
|
||||||
|
func (stream, "0x%0x:16", (pcrel + addr + opcode->length) & 0xffff);
|
||||||
|
break;
|
||||||
|
case PCREL8:
|
||||||
|
func (stream, "#0x%0x:8",
|
||||||
|
((char) pcrel + addr + opcode->length) & 0xffff);
|
||||||
|
break;
|
||||||
|
case QIM:
|
||||||
|
func (stream, "#%d:q", qim);
|
||||||
|
break;
|
||||||
|
case IMM4:
|
||||||
|
func (stream, "#%d:4", imm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opcode->length;
|
||||||
|
next:;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couldn't understand anything */
|
||||||
|
func (stream, "%02x\t\t*unknown*", buffer[0]);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,970 @@
|
||||||
|
/* Print Motorola 68k instructions.
|
||||||
|
Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
|
#include "dis-asm.h"
|
||||||
|
#include "ieee-float.h"
|
||||||
|
|
||||||
|
extern CONST struct ext_format ext_format_68881;
|
||||||
|
|
||||||
|
/* Opcode/m68k.h is a massive table. As a kludge, break it up into
|
||||||
|
two pieces. This makes nonportable C -- FIXME -- it assumes that
|
||||||
|
two data items declared near each other will be contiguous in
|
||||||
|
memory. This kludge can be removed, FIXME, when GCC is fixed to not
|
||||||
|
be a hog about initializers. */
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define BREAK_UP_BIG_DECL }; \
|
||||||
|
struct m68k_opcode m68k_opcodes_2[] = {
|
||||||
|
#define AND_OTHER_PART sizeof (m68k_opcodes_2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "opcode/m68k.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Local function prototypes */
|
||||||
|
|
||||||
|
static int
|
||||||
|
fetch_arg PARAMS ((unsigned char *, int, int));
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_base PARAMS ((int, int, disassemble_info*));
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
print_indexed PARAMS ((int, unsigned char *, bfd_vma, disassemble_info *));
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
print_insn_arg PARAMS ((char *, unsigned char *, unsigned char *, bfd_vma,
|
||||||
|
disassemble_info *));
|
||||||
|
|
||||||
|
/* Sign-extend an (unsigned char). */
|
||||||
|
#if __STDC__ == 1
|
||||||
|
#define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))
|
||||||
|
#else
|
||||||
|
#define COERCE_SIGNED_CHAR(ch) ((int)(((ch) ^ 0x80) & 0xFF) - 128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CONST char * CONST fpcr_names[] = {
|
||||||
|
"", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
|
||||||
|
"fpiar/fpcr", "fpsr/fpcr", "fpiar/fpsr/fpcr"};
|
||||||
|
|
||||||
|
static char *reg_names[] = {
|
||||||
|
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0",
|
||||||
|
"a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"};
|
||||||
|
|
||||||
|
/* Define accessors for 68K's 1, 2, and 4-byte signed quantities.
|
||||||
|
The _SHIFT values move the quantity to the high order end of an
|
||||||
|
`int' value, so it will sign-extend. Probably a few more casts
|
||||||
|
are needed to make it compile without warnings on finicky systems. */
|
||||||
|
#define BITS_PER_BYTE 8
|
||||||
|
#define WORD_SHIFT (BITS_PER_BYTE * ((sizeof (int)) - 2))
|
||||||
|
#define LONG_SHIFT (BITS_PER_BYTE * ((sizeof (int)) - 4))
|
||||||
|
|
||||||
|
#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
|
||||||
|
|
||||||
|
#define NEXTWORD(p) \
|
||||||
|
(p += 2, FETCH_DATA (info, p), \
|
||||||
|
(((int)((p[-2] << 8) + p[-1])) << WORD_SHIFT) >> WORD_SHIFT)
|
||||||
|
|
||||||
|
#define NEXTLONG(p) \
|
||||||
|
(p += 4, FETCH_DATA (info, p), \
|
||||||
|
(((int)((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])) \
|
||||||
|
<< LONG_SHIFT) >> LONG_SHIFT)
|
||||||
|
|
||||||
|
/* NEXTSINGLE and NEXTDOUBLE handle alignment problems, but not
|
||||||
|
* byte-swapping or other float format differences. FIXME! */
|
||||||
|
|
||||||
|
union number {
|
||||||
|
double d;
|
||||||
|
float f;
|
||||||
|
char c[10];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NEXTSINGLE(val, p) \
|
||||||
|
{ int i; union number u;\
|
||||||
|
FETCH_DATA (info, p + sizeof (float));\
|
||||||
|
for (i = 0; i < sizeof(float); i++) u.c[i] = *p++; \
|
||||||
|
val = u.f; }
|
||||||
|
|
||||||
|
#define NEXTDOUBLE(val, p) \
|
||||||
|
{ int i; union number u;\
|
||||||
|
FETCH_DATA (info, p + sizeof (double));\
|
||||||
|
for (i = 0; i < sizeof(double); i++) u.c[i] = *p++; \
|
||||||
|
val = u.d; }
|
||||||
|
|
||||||
|
/* Need a function to convert from extended to double precision... */
|
||||||
|
#define NEXTEXTEND(p) \
|
||||||
|
(p += 12, FETCH_DATA (info, p), 0.0)
|
||||||
|
|
||||||
|
/* Need a function to convert from packed to double
|
||||||
|
precision. Actually, it's easier to print a
|
||||||
|
packed number than a double anyway, so maybe
|
||||||
|
there should be a special case to handle this... */
|
||||||
|
#define NEXTPACKED(p) \
|
||||||
|
(p += 12, FETCH_DATA (info, p), 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
/* Maximum length of an instruction. */
|
||||||
|
#define MAXLEN 22
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
struct private
|
||||||
|
{
|
||||||
|
/* Points to first byte not fetched. */
|
||||||
|
bfd_byte *max_fetched;
|
||||||
|
bfd_byte the_buffer[MAXLEN];
|
||||||
|
bfd_vma insn_start;
|
||||||
|
jmp_buf bailout;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
|
||||||
|
to ADDR (exclusive) are valid. Returns 1 for success, longjmps
|
||||||
|
on error. */
|
||||||
|
#define FETCH_DATA(info, addr) \
|
||||||
|
((addr) <= ((struct private *)(info->private_data))->max_fetched \
|
||||||
|
? 1 : fetch_data ((info), (addr)))
|
||||||
|
|
||||||
|
static int
|
||||||
|
fetch_data (info, addr)
|
||||||
|
struct disassemble_info *info;
|
||||||
|
bfd_byte *addr;
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
struct private *priv = (struct private *)info->private_data;
|
||||||
|
bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
|
||||||
|
|
||||||
|
status = (*info->read_memory_func) (start,
|
||||||
|
priv->max_fetched,
|
||||||
|
addr - priv->max_fetched,
|
||||||
|
info);
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
(*info->memory_error_func) (status, start, info);
|
||||||
|
longjmp (priv->bailout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
priv->max_fetched = addr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
m68k_opcode_error(info, code, place)
|
||||||
|
struct disassemble_info *info;
|
||||||
|
int code, place;
|
||||||
|
{
|
||||||
|
(*info->fprintf_func)(info->stream,
|
||||||
|
"<internal error in opcode table: \"%c%c\">",
|
||||||
|
code, place);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the m68k instruction at address MEMADDR in debugged memory,
|
||||||
|
on STREAM. Returns length of the instruction, in bytes. */
|
||||||
|
|
||||||
|
int
|
||||||
|
print_insn_m68k (memaddr, info)
|
||||||
|
bfd_vma memaddr;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
register unsigned char *p;
|
||||||
|
register char *d;
|
||||||
|
register unsigned long bestmask;
|
||||||
|
int best;
|
||||||
|
struct private priv;
|
||||||
|
bfd_byte *buffer = priv.the_buffer;
|
||||||
|
|
||||||
|
info->private_data = (PTR) &priv;
|
||||||
|
priv.max_fetched = priv.the_buffer;
|
||||||
|
priv.insn_start = memaddr;
|
||||||
|
if (setjmp (priv.bailout) != 0)
|
||||||
|
/* Error return. */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
bestmask = 0;
|
||||||
|
best = -1;
|
||||||
|
FETCH_DATA (info, buffer + 2);
|
||||||
|
for (i = 0; i < numopcodes; i++)
|
||||||
|
{
|
||||||
|
register unsigned long opcode = m68k_opcodes[i].opcode;
|
||||||
|
register unsigned long match = m68k_opcodes[i].match;
|
||||||
|
if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
|
||||||
|
&& ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
|
||||||
|
/* Only fetch the next two bytes if we need to. */
|
||||||
|
&& (((0xffff & match) == 0)
|
||||||
|
||
|
||||||
|
(FETCH_DATA (info, buffer + 4)
|
||||||
|
&& ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
|
||||||
|
&& ((0xff & buffer[3] & match) == (0xff & opcode)))
|
||||||
|
))
|
||||||
|
{
|
||||||
|
/* Don't use for printout the variants of divul and divsl
|
||||||
|
that have the same register number in two places.
|
||||||
|
The more general variants will match instead. */
|
||||||
|
for (d = m68k_opcodes[i].args; *d; d += 2)
|
||||||
|
if (d[1] == 'D')
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Don't use for printout the variants of most floating
|
||||||
|
point coprocessor instructions which use the same
|
||||||
|
register number in two places, as above. */
|
||||||
|
if (*d == 0)
|
||||||
|
for (d = m68k_opcodes[i].args; *d; d += 2)
|
||||||
|
if (d[1] == 't')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*d == 0 && match > bestmask)
|
||||||
|
{
|
||||||
|
best = i;
|
||||||
|
bestmask = match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle undefined instructions. */
|
||||||
|
if (best < 0)
|
||||||
|
{
|
||||||
|
(*info->fprintf_func) (info->stream, "0%o",
|
||||||
|
(buffer[0] << 8) + buffer[1]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", m68k_opcodes[best].name);
|
||||||
|
|
||||||
|
/* Point at first word of argument data,
|
||||||
|
and at descriptor for first argument. */
|
||||||
|
p = buffer + 2;
|
||||||
|
|
||||||
|
/* Why do this this way? -MelloN */
|
||||||
|
for (d = m68k_opcodes[best].args; *d; d += 2)
|
||||||
|
{
|
||||||
|
if (d[0] == '#')
|
||||||
|
{
|
||||||
|
if (d[1] == 'l' && p - buffer < 6)
|
||||||
|
p = buffer + 6;
|
||||||
|
else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
|
||||||
|
p = buffer + 4;
|
||||||
|
}
|
||||||
|
if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
|
||||||
|
p = buffer + 4;
|
||||||
|
if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
|
||||||
|
p = buffer + 6;
|
||||||
|
if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
|
||||||
|
p = buffer + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
FETCH_DATA (info, p);
|
||||||
|
|
||||||
|
d = m68k_opcodes[best].args;
|
||||||
|
|
||||||
|
if (*d)
|
||||||
|
(*info->fprintf_func) (info->stream, " ");
|
||||||
|
|
||||||
|
while (*d)
|
||||||
|
{
|
||||||
|
p = print_insn_arg (d, buffer, p, memaddr + p - buffer, info);
|
||||||
|
d += 2;
|
||||||
|
if (*d && *(d - 2) != 'I' && *d != 'k')
|
||||||
|
(*info->fprintf_func) (info->stream, ",");
|
||||||
|
}
|
||||||
|
return p - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
print_insn_arg (d, buffer, p, addr, info)
|
||||||
|
char *d;
|
||||||
|
unsigned char *buffer;
|
||||||
|
register unsigned char *p;
|
||||||
|
bfd_vma addr; /* PC for this arg to be relative to */
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
register int val = 0;
|
||||||
|
register int place = d[1];
|
||||||
|
int regno;
|
||||||
|
register CONST char *regname;
|
||||||
|
register unsigned char *p1;
|
||||||
|
double flval;
|
||||||
|
int flt_p;
|
||||||
|
|
||||||
|
switch (*d)
|
||||||
|
{
|
||||||
|
case 'c': /* cache identifier */
|
||||||
|
{
|
||||||
|
static char *cacheFieldName[] = { "NOP", "dc", "ic", "bc" };
|
||||||
|
val = fetch_arg (buffer, place, 2, info);
|
||||||
|
(*info->fprintf_func) (info->stream, cacheFieldName[val]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'a': /* address register indirect only. Cf. case '+'. */
|
||||||
|
{
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream,
|
||||||
|
"%s@",
|
||||||
|
reg_names [fetch_arg (buffer, place, 3, info) + 8]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '_': /* 32-bit absolute address for move16. */
|
||||||
|
{
|
||||||
|
val = NEXTLONG (p);
|
||||||
|
(*info->fprintf_func) (info->stream, "@#");
|
||||||
|
print_address (val, info->stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
(*info->fprintf_func) (info->stream, "ccr");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
(*info->fprintf_func) (info->stream, "sr");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
(*info->fprintf_func) (info->stream, "usp");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
static struct { char *name; int value; } names[]
|
||||||
|
= {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
|
||||||
|
{"tc", 0x003}, {"itt0",0x004}, {"itt1", 0x005},
|
||||||
|
{"dtt0",0x006}, {"dtt1",0x007},
|
||||||
|
{"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
|
||||||
|
{"msp", 0x803}, {"isp", 0x804}, {"mmusr",0x805},
|
||||||
|
{"urp", 0x806}, {"srp", 0x807}};
|
||||||
|
|
||||||
|
val = fetch_arg (buffer, place, 12, info);
|
||||||
|
for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
|
||||||
|
if (names[regno].value == val)
|
||||||
|
{
|
||||||
|
(*info->fprintf_func) (info->stream, names[regno].name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (regno < 0)
|
||||||
|
(*info->fprintf_func) (info->stream, "%d", val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Q':
|
||||||
|
val = fetch_arg (buffer, place, 3, info);
|
||||||
|
/* 0 means 8, except for the bkpt instruction... */
|
||||||
|
if (val == 0 && d[1] != 's')
|
||||||
|
val = 8;
|
||||||
|
(*info->fprintf_func) (info->stream, "#%d", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'M':
|
||||||
|
val = fetch_arg (buffer, place, 8, info);
|
||||||
|
if (val & 0x80)
|
||||||
|
val = val - 0x100;
|
||||||
|
(*info->fprintf_func) (info->stream, "#%d", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'T':
|
||||||
|
val = fetch_arg (buffer, place, 4, info);
|
||||||
|
(*info->fprintf_func) (info->stream, "#%d", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
(*info->fprintf_func) (info->stream, "%s",
|
||||||
|
reg_names[fetch_arg (buffer, place, 3, info)]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "%s",
|
||||||
|
reg_names[fetch_arg (buffer, place, 3, info) + 010]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "%s",
|
||||||
|
reg_names[fetch_arg (buffer, place, 4, info)]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "%s@",
|
||||||
|
reg_names[fetch_arg (buffer, place, 4, info)]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'F':
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "fp%d",
|
||||||
|
fetch_arg (buffer, place, 3, info));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'O':
|
||||||
|
val = fetch_arg (buffer, place, 6, info);
|
||||||
|
if (val & 0x20)
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", reg_names [val & 7]);
|
||||||
|
else
|
||||||
|
(*info->fprintf_func) (info->stream, "%d", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "%s@+",
|
||||||
|
reg_names[fetch_arg (buffer, place, 3, info) + 8]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "%s@-",
|
||||||
|
reg_names[fetch_arg (buffer, place, 3, info) + 8]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
if (place == 'k')
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "{%s}",
|
||||||
|
reg_names[fetch_arg (buffer, place, 3, info)]);
|
||||||
|
else if (place == 'C')
|
||||||
|
{
|
||||||
|
val = fetch_arg (buffer, place, 7, info);
|
||||||
|
if ( val > 63 ) /* This is a signed constant. */
|
||||||
|
val -= 128;
|
||||||
|
(*info->fprintf_func) (info->stream, "{#%d}", val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m68k_opcode_error (info, *d, place);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
case '^':
|
||||||
|
p1 = buffer + (*d == '#' ? 2 : 4);
|
||||||
|
if (place == 's')
|
||||||
|
val = fetch_arg (buffer, place, 4, info);
|
||||||
|
else if (place == 'C')
|
||||||
|
val = fetch_arg (buffer, place, 7, info);
|
||||||
|
else if (place == '8')
|
||||||
|
val = fetch_arg (buffer, place, 3, info);
|
||||||
|
else if (place == '3')
|
||||||
|
val = fetch_arg (buffer, place, 8, info);
|
||||||
|
else if (place == 'b')
|
||||||
|
val = NEXTBYTE (p1);
|
||||||
|
else if (place == 'w')
|
||||||
|
val = NEXTWORD (p1);
|
||||||
|
else if (place == 'l')
|
||||||
|
val = NEXTLONG (p1);
|
||||||
|
else
|
||||||
|
m68k_opcode_error (info, *d, place);
|
||||||
|
(*info->fprintf_func) (info->stream, "#%d", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'B':
|
||||||
|
if (place == 'b')
|
||||||
|
val = NEXTBYTE (p);
|
||||||
|
else if (place == 'B')
|
||||||
|
val = COERCE_SIGNED_CHAR(buffer[1]);
|
||||||
|
else if (place == 'w' || place == 'W')
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
else if (place == 'l' || place == 'L')
|
||||||
|
val = NEXTLONG (p);
|
||||||
|
else if (place == 'g')
|
||||||
|
{
|
||||||
|
val = NEXTBYTE (buffer);
|
||||||
|
if (val == 0)
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
else if (val == -1)
|
||||||
|
val = NEXTLONG (p);
|
||||||
|
}
|
||||||
|
else if (place == 'c')
|
||||||
|
{
|
||||||
|
if (buffer[1] & 0x40) /* If bit six is one, long offset */
|
||||||
|
val = NEXTLONG (p);
|
||||||
|
else
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m68k_opcode_error (info, *d, place);
|
||||||
|
|
||||||
|
print_address (addr + val, info->stream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
(*info->fprintf_func)
|
||||||
|
(info->stream, "%s@(%d)",
|
||||||
|
reg_names[fetch_arg (buffer, place, 3, info)], val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
(*info->fprintf_func) (info->stream, "%s",
|
||||||
|
fpcr_names[fetch_arg (buffer, place, 3, info)]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'I':
|
||||||
|
/* Get coprocessor ID... */
|
||||||
|
val = fetch_arg (buffer, 'd', 3, info);
|
||||||
|
|
||||||
|
if (val != 1) /* Unusual coprocessor ID? */
|
||||||
|
(*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
|
||||||
|
if (place == 'i')
|
||||||
|
p += 2; /* Skip coprocessor extended operands */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
case '~':
|
||||||
|
case '%':
|
||||||
|
case ';':
|
||||||
|
case '@':
|
||||||
|
case '!':
|
||||||
|
case '$':
|
||||||
|
case '?':
|
||||||
|
case '/':
|
||||||
|
case '&':
|
||||||
|
case '`':
|
||||||
|
|
||||||
|
if (place == 'd')
|
||||||
|
{
|
||||||
|
val = fetch_arg (buffer, 'x', 6, info);
|
||||||
|
val = ((val & 7) << 3) + ((val >> 3) & 7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
val = fetch_arg (buffer, 's', 6, info);
|
||||||
|
|
||||||
|
/* Get register number assuming address register. */
|
||||||
|
regno = (val & 7) + 8;
|
||||||
|
regname = reg_names[regno];
|
||||||
|
switch (val >> 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", reg_names[val]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", regname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
(*info->fprintf_func) (info->stream, "%s@", regname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
(*info->fprintf_func) (info->stream, "%s@+", regname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
(*info->fprintf_func) (info->stream, "%s@-", regname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
(*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
p = print_indexed (regno, p, addr, info);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
switch (val & 7)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
(*info->fprintf_func) (info->stream, "@#");
|
||||||
|
print_address (val, info->stream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
val = NEXTLONG (p);
|
||||||
|
(*info->fprintf_func) (info->stream, "@#");
|
||||||
|
print_address (val, info->stream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
print_address (addr + val, info->stream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
p = print_indexed (-1, p, addr, info);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
flt_p = 1; /* Assume it's a float... */
|
||||||
|
switch( place )
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
val = NEXTBYTE (p);
|
||||||
|
flt_p = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'w':
|
||||||
|
val = NEXTWORD (p);
|
||||||
|
flt_p = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
val = NEXTLONG (p);
|
||||||
|
flt_p = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
NEXTSINGLE(flval, p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'F':
|
||||||
|
NEXTDOUBLE(flval, p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
ieee_extended_to_double (&ext_format_68881,
|
||||||
|
(char *)p, &flval);
|
||||||
|
p += 12;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
flval = NEXTPACKED(p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
m68k_opcode_error (info, *d, place);
|
||||||
|
}
|
||||||
|
if ( flt_p ) /* Print a float? */
|
||||||
|
(*info->fprintf_func) (info->stream, "#%g", flval);
|
||||||
|
else
|
||||||
|
(*info->fprintf_func) (info->stream, "#%d", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
(*info->fprintf_func) (info->stream,
|
||||||
|
"<invalid address mode 0%o>",
|
||||||
|
(unsigned) val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'L':
|
||||||
|
case 'l':
|
||||||
|
if (place == 'w')
|
||||||
|
{
|
||||||
|
char doneany;
|
||||||
|
p1 = buffer + 2;
|
||||||
|
val = NEXTWORD (p1);
|
||||||
|
/* Move the pointer ahead if this point is farther ahead
|
||||||
|
than the last. */
|
||||||
|
p = p1 > p ? p1 : p;
|
||||||
|
if (val == 0)
|
||||||
|
{
|
||||||
|
(*info->fprintf_func) (info->stream, "#0");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*d == 'l')
|
||||||
|
{
|
||||||
|
register int newval = 0;
|
||||||
|
for (regno = 0; regno < 16; ++regno)
|
||||||
|
if (val & (0x8000 >> regno))
|
||||||
|
newval |= 1 << regno;
|
||||||
|
val = newval;
|
||||||
|
}
|
||||||
|
val &= 0xffff;
|
||||||
|
doneany = 0;
|
||||||
|
for (regno = 0; regno < 16; ++regno)
|
||||||
|
if (val & (1 << regno))
|
||||||
|
{
|
||||||
|
int first_regno;
|
||||||
|
if (doneany)
|
||||||
|
(*info->fprintf_func) (info->stream, "/");
|
||||||
|
doneany = 1;
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
|
||||||
|
first_regno = regno;
|
||||||
|
while (val & (1 << (regno + 1)))
|
||||||
|
++regno;
|
||||||
|
if (regno > first_regno)
|
||||||
|
(*info->fprintf_func) (info->stream, "-%s",
|
||||||
|
reg_names[regno]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (place == '3')
|
||||||
|
{
|
||||||
|
/* `fmovem' insn. */
|
||||||
|
char doneany;
|
||||||
|
val = fetch_arg (buffer, place, 8, info);
|
||||||
|
if (val == 0)
|
||||||
|
{
|
||||||
|
(*info->fprintf_func) (info->stream, "#0");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*d == 'l')
|
||||||
|
{
|
||||||
|
register int newval = 0;
|
||||||
|
for (regno = 0; regno < 8; ++regno)
|
||||||
|
if (val & (0x80 >> regno))
|
||||||
|
newval |= 1 << regno;
|
||||||
|
val = newval;
|
||||||
|
}
|
||||||
|
val &= 0xff;
|
||||||
|
doneany = 0;
|
||||||
|
for (regno = 0; regno < 8; ++regno)
|
||||||
|
if (val & (1 << regno))
|
||||||
|
{
|
||||||
|
int first_regno;
|
||||||
|
if (doneany)
|
||||||
|
(*info->fprintf_func) (info->stream, "/");
|
||||||
|
doneany = 1;
|
||||||
|
(*info->fprintf_func) (info->stream, "fp%d", regno);
|
||||||
|
first_regno = regno;
|
||||||
|
while (val & (1 << (regno + 1)))
|
||||||
|
++regno;
|
||||||
|
if (regno > first_regno)
|
||||||
|
(*info->fprintf_func) (info->stream, "-fp%d", regno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto de_fault;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: de_fault:
|
||||||
|
m68k_opcode_error (info, *d, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned char *) p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch BITS bits from a position in the instruction specified by CODE.
|
||||||
|
CODE is a "place to put an argument", or 'x' for a destination
|
||||||
|
that is a general address (mode and register).
|
||||||
|
BUFFER contains the instruction. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
fetch_arg (buffer, code, bits, info)
|
||||||
|
unsigned char *buffer;
|
||||||
|
int code;
|
||||||
|
int bits;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
register int val = 0;
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
val = buffer[1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd': /* Destination, for register or quick. */
|
||||||
|
val = (buffer[0] << 8) + buffer[1];
|
||||||
|
val >>= 9;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x': /* Destination, for general arg */
|
||||||
|
val = (buffer[0] << 8) + buffer[1];
|
||||||
|
val >>= 6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[3] >> 4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = buffer[3];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[2] << 8) + buffer[3];
|
||||||
|
val >>= 12;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[2] << 8) + buffer[3];
|
||||||
|
val >>= 6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3':
|
||||||
|
case 'j':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[2] << 8) + buffer[3];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '4':
|
||||||
|
FETCH_DATA (info, buffer + 5);
|
||||||
|
val = (buffer[4] << 8) + buffer[5];
|
||||||
|
val >>= 12;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '5':
|
||||||
|
FETCH_DATA (info, buffer + 5);
|
||||||
|
val = (buffer[4] << 8) + buffer[5];
|
||||||
|
val >>= 6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
FETCH_DATA (info, buffer + 5);
|
||||||
|
val = (buffer[4] << 8) + buffer[5];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '7':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[2] << 8) + buffer[3];
|
||||||
|
val >>= 7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[2] << 8) + buffer[3];
|
||||||
|
val >>= 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '9':
|
||||||
|
FETCH_DATA (info, buffer + 3);
|
||||||
|
val = (buffer[2] << 8) + buffer[3];
|
||||||
|
val >>= 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
val = (buffer[1] >> 6);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bits)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
return val & 3;
|
||||||
|
case 3:
|
||||||
|
return val & 7;
|
||||||
|
case 4:
|
||||||
|
return val & 017;
|
||||||
|
case 5:
|
||||||
|
return val & 037;
|
||||||
|
case 6:
|
||||||
|
return val & 077;
|
||||||
|
case 7:
|
||||||
|
return val & 0177;
|
||||||
|
case 8:
|
||||||
|
return val & 0377;
|
||||||
|
case 12:
|
||||||
|
return val & 07777;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print an indexed argument. The base register is BASEREG (-1 for pc).
|
||||||
|
P points to extension word, in buffer.
|
||||||
|
ADDR is the nominal core address of that extension word. */
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
print_indexed (basereg, p, addr, info)
|
||||||
|
int basereg;
|
||||||
|
unsigned char *p;
|
||||||
|
bfd_vma addr;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
register int word;
|
||||||
|
static char *scales[] = {"", "*2", "*4", "*8"};
|
||||||
|
register int base_disp;
|
||||||
|
register int outer_disp;
|
||||||
|
char buf[40];
|
||||||
|
|
||||||
|
word = NEXTWORD (p);
|
||||||
|
|
||||||
|
/* Generate the text for the index register.
|
||||||
|
Where this will be output is not yet determined. */
|
||||||
|
sprintf (buf, "[%s.%c%s]",
|
||||||
|
reg_names[(word >> 12) & 0xf],
|
||||||
|
(word & 0x800) ? 'l' : 'w',
|
||||||
|
scales[(word >> 9) & 3]);
|
||||||
|
|
||||||
|
/* Handle the 68000 style of indexing. */
|
||||||
|
|
||||||
|
if ((word & 0x100) == 0)
|
||||||
|
{
|
||||||
|
print_base (basereg,
|
||||||
|
((word & 0x80) ? word | 0xff00 : word & 0xff)
|
||||||
|
+ ((basereg == -1) ? addr : 0),
|
||||||
|
info);
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", buf);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the generalized kind. */
|
||||||
|
/* First, compute the displacement to add to the base register. */
|
||||||
|
|
||||||
|
if (word & 0200)
|
||||||
|
basereg = -2;
|
||||||
|
if (word & 0100)
|
||||||
|
buf[0] = 0;
|
||||||
|
base_disp = 0;
|
||||||
|
switch ((word >> 4) & 3)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
base_disp = NEXTWORD (p);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
base_disp = NEXTLONG (p);
|
||||||
|
}
|
||||||
|
if (basereg == -1)
|
||||||
|
base_disp += addr;
|
||||||
|
|
||||||
|
/* Handle single-level case (not indirect) */
|
||||||
|
|
||||||
|
if ((word & 7) == 0)
|
||||||
|
{
|
||||||
|
print_base (basereg, base_disp, info);
|
||||||
|
(*info->fprintf_func) (info->stream, "%s", buf);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Two level. Compute displacement to add after indirection. */
|
||||||
|
|
||||||
|
outer_disp = 0;
|
||||||
|
switch (word & 3)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
outer_disp = NEXTWORD (p);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
outer_disp = NEXTLONG (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*info->fprintf_func) (info->stream, "%d(", outer_disp);
|
||||||
|
print_base (basereg, base_disp, info);
|
||||||
|
|
||||||
|
/* If postindexed, print the closeparen before the index. */
|
||||||
|
if (word & 4)
|
||||||
|
(*info->fprintf_func) (info->stream, ")%s", buf);
|
||||||
|
/* If preindexed, print the closeparen after the index. */
|
||||||
|
else
|
||||||
|
(*info->fprintf_func) (info->stream, "%s)", buf);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
|
||||||
|
REGNO = -1 for pc, -2 for none (suppressed). */
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_base (regno, disp, info)
|
||||||
|
int regno;
|
||||||
|
int disp;
|
||||||
|
disassemble_info *info;
|
||||||
|
{
|
||||||
|
if (regno == -2)
|
||||||
|
(*info->fprintf_func) (info->stream, "%d", disp);
|
||||||
|
else if (regno == -1)
|
||||||
|
(*info->fprintf_func) (info->stream, "0x%x", (unsigned) disp);
|
||||||
|
else
|
||||||
|
(*info->fprintf_func) (info->stream, "%d(%s)", disp, reg_names[regno]);
|
||||||
|
}
|
|
@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
|
#include <ansidecl.h>
|
||||||
#include "sysdep.h"
|
#include "sysdep.h"
|
||||||
#include <stdio.h>
|
#include "dis-asm.h"
|
||||||
#include "bfd.h"
|
|
||||||
#include "opcode/mips.h"
|
#include "opcode/mips.h"
|
||||||
|
|
||||||
/* FIXME: we need direct access to the swapping functions. */
|
/* FIXME: we need direct access to the swapping functions. */
|
||||||
|
@ -60,122 +60,159 @@ extern int print_address PARAMS ((bfd_vma, FILE *));
|
||||||
static CONST char * CONST reg_names[] = REGISTER_NAMES;
|
static CONST char * CONST reg_names[] = REGISTER_NAMES;
|
||||||
|
|
||||||
/* subroutine */
|
/* subroutine */
|
||||||
static unsigned char *
|
static void
|
||||||
print_insn_arg (d, l, stream, pc)
|
print_insn_arg (d, l, pc, info)
|
||||||
char *d;
|
char *d;
|
||||||
register unsigned long int *l;
|
register unsigned long int l;
|
||||||
FILE *stream;
|
|
||||||
bfd_vma pc;
|
bfd_vma pc;
|
||||||
|
struct disassemble_info *info;
|
||||||
{
|
{
|
||||||
switch (*d)
|
switch (*d)
|
||||||
{
|
{
|
||||||
case ',':
|
case ',':
|
||||||
case '(':
|
case '(':
|
||||||
case ')':
|
case ')':
|
||||||
fputc (*d, stream);
|
(*info->fprintf_func) (info->stream, "%c", *d);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rs]);
|
(*info->fprintf_func) (info->stream, "$%s",
|
||||||
|
reg_names[(l >> OP_SH_RS) & OP_MASK_RS]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rt]);
|
(*info->fprintf_func) (info->stream, "$%s",
|
||||||
|
reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate);
|
(*info->fprintf_func) (info->stream, "%d",
|
||||||
|
(l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'j': /* same as i, but sign-extended */
|
case 'j': /* same as i, but sign-extended */
|
||||||
fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta);
|
(*info->fprintf_func) (info->stream, "%d",
|
||||||
|
(l >> OP_SH_DELTA) & OP_MASK_DELTA);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
print_address ((pc & 0xF0000000) | (((struct op_j_fmt *)l)->target << 2),
|
print_address (((pc & 0xF0000000)
|
||||||
stream);
|
| (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)),
|
||||||
|
info->stream);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4, stream);
|
print_address ((((l >> OP_SH_DELTA) & OP_MASK_DELTA) << 2) + pc + 4,
|
||||||
|
info->stream);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
fprintf (stream, "$%s", reg_names[((struct op_r_fmt *) l)->rd]);
|
(*info->fprintf_func) (info->stream, "$%s",
|
||||||
|
reg_names[(l >> OP_SH_RD) & OP_MASK_RD]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt);
|
(*info->fprintf_func) (info->stream, "0x%x",
|
||||||
|
(l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
fprintf (stream, "0x%x", ((struct op_brk_fmt *) l)->code);
|
(*info->fprintf_func) (info->stream, "0x%x",
|
||||||
|
(l >> OP_SH_CODE) & OP_MASK_CODE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs);
|
(*info->fprintf_func) (info->stream, "$f%d",
|
||||||
|
(l >> OP_SH_FS) & OP_MASK_FS);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft);
|
(*info->fprintf_func) (info->stream, "$f%d",
|
||||||
|
(l >> OP_SH_FT) & OP_MASK_FT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd);
|
(*info->fprintf_func) (info->stream, "$f%d",
|
||||||
|
(l >> OP_SH_FD) & OP_MASK_FD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf (stream, "# internal error, undefined modifier(%c)", *d);
|
(*info->fprintf_func) (info->stream,
|
||||||
|
"# internal error, undefined modifier(%c)", *d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the mips instruction at address MEMADDR in debugged memory,
|
/* Print the mips instruction at address MEMADDR in debugged memory,
|
||||||
on STREAM. Returns length of the instruction, in bytes, which is
|
on using INFO. Returns length of the instruction, in bytes, which is
|
||||||
always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if
|
always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if
|
||||||
this is little-endian code. */
|
this is little-endian code. */
|
||||||
|
|
||||||
int
|
int
|
||||||
print_insn_mips (memaddr, buffer, stream, bigendian)
|
_print_insn_mips (memaddr, word, info)
|
||||||
bfd_vma memaddr;
|
bfd_vma memaddr;
|
||||||
bfd_byte *buffer;
|
struct disassemble_info *info;
|
||||||
FILE *stream;
|
unsigned long int word;
|
||||||
int bigendian;
|
|
||||||
{
|
{
|
||||||
register int i;
|
register int i;
|
||||||
register char *d;
|
register char *d;
|
||||||
unsigned long int l;
|
|
||||||
|
|
||||||
/* FIXME: can't we export these functions from bfd? */
|
|
||||||
if (bigendian)
|
|
||||||
l = _do_getb32 (buffer);
|
|
||||||
else
|
|
||||||
l = _do_getl32 (buffer);
|
|
||||||
|
|
||||||
for (i = 0; i < NOPCODES; i++)
|
for (i = 0; i < NOPCODES; i++)
|
||||||
{
|
{
|
||||||
register unsigned int opcode = mips_opcodes[i].opcode;
|
register unsigned int opcode = mips_opcodes[i].opcode;
|
||||||
register unsigned int match = mips_opcodes[i].match;
|
register unsigned int match = mips_opcodes[i].match;
|
||||||
if ((l & match) == opcode)
|
if ((word & match) == opcode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle undefined instructions. */
|
/* Handle undefined instructions. */
|
||||||
if (i == NOPCODES)
|
if (i == NOPCODES)
|
||||||
{
|
{
|
||||||
fprintf (stream, "0x%x",l);
|
(*info->fprintf_func) (info->stream, "0x%x", word);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stream, "%s", mips_opcodes[i].name);
|
(*info->fprintf_func) (info->stream, "%s", mips_opcodes[i].name);
|
||||||
|
|
||||||
if (!(d = mips_opcodes[i].args))
|
if (!(d = mips_opcodes[i].args))
|
||||||
return 4;
|
return 4;
|
||||||
|
|
||||||
fputc (' ', stream);
|
(*info->fprintf_func) (info->stream, " ");
|
||||||
|
|
||||||
while (*d)
|
while (*d)
|
||||||
print_insn_arg (d++, &l, stream, memaddr);
|
print_insn_arg (d++, word, memaddr, info);
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
print_insn_big_mips (memaddr, info)
|
||||||
|
bfd_vma memaddr;
|
||||||
|
struct disassemble_info *info;
|
||||||
|
{
|
||||||
|
bfd_byte buffer[4];
|
||||||
|
int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
|
||||||
|
if (status == 0)
|
||||||
|
return _print_insn_mips (memaddr, _do_getb32 (buffer), info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*info->memory_error_func) (status, memaddr, info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
print_insn_little_mips (memaddr, info)
|
||||||
|
bfd_vma memaddr;
|
||||||
|
struct disassemble_info *info;
|
||||||
|
{
|
||||||
|
bfd_byte buffer[4];
|
||||||
|
int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
|
||||||
|
if (status == 0)
|
||||||
|
return _print_insn_mips (memaddr, _do_getl32 (buffer), info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*info->memory_error_func) (status, memaddr, info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,33 +1,111 @@
|
||||||
#include <stdio.h>
|
/*
|
||||||
|
This file is part of GNU Binutils.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
|
#include <ansidecl.h>
|
||||||
|
#include "sysdep.h"
|
||||||
|
#include "dis-asm.h"
|
||||||
|
|
||||||
#define DEFINE_TABLE
|
#define DEFINE_TABLE
|
||||||
#include "z8k-opc.h"
|
#include "z8k-opc.h"
|
||||||
|
|
||||||
static void fetch_data();
|
|
||||||
static void fetch_instr();
|
#include <setjmp.h>
|
||||||
static unsigned long get_val();
|
|
||||||
static int is_segmented();
|
|
||||||
static int lookup_instr();
|
|
||||||
static void output_instr();
|
|
||||||
static void unpack_instr();
|
|
||||||
static void unparse_instr();
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char instr_buf[24];
|
typedef struct
|
||||||
unsigned long bytes_fetched;
|
{
|
||||||
unsigned long tabl_index;
|
/* These are all indexed by nibble number (i.e only every other entry
|
||||||
char instr_asmsrc[80];
|
of bytes is used, and every 4th entry of words). */
|
||||||
unsigned long arg_reg[0x0f];
|
unsigned char nibbles[24];
|
||||||
unsigned long immediate;
|
unsigned char bytes[24];
|
||||||
unsigned long displacement;
|
unsigned short words[24];
|
||||||
unsigned long address;
|
|
||||||
unsigned long cond_code;
|
|
||||||
unsigned long ctrl_code;
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned long interrupts;
|
|
||||||
} instr_data_s;
|
|
||||||
|
|
||||||
|
/* Nibble number of first word not yet fetched. */
|
||||||
|
int max_fetched;
|
||||||
|
bfd_vma insn_start;
|
||||||
|
jmp_buf bailout;
|
||||||
|
|
||||||
static char *codes[16] =
|
long tabl_index;
|
||||||
|
char instr_asmsrc[80];
|
||||||
|
unsigned long arg_reg[0x0f];
|
||||||
|
unsigned long immediate;
|
||||||
|
unsigned long displacement;
|
||||||
|
unsigned long address;
|
||||||
|
unsigned long cond_code;
|
||||||
|
unsigned long ctrl_code;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned long interrupts;
|
||||||
|
}
|
||||||
|
instr_data_s;
|
||||||
|
|
||||||
|
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
|
||||||
|
to ADDR (exclusive) are valid. Returns 1 for success, longjmps
|
||||||
|
on error. */
|
||||||
|
#define FETCH_DATA(info, nibble) \
|
||||||
|
((nibble) <= ((instr_data_s *)(info->private_data))->max_fetched \
|
||||||
|
? 1 : fetch_data ((info), (nibble)))
|
||||||
|
|
||||||
|
static int
|
||||||
|
fetch_data (info, nibble)
|
||||||
|
struct disassemble_info *info;
|
||||||
|
int nibble;
|
||||||
|
{
|
||||||
|
char mybuf[20];
|
||||||
|
int status;
|
||||||
|
instr_data_s *priv = (instr_data_s *)info->private_data;
|
||||||
|
bfd_vma start = priv->insn_start + priv->max_fetched / 2;
|
||||||
|
|
||||||
|
if ((nibble % 4) != 0)
|
||||||
|
abort ();
|
||||||
|
status = (*info->read_memory_func) (start,
|
||||||
|
mybuf,
|
||||||
|
(nibble - priv->max_fetched) / 2,
|
||||||
|
info);
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
(*info->memory_error_func) (status, start, info);
|
||||||
|
longjmp (priv->bailout);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p = mybuf + priv->max_fetched / 2;
|
||||||
|
|
||||||
|
for (i = priv->max_fetched; i < nibble;)
|
||||||
|
{
|
||||||
|
priv->words[i] = (p[0] << 8) | p[1];
|
||||||
|
|
||||||
|
priv->bytes[i] = *p;
|
||||||
|
priv->nibbles[i++] = *p >> 4;
|
||||||
|
priv->nibbles[i++] = *p &0xf;
|
||||||
|
|
||||||
|
++p;
|
||||||
|
priv->bytes[i] = *p;
|
||||||
|
priv->nibbles[i++] = *p >> 4;
|
||||||
|
priv->nibbles[i++] = *p & 0xf;
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
priv->max_fetched = nibble;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *codes[16] =
|
||||||
{
|
{
|
||||||
"f",
|
"f",
|
||||||
"lt",
|
"lt",
|
||||||
|
@ -47,473 +125,445 @@ static char *codes[16] =
|
||||||
"nc/uge"
|
"nc/uge"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int z8k_lookup_instr PARAMS ((unsigned char*, disassemble_info *));
|
||||||
|
static void output_instr
|
||||||
|
PARAMS ((instr_data_s *, unsigned long, disassemble_info *));
|
||||||
|
static void unpack_instr PARAMS ((instr_data_s *, int, disassemble_info *));
|
||||||
|
static void unparse_instr PARAMS ((instr_data_s *));
|
||||||
|
|
||||||
int print_insn_z8k(addr, in_buf, stream)
|
static int
|
||||||
unsigned long addr;
|
print_insn_z8k (addr, info, is_segmented)
|
||||||
unsigned char *in_buf;
|
unsigned long addr;
|
||||||
FILE *stream;
|
disassemble_info *info;
|
||||||
|
int is_segmented;
|
||||||
{
|
{
|
||||||
instr_data_s instr_data;
|
instr_data_s instr_data;
|
||||||
|
|
||||||
fetch_instr( &in_buf, &instr_data );
|
info->private_data = (PTR) &instr_data;
|
||||||
if ( lookup_instr( &instr_data ))
|
instr_data.max_fetched = 0;
|
||||||
{
|
instr_data.insn_start = addr;
|
||||||
fetch_data( &in_buf, &instr_data );
|
if (setjmp (instr_data.bailout) != 0)
|
||||||
unpack_instr( &instr_data );
|
/* Error return. */
|
||||||
unparse_instr( &instr_data );
|
return -1;
|
||||||
output_instr( &instr_data, addr, stream );
|
|
||||||
return instr_data.bytes_fetched;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stream,".word %02x%02x", in_buf[0], in_buf[1]);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
instr_data.tabl_index = z8k_lookup_instr (instr_data.nibbles, info);
|
||||||
|
if (instr_data.tabl_index > 0)
|
||||||
|
{
|
||||||
|
unpack_instr (&instr_data, is_segmented, info);
|
||||||
|
unparse_instr (&instr_data);
|
||||||
|
output_instr (&instr_data, addr, info);
|
||||||
|
return z8k_table[instr_data.tabl_index].length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FETCH_DATA (info, 4);
|
||||||
|
(*info->fprintf_func) (info->stream, ".word %02x%02x",
|
||||||
|
instr_data.bytes[0], instr_data.bytes[2]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_insn_z8001 (addr, info)
|
||||||
static void fetch_data( in_buf, instr_data )
|
unsigned long addr;
|
||||||
unsigned char **in_buf;
|
disassemble_info *info;
|
||||||
instr_data_s *instr_data;
|
|
||||||
{
|
{
|
||||||
int bytes_2fetch;
|
return print_insn_z8k (addr, info, 1);
|
||||||
|
|
||||||
bytes_2fetch = z8k_table[instr_data->tabl_index].length -
|
|
||||||
instr_data->bytes_fetched;
|
|
||||||
while( bytes_2fetch-- )
|
|
||||||
instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fetch_instr( in_buf, instr_data )
|
print_insn_z8002 (addr, info)
|
||||||
unsigned char **in_buf;
|
unsigned long addr;
|
||||||
instr_data_s *instr_data;
|
disassemble_info *info;
|
||||||
{
|
{
|
||||||
unsigned int loop = 2;
|
return print_insn_z8k (addr, info, 0);
|
||||||
|
|
||||||
instr_data->bytes_fetched = 0;
|
|
||||||
while( loop-- )
|
|
||||||
instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long get_val( instr_buf, start_nibl, nibls_long )
|
int
|
||||||
unsigned char (*instr_buf)[];
|
z8k_lookup_instr (nibbles, info)
|
||||||
unsigned int start_nibl, nibls_long;
|
unsigned char *nibbles;
|
||||||
{
|
disassemble_info *info;
|
||||||
unsigned long ret_val;
|
|
||||||
unsigned char byte_val, nibl_val;
|
|
||||||
unsigned int nibl_index, nibl_lim;
|
|
||||||
unsigned int byte_index;
|
|
||||||
unsigned int which_nibl;
|
|
||||||
|
|
||||||
ret_val = 0;
|
|
||||||
nibl_lim = start_nibl + nibls_long;
|
|
||||||
for( nibl_index = start_nibl; nibl_index < nibl_lim; nibl_index++ )
|
|
||||||
{
|
|
||||||
byte_index = nibl_index / 2;
|
|
||||||
which_nibl = nibl_index % 2;
|
|
||||||
switch( which_nibl )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
byte_val = (*instr_buf)[byte_index];
|
|
||||||
nibl_val = (byte_val >> 4) & 0x0f;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
nibl_val = byte_val & 0x0f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ret_val = (ret_val << 4) | nibl_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_val;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_segmented()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int lookup_instr( instr_data )
|
|
||||||
instr_data_s *instr_data;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
int nibl_index, tabl_index;
|
int nibl_index, tabl_index;
|
||||||
int tablent_found, nibl_matched;
|
int nibl_matched;
|
||||||
unsigned short instr_nibl;
|
unsigned short instr_nibl;
|
||||||
unsigned short tabl_datum, datum_class, datum_value;
|
unsigned short tabl_datum, datum_class, datum_value;
|
||||||
|
|
||||||
nibl_matched = 0;
|
nibl_matched = 0;
|
||||||
tabl_index = 0;
|
tabl_index = 0;
|
||||||
while( ! nibl_matched && z8k_table[tabl_index].name)
|
while (!nibl_matched && z8k_table[tabl_index].name)
|
||||||
{
|
|
||||||
nibl_matched = 1;
|
|
||||||
for( nibl_index = 0; nibl_index < 4 && nibl_matched; nibl_index++ )
|
|
||||||
{
|
{
|
||||||
instr_nibl = get_val( instr_data->instr_buf, nibl_index, 1 );
|
nibl_matched = 1;
|
||||||
|
for (nibl_index = 0; nibl_index < z8k_table[tabl_index].length * 2 && nibl_matched; nibl_index++)
|
||||||
|
{
|
||||||
|
if ((nibl_index % 4) == 0)
|
||||||
|
/* Fetch one word at a time. */
|
||||||
|
FETCH_DATA (info, nibl_index + 4);
|
||||||
|
instr_nibl = nibbles[nibl_index];
|
||||||
|
|
||||||
tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
|
tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
|
||||||
datum_class = tabl_datum & CLASS_MASK;
|
datum_class = tabl_datum & CLASS_MASK;
|
||||||
datum_value = ~CLASS_MASK & tabl_datum;
|
datum_value = ~CLASS_MASK & tabl_datum;
|
||||||
|
|
||||||
switch( datum_class )
|
switch (datum_class)
|
||||||
{
|
{
|
||||||
case CLASS_BIT:
|
case CLASS_BIT:
|
||||||
if( datum_value != instr_nibl ) nibl_matched = 0;
|
if (datum_value != instr_nibl)
|
||||||
break;
|
nibl_matched = 0;
|
||||||
case CLASS_00II:
|
break;
|
||||||
if( ! ((~instr_nibl) & 0x4) ) nibl_matched = 0;
|
case CLASS_00II:
|
||||||
break;
|
if (!((~instr_nibl) & 0x4))
|
||||||
case CLASS_01II:
|
nibl_matched = 0;
|
||||||
if( ! (instr_nibl & 0x4) ) nibl_matched = 0;
|
break;
|
||||||
break;
|
case CLASS_01II:
|
||||||
case CLASS_0CCC:
|
if (!(instr_nibl & 0x4))
|
||||||
if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
|
nibl_matched = 0;
|
||||||
break;
|
break;
|
||||||
case CLASS_1CCC:
|
case CLASS_0CCC:
|
||||||
if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
|
if (!((~instr_nibl) & 0x8))
|
||||||
break;
|
nibl_matched = 0;
|
||||||
case CLASS_0DISP7:
|
break;
|
||||||
if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
|
case CLASS_1CCC:
|
||||||
nibl_index += 1;
|
if (!(instr_nibl & 0x8))
|
||||||
break;
|
nibl_matched = 0;
|
||||||
case CLASS_1DISP7:
|
break;
|
||||||
if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
|
case CLASS_0DISP7:
|
||||||
nibl_index += 1;
|
if (!((~instr_nibl) & 0x8))
|
||||||
break;
|
nibl_matched = 0;
|
||||||
case CLASS_REGN0:
|
nibl_index += 1;
|
||||||
if( instr_nibl == 0 ) nibl_matched = 0;
|
break;
|
||||||
break;
|
case CLASS_1DISP7:
|
||||||
default:
|
if (!(instr_nibl & 0x8))
|
||||||
break;
|
nibl_matched = 0;
|
||||||
}
|
nibl_index += 1;
|
||||||
|
break;
|
||||||
|
case CLASS_REGN0:
|
||||||
|
if (instr_nibl == 0)
|
||||||
|
nibl_matched = 0;
|
||||||
|
break;
|
||||||
|
case CLASS_BIT_1OR2:
|
||||||
|
if ((instr_nibl | 0x2) != (datum_value | 0x2))
|
||||||
|
nibl_matched = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nibl_matched)
|
||||||
|
{
|
||||||
|
return tabl_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabl_index++;
|
||||||
}
|
}
|
||||||
tabl_index++;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
instr_data->tabl_index = tabl_index;
|
|
||||||
|
|
||||||
return nibl_matched;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_instr( instr_data, addr, stream )
|
static void
|
||||||
instr_data_s *instr_data;
|
output_instr (instr_data, addr, info)
|
||||||
unsigned long addr;
|
instr_data_s *instr_data;
|
||||||
FILE *stream;
|
unsigned long addr;
|
||||||
|
disassemble_info *info;
|
||||||
{
|
{
|
||||||
int loop, loop_limit;
|
int loop, loop_limit;
|
||||||
unsigned long word_val;
|
char tmp_str[20];
|
||||||
char tmp_str[20];
|
char out_str[100];
|
||||||
char out_str[100];
|
|
||||||
|
|
||||||
strcpy( out_str, "" );
|
strcpy (out_str, "\t");
|
||||||
|
|
||||||
loop_limit = z8k_table[instr_data->tabl_index].length / 2;
|
loop_limit = z8k_table[instr_data->tabl_index].length * 2;
|
||||||
for( loop = 0; loop < loop_limit; loop++ )
|
FETCH_DATA (info, loop_limit);
|
||||||
{
|
for (loop = 0; loop < loop_limit; loop++)
|
||||||
word_val = get_val( instr_data->instr_buf, loop * 4, 4 );
|
{
|
||||||
sprintf( tmp_str, "%04x ", word_val );
|
sprintf (tmp_str, "%x", instr_data->nibbles[loop]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
while( loop++ < 5 )
|
while (loop++ < 8)
|
||||||
{
|
{
|
||||||
strcat( out_str, " " );
|
strcat (out_str, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat( out_str, instr_data->instr_asmsrc );
|
strcat (out_str, instr_data->instr_asmsrc);
|
||||||
|
|
||||||
fprintf( stream, "%s", out_str );
|
(*info->fprintf_func) (info->stream, "%s", out_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unpack_instr( instr_data )
|
static void
|
||||||
instr_data_s *instr_data;
|
unpack_instr (instr_data, is_segmented, info)
|
||||||
|
instr_data_s *instr_data;
|
||||||
|
int is_segmented;
|
||||||
|
disassemble_info *info;
|
||||||
{
|
{
|
||||||
int nibl_index, word_index;
|
int nibl_count, loop;
|
||||||
int nibl_count, loop;
|
unsigned short instr_nibl, instr_byte, instr_word;
|
||||||
unsigned short instr_nibl, instr_byte, instr_word, instr_long;
|
long instr_long;
|
||||||
unsigned short tabl_datum, datum_class, datum_value;
|
unsigned short tabl_datum, datum_class, datum_value;
|
||||||
|
|
||||||
nibl_count = 0;
|
nibl_count = 0;
|
||||||
loop = 0;
|
loop = 0;
|
||||||
while( z8k_table[instr_data->tabl_index].byte_info[loop] != 0 )
|
while (z8k_table[instr_data->tabl_index].byte_info[loop] != 0)
|
||||||
{
|
{
|
||||||
word_index = (int) nibl_count / 4;
|
FETCH_DATA (info, nibl_count + 4 - (nibl_count % 4));
|
||||||
nibl_index = (int) nibl_count % 4;
|
instr_nibl = instr_data->nibbles[nibl_count];
|
||||||
|
instr_byte = instr_data->bytes[nibl_count];
|
||||||
switch( nibl_index )
|
instr_word = instr_data->words[nibl_count];
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
|
|
||||||
instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
|
|
||||||
instr_word = get_val( instr_data->instr_buf, nibl_count, 4 );
|
|
||||||
instr_long = get_val( instr_data->instr_buf, nibl_count, 8 );
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
|
|
||||||
instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
|
tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
|
||||||
datum_class = tabl_datum & CLASS_MASK;
|
datum_class = tabl_datum & CLASS_MASK;
|
||||||
datum_value = tabl_datum & ~CLASS_MASK;
|
datum_value = tabl_datum & ~CLASS_MASK;
|
||||||
|
|
||||||
switch( datum_class )
|
switch (datum_class)
|
||||||
{
|
{
|
||||||
case CLASS_X:
|
case CLASS_X:
|
||||||
instr_data->address = instr_nibl;
|
instr_data->address = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_BA:
|
case CLASS_BA:
|
||||||
instr_data->displacement = instr_nibl;
|
instr_data->displacement = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_BX:
|
case CLASS_BX:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_DISP:
|
case CLASS_DISP:
|
||||||
switch( datum_value )
|
switch (datum_value)
|
||||||
{
|
{
|
||||||
case ARG_DISP16:
|
case ARG_DISP16:
|
||||||
instr_data->displacement = instr_word;
|
instr_data->displacement = instr_word;
|
||||||
nibl_count += 3;
|
nibl_count += 3;
|
||||||
break;
|
break;
|
||||||
case ARG_DISP12:
|
case ARG_DISP12:
|
||||||
instr_data->displacement = instr_word & 0x0fff;
|
instr_data->displacement = instr_word & 0x0fff;
|
||||||
nibl_count += 2;
|
nibl_count += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_IMM:
|
case CLASS_IMM:
|
||||||
switch( datum_value )
|
switch (datum_value)
|
||||||
{
|
{
|
||||||
case ARG_IMM4:
|
case ARG_IMM4:
|
||||||
instr_data->immediate = instr_nibl;
|
instr_data->immediate = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case ARG_IMM8:
|
case ARG_NIM8:
|
||||||
instr_data->immediate = instr_byte;
|
instr_data->immediate = (-instr_byte);
|
||||||
nibl_count += 1;
|
nibl_count += 1;
|
||||||
break;
|
break;
|
||||||
case ARG_IMM16:
|
case ARG_IMM8:
|
||||||
instr_data->immediate = instr_word;
|
instr_data->immediate = instr_byte;
|
||||||
nibl_count += 3;
|
nibl_count += 1;
|
||||||
break;
|
break;
|
||||||
case ARG_IMM32:
|
case ARG_IMM16:
|
||||||
instr_data->immediate = instr_long;
|
instr_data->immediate = instr_word;
|
||||||
nibl_count += 7;
|
nibl_count += 3;
|
||||||
break;
|
break;
|
||||||
case ARG_IMMN:
|
case ARG_IMM32:
|
||||||
instr_data->immediate = instr_nibl -1;
|
FETCH_DATA (info, nibl_count + 8);
|
||||||
break;
|
instr_long = (instr_data->words[nibl_count] << 16)
|
||||||
/* ????? */
|
| (instr_data->words[nibl_count + 4]);
|
||||||
/* missing ARG_IMMNMINUS1 */
|
instr_data->immediate = instr_long;
|
||||||
case ARG_IMM_1:
|
nibl_count += 7;
|
||||||
instr_data->immediate = 1;
|
break;
|
||||||
break;
|
case ARG_IMMN:
|
||||||
case ARG_IMM_2:
|
instr_data->immediate = instr_nibl - 1;
|
||||||
instr_data->immediate = 2;
|
break;
|
||||||
break;
|
/* ????? */
|
||||||
case ARG_NIM16:
|
/* missing ARG_IMMNMINUS1 */
|
||||||
instr_data->immediate = (- instr_word);
|
case ARG_IMM_1:
|
||||||
nibl_count += 3;
|
instr_data->immediate = 1;
|
||||||
break;
|
break;
|
||||||
case ARG_IMM2:
|
case ARG_IMM_2:
|
||||||
instr_data->immediate = instr_nibl & 0x3;
|
instr_data->immediate = 2;
|
||||||
break;
|
break;
|
||||||
default:
|
case ARG_IMM2:
|
||||||
break;
|
instr_data->immediate = instr_nibl & 0x3;
|
||||||
}
|
break;
|
||||||
break;
|
default:
|
||||||
case CLASS_CC:
|
break;
|
||||||
instr_data->cond_code = instr_nibl;
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_CTRL:
|
case CLASS_CC:
|
||||||
instr_data->ctrl_code = instr_nibl;
|
instr_data->cond_code = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_DA:
|
case CLASS_CTRL:
|
||||||
case CLASS_ADDRESS:
|
instr_data->ctrl_code = instr_nibl;
|
||||||
if( is_segmented() )
|
break;
|
||||||
{
|
case CLASS_DA:
|
||||||
if( instr_nibl & 0x8 )
|
case CLASS_ADDRESS:
|
||||||
{
|
if (is_segmented)
|
||||||
instr_data->address = ((instr_word & 0x7f00) << 8) +
|
{
|
||||||
(instr_long & 0xffff);
|
if (instr_nibl & 0x8)
|
||||||
nibl_count += 7;
|
{
|
||||||
}
|
FETCH_DATA (info, nibl_count + 8);
|
||||||
else
|
instr_long = (instr_data->words[nibl_count] << 16)
|
||||||
{
|
| (instr_data->words[nibl_count + 4]);
|
||||||
instr_data->address = ((instr_word & 0x7f00) << 8) +
|
instr_data->address = ((instr_word & 0x7f00) << 8) +
|
||||||
(instr_word & 0x00ff);
|
(instr_long & 0xffff);
|
||||||
nibl_count += 3;
|
nibl_count += 7;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
instr_data->address = ((instr_word & 0x7f00) << 8) +
|
||||||
instr_data->address = instr_word;
|
(instr_word & 0x00ff);
|
||||||
nibl_count += 3;
|
nibl_count += 3;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case CLASS_0CCC:
|
else
|
||||||
instr_data->cond_code = instr_nibl & 0x7;
|
{
|
||||||
break;
|
instr_data->address = instr_word;
|
||||||
case CLASS_1CCC:
|
nibl_count += 3;
|
||||||
instr_data->cond_code = instr_nibl & 0x7;
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_0DISP7:
|
case CLASS_0CCC:
|
||||||
instr_data->displacement = instr_byte & 0x7f;
|
instr_data->cond_code = instr_nibl & 0x7;
|
||||||
nibl_count += 1;
|
break;
|
||||||
break;
|
case CLASS_1CCC:
|
||||||
case CLASS_1DISP7:
|
instr_data->cond_code = instr_nibl & 0x7;
|
||||||
instr_data->displacement = instr_byte & 0x7f;
|
break;
|
||||||
nibl_count += 1;
|
case CLASS_0DISP7:
|
||||||
break;
|
instr_data->displacement = instr_byte & 0x7f;
|
||||||
case CLASS_01II:
|
nibl_count += 1;
|
||||||
instr_data->interrupts = instr_nibl & 0x3;
|
break;
|
||||||
break;
|
case CLASS_1DISP7:
|
||||||
case CLASS_00II:
|
instr_data->displacement = instr_byte & 0x7f;
|
||||||
instr_data->interrupts = instr_nibl & 0x3;
|
nibl_count += 1;
|
||||||
break;
|
break;
|
||||||
case CLASS_BIT:
|
case CLASS_01II:
|
||||||
/* do nothing */
|
instr_data->interrupts = instr_nibl & 0x3;
|
||||||
break;
|
break;
|
||||||
case CLASS_IR:
|
case CLASS_00II:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->interrupts = instr_nibl & 0x3;
|
||||||
break;
|
break;
|
||||||
case CLASS_FLAGS:
|
case CLASS_BIT:
|
||||||
instr_data->flags = instr_nibl;
|
/* do nothing */
|
||||||
break;
|
break;
|
||||||
case CLASS_REG:
|
case CLASS_IR:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_BYTE:
|
case CLASS_FLAGS:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->flags = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_WORD:
|
case CLASS_REG:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_QUAD:
|
case CLASS_REG_BYTE:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_LONG:
|
case CLASS_REG_WORD:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
break;
|
break;
|
||||||
case CLASS_REGN0:
|
case CLASS_REG_QUAD:
|
||||||
instr_data->arg_reg[datum_value] = instr_nibl;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
break;
|
break;
|
||||||
default:
|
case CLASS_REG_LONG:
|
||||||
break;
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
}
|
break;
|
||||||
|
case CLASS_REGN0:
|
||||||
|
instr_data->arg_reg[datum_value] = instr_nibl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
loop += 1;
|
loop += 1;
|
||||||
nibl_count += 1;
|
nibl_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unparse_instr( instr_data )
|
static void
|
||||||
instr_data_s *instr_data;
|
unparse_instr (instr_data)
|
||||||
|
instr_data_s *instr_data;
|
||||||
{
|
{
|
||||||
unsigned short tabl_datum, datum_class, datum_value;
|
unsigned short tabl_datum, datum_class, datum_value;
|
||||||
int loop, loop_limit;
|
int loop, loop_limit;
|
||||||
char out_str[80], tmp_str[25];
|
char out_str[80], tmp_str[25];
|
||||||
|
|
||||||
sprintf( out_str, "\t%s\t", z8k_table[instr_data->tabl_index].name );
|
sprintf (out_str, "\t%s\t", z8k_table[instr_data->tabl_index].name);
|
||||||
|
|
||||||
loop_limit = z8k_table[instr_data->tabl_index].noperands;
|
loop_limit = z8k_table[instr_data->tabl_index].noperands;
|
||||||
for( loop = 0; loop < loop_limit; loop++ )
|
for (loop = 0; loop < loop_limit; loop++)
|
||||||
{
|
{
|
||||||
if( loop )
|
if (loop)
|
||||||
strcat( out_str, "," );
|
strcat (out_str, ",");
|
||||||
|
|
||||||
tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
|
tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
|
||||||
datum_class = tabl_datum & CLASS_MASK;
|
datum_class = tabl_datum & CLASS_MASK;
|
||||||
datum_value = tabl_datum & ~CLASS_MASK;
|
datum_value = tabl_datum & ~CLASS_MASK;
|
||||||
|
|
||||||
switch( datum_class )
|
switch (datum_class)
|
||||||
{
|
{
|
||||||
case CLASS_X:
|
case CLASS_X:
|
||||||
sprintf( tmp_str, "0x%0x(R%d)", instr_data->address,
|
sprintf (tmp_str, "0x%0x(R%d)", instr_data->address,
|
||||||
instr_data->arg_reg[datum_value] );
|
instr_data->arg_reg[datum_value]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_BA:
|
case CLASS_BA:
|
||||||
sprintf( tmp_str, "r%d(#%x)", instr_data->arg_reg[datum_value],
|
sprintf (tmp_str, "r%d(#%x)", instr_data->arg_reg[datum_value],
|
||||||
instr_data->displacement);
|
instr_data->immediate);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_BX:
|
case CLASS_BX:
|
||||||
sprintf( tmp_str, "r%d(R%d)", instr_data->arg_reg[datum_value],
|
sprintf (tmp_str, "r%d(R%d)", instr_data->arg_reg[datum_value],
|
||||||
instr_data->arg_reg[ARG_RX] );
|
instr_data->arg_reg[ARG_RX]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_DISP:
|
case CLASS_DISP:
|
||||||
sprintf( tmp_str, "#0x%0x", instr_data->displacement );
|
sprintf (tmp_str, "#0x%0x", instr_data->displacement);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_IMM:
|
case CLASS_IMM:
|
||||||
sprintf( tmp_str, "#0x%0x", instr_data->immediate );
|
sprintf (tmp_str, "#0x%0x", instr_data->immediate);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_CC:
|
case CLASS_CC:
|
||||||
sprintf( tmp_str, "%s", codes[instr_data->cond_code] );
|
sprintf (tmp_str, "%s", codes[instr_data->cond_code]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_CTRL:
|
case CLASS_CTRL:
|
||||||
sprintf( tmp_str, "0x%0x", instr_data->ctrl_code );
|
sprintf (tmp_str, "0x%0x", instr_data->ctrl_code);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_DA:
|
case CLASS_DA:
|
||||||
case CLASS_ADDRESS:
|
case CLASS_ADDRESS:
|
||||||
sprintf( tmp_str, "#0x%0x", instr_data->address );
|
sprintf (tmp_str, "#0x%0x", instr_data->address);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_IR:
|
case CLASS_IR:
|
||||||
sprintf( tmp_str, "@R%d", instr_data->arg_reg[datum_value] );
|
sprintf (tmp_str, "@R%d", instr_data->arg_reg[datum_value]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_FLAGS:
|
case CLASS_FLAGS:
|
||||||
sprintf( tmp_str, "0x%0x", instr_data->flags );
|
sprintf (tmp_str, "0x%0x", instr_data->flags);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_BYTE:
|
case CLASS_REG_BYTE:
|
||||||
if( instr_data->arg_reg[datum_value] >= 0x8 )
|
if (instr_data->arg_reg[datum_value] >= 0x8)
|
||||||
{
|
{
|
||||||
sprintf( tmp_str, "rl%d",
|
sprintf (tmp_str, "rl%d",
|
||||||
instr_data->arg_reg[datum_value] - 0x8 );
|
instr_data->arg_reg[datum_value] - 0x8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf( tmp_str, "rh%d", instr_data->arg_reg[datum_value] );
|
sprintf (tmp_str, "rh%d", instr_data->arg_reg[datum_value]);
|
||||||
}
|
}
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_WORD:
|
case CLASS_REG_WORD:
|
||||||
sprintf( tmp_str, "r%d", instr_data->arg_reg[datum_value] );
|
sprintf (tmp_str, "r%d", instr_data->arg_reg[datum_value]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_QUAD:
|
case CLASS_REG_QUAD:
|
||||||
sprintf( tmp_str, "rq%d", instr_data->arg_reg[datum_value] );
|
sprintf (tmp_str, "rq%d", instr_data->arg_reg[datum_value]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
case CLASS_REG_LONG:
|
case CLASS_REG_LONG:
|
||||||
sprintf( tmp_str, "rr%d", instr_data->arg_reg[datum_value] );
|
sprintf (tmp_str, "rr%d", instr_data->arg_reg[datum_value]);
|
||||||
strcat( out_str, tmp_str );
|
strcat (out_str, tmp_str);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy( instr_data->instr_asmsrc, out_str );
|
strcpy (instr_data->instr_asmsrc, out_str);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue