diff options
Diffstat (limited to 'opcodes/ns32k-dis.c')
-rw-r--r-- | opcodes/ns32k-dis.c | 894 |
1 files changed, 894 insertions, 0 deletions
diff --git a/opcodes/ns32k-dis.c b/opcodes/ns32k-dis.c new file mode 100644 index 0000000..050266b --- /dev/null +++ b/opcodes/ns32k-dis.c @@ -0,0 +1,894 @@ +/* Print National Semiconductor 32000 instructions. + Copyright (c) 1986, 88, 91, 92, 94, 95, 1998 Free Software Foundation, Inc. + +This file is part of opcodes library. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "bfd.h" +#include "sysdep.h" +#include "dis-asm.h" +#if !defined(const) && !defined(__STDC__) +#define const +#endif +#include "opcode/ns32k.h" +#include "opintl.h" + +static disassemble_info *dis_info; + +/* + * Hacks to get it to compile <= READ THESE AS FIXES NEEDED + */ +#define INVALID_FLOAT(val, size) invalid_float((char *)val, size) + +static int print_insn_arg + PARAMS ((int, int, int *, char *, bfd_vma, char *, int)); +static int get_displacement PARAMS ((char *, int *)); +static int invalid_float PARAMS ((char *, int)); + +static long read_memory_integer(addr, nr) + unsigned char *addr; + int nr; +{ + long val; + int i; + for (val = 0, i = nr - 1; i >= 0; i--) { + val = (val << 8); + val |= (0xff & *(addr + i)); + } + return val; +} + +/* 32000 instructions are never longer than this. */ +#define MAXLEN 62 + + +#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, 1); + } + else + priv->max_fetched = addr; + return 1; +} +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0]) + +#define NEXT_IS_ADDR '|' + + +struct ns32k_option { + char *pattern; /* the option itself */ + unsigned long value; /* binary value of the option */ + unsigned long match; /* these bits must match */ +}; + + +static const struct ns32k_option opt_u[]= /* restore, exit */ +{ + { "r0", 0x80, 0x80 }, + { "r1", 0x40, 0x40 }, + { "r2", 0x20, 0x20 }, + { "r3", 0x10, 0x10 }, + { "r4", 0x08, 0x08 }, + { "r5", 0x04, 0x04 }, + { "r6", 0x02, 0x02 }, + { "r7", 0x01, 0x01 }, + { 0 , 0x00, 0x00 } +}; + +static const struct ns32k_option opt_U[]= /* save, enter */ +{ + { "r0", 0x01, 0x01 }, + { "r1", 0x02, 0x02 }, + { "r2", 0x04, 0x04 }, + { "r3", 0x08, 0x08 }, + { "r4", 0x10, 0x10 }, + { "r5", 0x20, 0x20 }, + { "r6", 0x40, 0x40 }, + { "r7", 0x80, 0x80 }, + { 0 , 0x00, 0x00 } +}; + +static const struct ns32k_option opt_O[]= /* setcfg */ +{ + { "c", 0x8, 0x8 }, + { "m", 0x4, 0x4 }, + { "f", 0x2, 0x2 }, + { "i", 0x1, 0x1 }, + { 0 , 0x0, 0x0 } +}; + +static const struct ns32k_option opt_C[]= /* cinv */ +{ + { "a", 0x4, 0x4 }, + { "i", 0x2, 0x2 }, + { "d", 0x1, 0x1 }, + { 0 , 0x0, 0x0 } +}; + +static const struct ns32k_option opt_S[]= /* string inst */ +{ + { "b", 0x1, 0x1 }, + { "u", 0x6, 0x6 }, + { "w", 0x2, 0x2 }, + { 0 , 0x0, 0x0 } +}; + +static const struct ns32k_option list_P532[]= /* lpr spr */ +{ + { "us", 0x0, 0xf }, + { "dcr", 0x1, 0xf }, + { "bpc", 0x2, 0xf }, + { "dsr", 0x3, 0xf }, + { "car", 0x4, 0xf }, + { "fp", 0x8, 0xf }, + { "sp", 0x9, 0xf }, + { "sb", 0xa, 0xf }, + { "usp", 0xb, 0xf }, + { "cfg", 0xc, 0xf }, + { "psr", 0xd, 0xf }, + { "intbase", 0xe, 0xf }, + { "mod", 0xf, 0xf }, + { 0 , 0x00, 0xf } +}; + +static const struct ns32k_option list_M532[]= /* lmr smr */ +{ + { "mcr", 0x9, 0xf }, + { "msr", 0xa, 0xf }, + { "tear", 0xb, 0xf }, + { "ptb0", 0xc, 0xf }, + { "ptb1", 0xd, 0xf }, + { "ivar0", 0xe, 0xf }, + { "ivar1", 0xf, 0xf }, + { 0 , 0x0, 0xf } +}; + +static const struct ns32k_option list_P032[]= /* lpr spr */ +{ + { "upsr", 0x0, 0xf }, + { "fp", 0x8, 0xf }, + { "sp", 0x9, 0xf }, + { "sb", 0xa, 0xf }, + { "psr", 0xb, 0xf }, + { "intbase", 0xe, 0xf }, + { "mod", 0xf, 0xf }, + { 0 , 0x0, 0xf } +}; + +static const struct ns32k_option list_M032[]= /* lmr smr */ +{ + { "bpr0", 0x0, 0xf }, + { "bpr1", 0x1, 0xf }, + { "pf0", 0x4, 0xf }, + { "pf1", 0x5, 0xf }, + { "sc", 0x8, 0xf }, + { "msr", 0xa, 0xf }, + { "bcnt", 0xb, 0xf }, + { "ptb0", 0xc, 0xf }, + { "ptb1", 0xd, 0xf }, + { "eia", 0xf, 0xf }, + { 0 , 0x0, 0xf } +}; + + +/* + * figure out which options are present + */ +static void +optlist(options, optionP, result) + int options; + const struct ns32k_option *optionP; + char *result; +{ + if (options == 0) { + sprintf(result, "[]"); + return; + } + sprintf(result, "["); + + for (; (options != 0) && optionP->pattern; optionP++) { + if ((options & optionP->match) == optionP->value) { + /* we found a match, update result and options */ + strcat(result, optionP->pattern); + options &= ~optionP->value; + if (options != 0) /* more options to come */ + strcat(result, ","); + } + } + if (options != 0) + strcat(result, "undefined"); + + strcat(result, "]"); +} + +static void +list_search (reg_value, optionP, result) + int reg_value; + const struct ns32k_option *optionP; + char *result; +{ + for (; optionP->pattern; optionP++) { + if ((reg_value & optionP->match) == optionP->value) { + sprintf(result, "%s", optionP->pattern); + return; + } + } + sprintf(result, "undefined"); +} + +/* + * extract "count" bits starting "offset" bits + * into buffer + */ + +static int +bit_extract (buffer, offset, count) + bfd_byte *buffer; + int offset; + int count; +{ + int result; + int bit; + + buffer += offset >> 3; + offset &= 7; + bit = 1; + result = 0; + while (count--) + { + FETCH_DATA(dis_info, buffer + 1); + if ((*buffer & (1 << offset))) + result |= bit; + if (++offset == 8) + { + offset = 0; + buffer++; + } + bit <<= 1; + } + return result; +} + +/* Like bit extract but the buffer is valid and doen't need to be + * fetched + */ +static int +bit_extract_simple (buffer, offset, count) + bfd_byte *buffer; + int offset; + int count; +{ + int result; + int mask; + int bit; + + buffer += offset >> 3; + offset &= 7; + bit = 1; + result = 0; + while (count--) + { + if ((*buffer & (1 << offset))) + result |= bit; + if (++offset == 8) + { + offset = 0; + buffer++; + } + bit <<= 1; + } + return result; +} + +static void +bit_copy (buffer, offset, count, to) + char *buffer; + int offset; + int count; + char *to; +{ + for(; count > 8; count -= 8, to++, offset += 8) + *to = bit_extract (buffer, offset, 8); + *to = bit_extract (buffer, offset, count); +} + + +static int +sign_extend (value, bits) + int value, bits; +{ + value = value & ((1 << bits) - 1); + return (value & (1 << (bits-1)) + ? value | (~((1 << bits) - 1)) + : value); +} + +static void +flip_bytes (ptr, count) + char *ptr; + int count; +{ + char tmp; + + while (count > 0) + { + tmp = ptr[0]; + ptr[0] = ptr[count-1]; + ptr[count-1] = tmp; + ptr++; + count -= 2; + } +} + +/* Given a character C, does it represent a general addressing mode? */ +#define Is_gen(c) \ + ((c) == 'F' || (c) == 'L' || (c) == 'B' \ + || (c) == 'W' || (c) == 'D' || (c) == 'A' || (c) == 'I' || (c) == 'Z') + +/* Adressing modes. */ +#define Adrmod_index_byte 0x1c +#define Adrmod_index_word 0x1d +#define Adrmod_index_doubleword 0x1e +#define Adrmod_index_quadword 0x1f + +/* Is MODE an indexed addressing mode? */ +#define Adrmod_is_index(mode) \ + (mode == Adrmod_index_byte \ + || mode == Adrmod_index_word \ + || mode == Adrmod_index_doubleword \ + || mode == Adrmod_index_quadword) + + +/* Print the 32000 instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn_ns32k (memaddr, info) + bfd_vma memaddr; + disassemble_info *info; +{ + register unsigned int i; + register char *d; + unsigned short first_word; + int ioffset; /* bits into instruction */ + int aoffset; /* bits into arguments */ + char arg_bufs[MAX_ARGS+1][ARG_LEN]; + int argnum; + int maxarg; + struct private priv; + bfd_byte *buffer = priv.the_buffer; + dis_info = info; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = memaddr; + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + /* Look for 8bit opcodes first. Other wise, fetching two bytes could take + * us over the end of accessible data unnecessarilly + */ + FETCH_DATA(info, buffer + 1); + for (i = 0; i < NOPCODES; i++) + if (ns32k_opcodes[i].opcode_id_size <= 8 + && ((buffer[0] + & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1)) + == ns32k_opcodes[i].opcode_seed)) + break; + if (i == NOPCODES) { + /* Maybe it is 9 to 16 bits big */ + FETCH_DATA(info, buffer + 2); + first_word = read_memory_integer(buffer, 2); + + for (i = 0; i < NOPCODES; i++) + if ((first_word + & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1)) + == ns32k_opcodes[i].opcode_seed) + break; + + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + (*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]); + return 1; + } + } + + (*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name); + + ioffset = ns32k_opcodes[i].opcode_size; + aoffset = ns32k_opcodes[i].opcode_size; + d = ns32k_opcodes[i].operands; + + if (*d) + { + /* Offset in bits of the first thing beyond each index byte. + Element 0 is for operand A and element 1 is for operand B. + The rest are irrelevant, but we put them here so we don't + index outside the array. */ + int index_offset[MAX_ARGS]; + + /* 0 for operand A, 1 for operand B, greater for other args. */ + int whicharg = 0; + + (*dis_info->fprintf_func)(dis_info->stream, "\t"); + + maxarg = 0; + + /* First we have to find and keep track of the index bytes, + if we are using scaled indexed addressing mode, since the index + bytes occur right after the basic instruction, not as part + of the addressing extension. */ + if (Is_gen(d[1])) + { + int addr_mode = bit_extract (buffer, ioffset - 5, 5); + + if (Adrmod_is_index (addr_mode)) + { + aoffset += 8; + index_offset[0] = aoffset; + } + } + if (d[2] && Is_gen(d[3])) + { + int addr_mode = bit_extract (buffer, ioffset - 10, 5); + + if (Adrmod_is_index (addr_mode)) + { + aoffset += 8; + index_offset[1] = aoffset; + } + } + + while (*d) + { + argnum = *d - '1'; + d++; + if (argnum > maxarg && argnum < MAX_ARGS) + maxarg = argnum; + ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer, + memaddr, arg_bufs[argnum], + index_offset[whicharg]); + d++; + whicharg++; + } + for (argnum = 0; argnum <= maxarg; argnum++) + { + bfd_vma addr; + char *ch; + for (ch = arg_bufs[argnum]; *ch;) + { + if (*ch == NEXT_IS_ADDR) + { + ++ch; + addr = bfd_scan_vma (ch, NULL, 16); + (*dis_info->print_address_func) (addr, dis_info); + while (*ch && *ch != NEXT_IS_ADDR) + ++ch; + if (*ch) + ++ch; + } + else + (*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++); + } + if (argnum < maxarg) + (*dis_info->fprintf_func)(dis_info->stream, ", "); + } + } + return aoffset / 8; +} + +/* Print an instruction operand of category given by d. IOFFSET is + the bit position below which small (<1 byte) parts of the operand can + be found (usually in the basic instruction, but for indexed + addressing it can be in the index byte). AOFFSETP is a pointer to the + bit position of the addressing extension. BUFFER contains the + instruction. ADDR is where BUFFER was read from. Put the disassembled + version of the operand in RESULT. INDEX_OFFSET is the bit position + of the index byte (it contains garbage if this operand is not a + general operand using scaled indexed addressing mode). */ + +static int +print_insn_arg (d, ioffset, aoffsetp, buffer, addr, result, index_offset) + int d; + int ioffset, *aoffsetp; + char *buffer; + bfd_vma addr; + char *result; + int index_offset; +{ + int addr_mode; + float Fvalue; + double Lvalue; + int Ivalue; + int disp1, disp2; + int index; + int size; + + switch (d) + { + case 'f': + /* a "gen" operand but 5 bits from the end of instruction */ + ioffset -= 5; + case 'Z': + case 'F': + case 'L': + case 'I': + case 'B': + case 'W': + case 'D': + case 'A': + addr_mode = bit_extract (buffer, ioffset-5, 5); + ioffset -= 5; + switch (addr_mode) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + /* register mode R0 -- R7 */ + switch (d) + { + case 'F': + case 'L': + case 'Z': + sprintf (result, "f%d", addr_mode); + break; + default: + sprintf (result, "r%d", addr_mode); + } + break; + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + /* Register relative disp(R0 -- R7) */ + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(r%d)", disp1, addr_mode & 7); + break; + case 0x10: + case 0x11: + case 0x12: + /* Memory relative disp2(disp1(FP, SP, SB)) */ + disp1 = get_displacement (buffer, aoffsetp); + disp2 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(%d(%s))", disp2, disp1, + addr_mode==0x10?"fp":addr_mode==0x11?"sp":"sb"); + break; + case 0x13: + /* reserved */ + sprintf (result, "reserved"); + break; + case 0x14: + /* Immediate */ + switch (d) + { + case 'I': case 'Z': case 'A': + /* I and Z are output operands and can`t be immediate + * A is an address and we can`t have the address of + * an immediate either. We don't know how much to increase + * aoffsetp by since whatever generated this is broken + * anyway! + */ + sprintf (result, _("$<undefined>")); + break; + case 'B': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + Ivalue = sign_extend (Ivalue, 8); + *aoffsetp += 8; + sprintf (result, "$%d", Ivalue); + break; + case 'W': + Ivalue = bit_extract (buffer, *aoffsetp, 16); + flip_bytes (&Ivalue, 2); + *aoffsetp += 16; + Ivalue = sign_extend (Ivalue, 16); + sprintf (result, "$%d", Ivalue); + break; + case 'D': + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + *aoffsetp += 32; + sprintf (result, "$%d", Ivalue); + break; + case 'F': + bit_copy (buffer, *aoffsetp, 32, (char *) &Fvalue); + flip_bytes (&Fvalue, 4); + *aoffsetp += 32; + if (INVALID_FLOAT (&Fvalue, 4)) + sprintf (result, "<<invalid float 0x%.8x>>", *(int *) &Fvalue); + else /* assume host has ieee float */ + sprintf (result, "$%g", Fvalue); + break; + case 'L': + bit_copy (buffer, *aoffsetp, 64, (char *) &Lvalue); + flip_bytes (&Lvalue, 8); + *aoffsetp += 64; + if (INVALID_FLOAT (&Lvalue, 8)) + sprintf (result, "<<invalid long 0x%.8x%.8x>>", + *(((int *) &Lvalue) + 1), *(int *) &Lvalue); + else /* assume host has ieee float */ + sprintf (result, "$%g", Lvalue); + break; + } + break; + case 0x15: + /* Absolute @disp */ + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "@|%d|", disp1); + break; + case 0x16: + /* External EXT(disp1) + disp2 (Mod table stuff) */ + disp1 = get_displacement (buffer, aoffsetp); + disp2 = get_displacement (buffer, aoffsetp); + sprintf (result, "EXT(%d) + %d", disp1, disp2); + break; + case 0x17: + /* Top of stack tos */ + sprintf (result, "tos"); + break; + case 0x18: + /* Memory space disp(FP) */ + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(fp)", disp1); + break; + case 0x19: + /* Memory space disp(SP) */ + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(sp)", disp1); + break; + case 0x1a: + /* Memory space disp(SB) */ + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(sb)", disp1); + break; + case 0x1b: + /* Memory space disp(PC) */ + disp1 = get_displacement (buffer, aoffsetp); + *result++ = NEXT_IS_ADDR; + sprintf_vma (result, addr + disp1); + result += strlen (result); + *result++ = NEXT_IS_ADDR; + *result = '\0'; + break; + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + /* Scaled index basemode[R0 -- R7:B,W,D,Q] */ + index = bit_extract (buffer, index_offset - 8, 3); + print_insn_arg (d, index_offset, aoffsetp, buffer, addr, + result, 0); + { + static const char *ind = "bwdq"; + char *off; + + off = result + strlen (result); + sprintf (off, "[r%d:%c]", index, + ind[addr_mode & 3]); + } + break; + } + break; + case 'H': + case 'q': + Ivalue = bit_extract (buffer, ioffset-4, 4); + Ivalue = sign_extend (Ivalue, 4); + sprintf (result, "%d", Ivalue); + ioffset -= 4; + break; + case 'r': + Ivalue = bit_extract (buffer, ioffset-3, 3); + sprintf (result, "r%d", Ivalue&7); + ioffset -= 3; + break; + case 'd': + sprintf (result, "%d", get_displacement (buffer, aoffsetp)); + break; + case 'b': + Ivalue = get_displacement (buffer, aoffsetp); + /* + * Warning!! HACK ALERT! + * Operand type 'b' is only used by the cmp{b,w,d} and + * movm{b,w,d} instructions; we need to know whether + * it's a `b' or `w' or `d' instruction; and for both + * cmpm and movm it's stored at the same place so we + * just grab two bits of the opcode and look at it... + * + */ + size = bit_extract(buffer, ioffset-6, 2); + if (size == 0) /* 00 => b */ + size = 1; + else if (size == 1) /* 01 => w */ + size = 2; + else + size = 4; /* 11 => d */ + + sprintf (result, "%d", (Ivalue / size) + 1); + break; + case 'p': + *result++ = NEXT_IS_ADDR; + sprintf_vma (result, addr + get_displacement (buffer, aoffsetp)); + result += strlen (result); + *result++ = NEXT_IS_ADDR; + *result = '\0'; + break; + case 'i': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + *aoffsetp += 8; + sprintf (result, "0x%x", Ivalue); + break; + case 'u': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + optlist(Ivalue, opt_u, result); + *aoffsetp += 8; + break; + case 'U': + Ivalue = bit_extract(buffer, *aoffsetp, 8); + optlist(Ivalue, opt_U, result); + *aoffsetp += 8; + break; + case 'O': + Ivalue = bit_extract(buffer, ioffset-9, 9); + optlist(Ivalue, opt_O, result); + ioffset -= 9; + break; + case 'C': + Ivalue = bit_extract(buffer, ioffset-4, 4); + optlist(Ivalue, opt_C, result); + ioffset -= 4; + break; + case 'S': + Ivalue = bit_extract(buffer, ioffset - 8, 8); + optlist(Ivalue, opt_S, result); + ioffset -= 8; + break; + case 'M': + Ivalue = bit_extract(buffer, ioffset-4, 4); + list_search(Ivalue, 0 ? list_M032 : list_M532, result); + ioffset -= 4; + break; + case 'P': + Ivalue = bit_extract(buffer, ioffset-4, 4); + list_search(Ivalue, 0 ? list_P032 : list_P532, result); + ioffset -= 4; + break; + case 'g': + Ivalue = bit_extract(buffer, *aoffsetp, 3); + sprintf(result, "%d", Ivalue); + *aoffsetp += 3; + break; + case 'G': + Ivalue = bit_extract(buffer, *aoffsetp, 5); + sprintf(result, "%d", Ivalue + 1); + *aoffsetp += 5; + break; + } + return ioffset; +} + +static int +get_displacement (buffer, aoffsetp) + char *buffer; + int *aoffsetp; +{ + int Ivalue; + short Ivalue2; + + Ivalue = bit_extract (buffer, *aoffsetp, 8); + switch (Ivalue & 0xc0) + { + case 0x00: + case 0x40: + Ivalue = sign_extend (Ivalue, 7); + *aoffsetp += 8; + break; + case 0x80: + Ivalue2 = bit_extract (buffer, *aoffsetp, 16); + flip_bytes (&Ivalue2, 2); + Ivalue = sign_extend (Ivalue2, 14); + *aoffsetp += 16; + break; + case 0xc0: + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + Ivalue = sign_extend (Ivalue, 30); + *aoffsetp += 32; + break; + } + return Ivalue; +} + + +#if 1 /* a version that should work on ns32k f's&d's on any machine */ +static int +invalid_float (p, len) + register char *p; + register int len; +{ + register int val; + + if ( len == 4 ) + val = (bit_extract_simple(p, 23, 8)/*exponent*/ == 0xff + || (bit_extract_simple(p, 23, 8)/*exponent*/ == 0 && + bit_extract_simple(p, 0, 23)/*mantisa*/ != 0)); + else if ( len == 8 ) + val = (bit_extract_simple(p, 52, 11)/*exponent*/ == 0x7ff + || (bit_extract_simple(p, 52, 11)/*exponent*/ == 0 + && (bit_extract_simple(p, 0, 32)/*low mantisa*/ != 0 + || bit_extract_simple(p, 32, 20)/*high mantisa*/ != 0))); + else + val = 1; + return (val); +} +#else + +/* assumes the bytes have been swapped to local order */ +typedef union { double d; + float f; + struct { unsigned m:23, e:8, :1;} sf; + struct { unsigned lm; unsigned m:20, e:11, :1;} sd; + } float_type_u; + +static int +invalid_float (p, len) + register float_type_u *p; + register int len; +{ + register int val; + if ( len == sizeof (float) ) + val = (p->sf.e == 0xff + || (p->sf.e == 0 && p->sf.m != 0)); + else if ( len == sizeof (double) ) + val = (p->sd.e == 0x7ff + || (p->sd.e == 0 && (p->sd.m != 0 || p->sd.lm != 0))); + else + val = 1; + return (val); +} +#endif |