/*
Written By Steve Chamberlain
-
- steve@cygnus.com
+ sac@cygnus.com
*/
#include <stdio.h>
#include "as.h"
#include "bfd.h"
-#include "h8300-opcode.h"
+#include "opcode/h8300.h"
#include <ctype.h>
+#include "listing.h"
char comment_chars[] = { ';',0 };
char line_separator_chars[] = { '$' ,0};
/* This table describes all the machine specific pseudo-ops the assembler
has to support. The fields are:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function
*/
void cons();
+
const pseudo_typeS md_pseudo_table[] = {
{ "int", cons, 2 },
- { 0, 0, 0 }
+ { 0,0,0 }
};
int md_reloc_size ;
static struct hash_control *opcode_hash_control; /* Opcode mnemonics */
-static struct hash_control *register_hash_control; /* Register name hash table */
/*
set up all the tables, etc that the MD part of the assembler needs
*/
-reloc_howto_type *r16;
-reloc_howto_type *r8;
-reloc_howto_type *r8ff;
-reloc_howto_type *r8pcrel;
+/* encode the size and number into the number field
+ xxnnnn
+ 00 8 bit
+ 01 16 bit
+ 10 ccr
+ nnnnreg number
+*/
+#define WORD_REG 0x10
+#define BYTE_REG 0x00
+#define CCR_REG 0x20
+ struct reg_entry
+{
+ char *name;
+ char number;
+};
+
+struct reg_entry reg_list[] = {
+"r0",WORD_REG +0,
+"r1",WORD_REG +1,
+"r2",WORD_REG +2,
+"r3",WORD_REG +3,
+"r4",WORD_REG +4,
+"r5",WORD_REG +5,
+"r6",WORD_REG +6,
+"r7",WORD_REG +7,
+"fp",WORD_REG +6,
+"sp",WORD_REG +7,
+"r0h",BYTE_REG + 0,
+"r0l",BYTE_REG + 1,
+"r1h",BYTE_REG + 2,
+"r1l",BYTE_REG + 3,
+"r2h",BYTE_REG + 4,
+"r2l",BYTE_REG + 5,
+"r3h",BYTE_REG + 6,
+"r3l",BYTE_REG + 7,
+"r4h",BYTE_REG + 8,
+"r4l",BYTE_REG + 9,
+"r5h",BYTE_REG + 10,
+"r5l",BYTE_REG + 11,
+"r6h",BYTE_REG + 12,
+"r6l",BYTE_REG + 13,
+"r7h",BYTE_REG + 14,
+"r7l",BYTE_REG + 15,
+"ccr",CCR_REG,
+0,0
+}
+;
+
+
+
+
void md_begin ()
{
- bfd_arch_info_type *ai;
- const struct h8_opcode *opcode;
-
+ struct h8_opcode *opcode;
+ const struct reg_entry *reg;
+ char prev_buffer[100];
+ int idx = 0;
+
opcode_hash_control = hash_new();
- for (opcode = h8_opcodes; opcode->name; opcode++) {
- hash_insert(opcode_hash_control, opcode->name, (char *)opcode);
- }
-
- ai = bfd_lookup_arch(bfd_arch_h8300,0);
+ prev_buffer[0] = 0;
- r16 = ai->reloc_type_lookup(ai, BFD_RELOC_16);
- r8 = ai->reloc_type_lookup(ai, BFD_RELOC_8);
- r8ff = ai->reloc_type_lookup(ai, BFD_RELOC_8_FFnn);
- r8pcrel = ai->reloc_type_lookup(ai, BFD_RELOC_8_PCREL);
+ for (opcode = h8_opcodes; opcode->name; opcode++)
+ {
+ /* Strip off any . part when inserting the opcode and only enter
+ unique codes into the hash table
+ */
+ char *src= opcode->name;
+ unsigned int len = strlen(src);
+ char *dst = malloc(len+1);
+ char *buffer = dst;
+ opcode->size = 0;
+ while (*src) {
+ if (*src == '.') {
+ *dst++ = 0;
+ src++;
+ opcode->size = *src;
+ break;
+ }
+ *dst++ = *src++;
+ }
+ if (strcmp(buffer, prev_buffer))
+ {
+ hash_insert(opcode_hash_control, buffer, (char *)opcode);
+ strcpy(prev_buffer, buffer);
+ idx++;
+ }
+ opcode->idx = idx;
+
+
+ /* Find the number of operands */
+ opcode->noperands = 0;
+ while (opcode->args.nib[opcode->noperands] != E)
+ opcode->noperands ++;
+ /* Find the length of the opcode in bytes */
+ opcode->length =0;
+ while (opcode->data.nib[opcode->length*2] != E)
+ opcode->length++;
+ }
-
}
};
struct h8_op
{
-op_type mode;
- unsigned reg;
- expressionS exp;
+ unsigned int dispreg;
+ op_type mode;
+ unsigned reg;
+ expressionS exp;
};
op_type rind_sord[] = {RSIND, RDIND};
op_type abs_sord[2] = {ABS16SRC, ABS16DST};
op_type disp_sord[] = {DISPSRC, DISPDST};
+
/* try and parse a reg name, returns number of chars consumed */
-int DEFUN(parse_reg,(src, mode, reg, dst),
- char *src AND
- op_type *mode AND
- unsigned int *reg AND
- int dst)
+int
+DEFUN(parse_reg,(src, mode, reg, dst),
+ char *src AND
+ op_type *mode AND
+ unsigned int *reg AND
+ int dst)
{
- if (src[0] == 's' && src[1] == 'p') {
- *mode = r16_sord[dst];
- *reg = 7;
- return 2;
- }
- if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') {
- *mode = CCR;
- *reg = 0;
- return 3;
- }
- if (src[0] == 'f' && src[1] == 'p') {
- *mode = r16_sord[dst];
- *reg = 6;
- return 2;
- }
- if (src[0] == 'r') {
- if (src[1] >= '0' && src[1] <= '7') {
- if(src[2] == 'l') {
- *mode = r8_sord[dst];
- *reg = (src[1] - '0') + 8;
- return 3;
- }
- if(src[2] == 'h') {
- *mode = r8_sord[dst];
- *reg = (src[1] - '0') ;
+ if (src[0] == 's' && src[1] == 'p')
+ {
+ *mode = r16_sord[dst];
+ *reg = 7;
+ return 2;
+ }
+ if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r')
+ {
+ *mode = CCR;
+ *reg = 0;
return 3;
- }
- *mode = r16_sord[dst];
- *reg = (src[1] - '0');
- return 2;
}
- }
- return 0;
+ if (src[0] == 'f' && src[1] == 'p')
+ {
+ *mode = r16_sord[dst];
+ *reg = 6;
+ return 2;
+ }
+ if (src[0] == 'r')
+ {
+ if (src[1] >= '0' && src[1] <= '7')
+ {
+ if(src[2] == 'l')
+ {
+ *mode = r8_sord[dst];
+ *reg = (src[1] - '0') + 8;
+ return 3;
+ }
+ if(src[2] == 'h')
+ {
+ *mode = r8_sord[dst];
+ *reg = (src[1] - '0') ;
+ return 3;
+ }
+ *mode = r16_sord[dst];
+ *reg = (src[1] - '0');
+ return 2;
+ }
+ }
+ return 0;
}
char *
new = input_line_pointer;
input_line_pointer = save;
if (SEG_NORMAL(seg))
- return new;
+ return new;
switch (seg) {
- case SEG_ABSOLUTE:
- case SEG_UNKNOWN:
- case SEG_DIFFERENCE:
- case SEG_BIG:
- case SEG_REGISTER:
- return new;
- case SEG_ABSENT:
- as_bad("Missing operand");
- return new;
- default:
- as_bad("Don't understand operand of type %s", segment_name (seg));
- return new;
- }
+ case SEG_ABSOLUTE:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ case SEG_BIG:
+ case SEG_REGISTER:
+ return new;
+ case SEG_ABSENT:
+ as_bad("Missing operand");
+ return new;
+ default:
+ as_bad("Don't understand operand of type %s", segment_name (seg));
+ return new;
+ }
+}
+
+static char *
+DEFUN(skip_colonthing,(ptr),
+ char *ptr)
+{
+ if (*ptr == ':') {
+ ptr++;
+ while (isdigit(*ptr))
+ ptr++;
+
+ }
+ return ptr;
}
+/* The many forms of operand:
+
+ Rn Register direct
+ @Rn Register indirect
+ @(exp[:16], Rn) Register indirect with displacement
+ @Rn+
+ @-Rn
+ @aa:8 absolute 8 bit
+ @aa:16 absolute 16 bit
+ @aa absolute 16 bit
+
+ #xx[:size] immediate data
+ @(exp:[8], pc) pc rel
+ @@aa[:8] memory indirect
+
+*/
static void
DEFUN(get_operand,(ptr, op, dst),
op_type mode;
unsigned int num;
unsigned int len;
+ unsigned int size;
op->mode = E;
- while (*src == ' ') src++;
len = parse_reg(src, &op->mode, &op->reg, dst);
if (len) {
- *ptr = src + len;
- return ;
- }
+ *ptr = src + len;
+ return ;
+ }
- if (*src == '@') {
+ if (*src == '@')
+ {
src++;
- if (*src == '-') {
+ if (*src == '@')
+ {
+ src++;
+ src = parse_exp(src,&op->exp);
+ src = skip_colonthing(src);
+
+ *ptr = src;
+
+ op->mode = MEMIND;
+ return;
+
+ }
+
+
+ if (*src == '-')
+ {
src++;
len = parse_reg(src, &mode, &num, dst);
- if (len == 0 || mode != r16_sord[dst]) {
+ if (len == 0 || mode != r16_sord[dst])
+ {
as_bad("@- needs word register");
}
op->mode = RDDEC;
*ptr = src + len;
return;
}
- if (*src == '(' && ')') {
+ if (*src == '(' && ')')
+ {
/* Disp */
src++;
src = parse_exp(src, &op->exp);
- if (*src == ')') {
+ if (*src == ')')
+ {
src++;
op->mode = abs_sord[dst];
*ptr = src;
return;
}
- if (*src != ',') {
+ src = skip_colonthing(src);
+
+ if (*src != ',')
+ {
as_bad("expected @(exp, reg16)");
}
src++;
len = parse_reg(src, &mode, &op->reg, dst);
if (len == 0 || mode != r16_sord[dst])
- {
- as_bad("expected @(exp, reg16)");
- }
+ {
+ as_bad("expected @(exp, reg16)");
+ }
op->mode = disp_sord[dst];
src += len;
- if (*src != ')' && '(') {
+ src = skip_colonthing(src);
+
+ if (*src != ')' && '(')
+ {
as_bad("expected @(exp, reg16)");
}
len = parse_reg(src, &mode, &num, dst);
if(len) {
- src += len;
- if (*src == '+') {
- src++;
- if (mode != RS16) {
- as_bad("@Rn+ needs word register");
+ src += len;
+ if (*src == '+')
+ {
+ src++;
+ if (mode != RS16)
+ {
+ as_bad("@Rn+ needs src word register");
+ }
+ op->mode = RSINC;
+ op->reg = num;
+ *ptr = src;
+ return;
+ }
+ if (mode != r16_sord[dst])
+ {
+ as_bad("@Rn needs word register");
}
- op->mode = RSINC;
+ op->mode =rind_sord[dst];
op->reg = num;
*ptr = src;
return;
}
- if (mode != r16_sord[dst]) {
- as_bad("@Rn needs word register");
- }
- op->mode =rind_sord[dst];
- op->reg = num;
- *ptr = src;
- return;
- }
- else {
+ else
+ {
/* must be a symbol */
op->mode = abs_sord[dst];
- *ptr = parse_exp(src, &op->exp);
+ *ptr = skip_colonthing(parse_exp(src, &op->exp));
+
return;
}
}
if (*src == '#') {
- src++;
- op->mode = IMM16;
- *ptr = parse_exp(src, &op->exp);
- return;
- }
+ src++;
+ op->mode = IMM16;
+ src = parse_exp(src, &op->exp);
+ *ptr= skip_colonthing(src);
+
+ return;
+ }
else {
- *ptr = parse_exp(src, &op->exp);
- op->mode = DISP8;
+ *ptr = parse_exp(src, &op->exp);
+ op->mode = DISP8;
+ }
+}
+
+
+static
+char *
+DEFUN(get_operands,(noperands,op_end, operand),
+ unsigned int noperands AND
+ char *op_end AND
+ struct h8_op *operand)
+{
+ char *ptr = op_end;
+ switch (noperands)
+ {
+ case 0:
+ operand[0].mode = 0;
+ operand[1].mode = 0;
+ break;
+
+ case 1:
+ ptr++;
+ get_operand(& ptr, operand +0,0);
+ operand[1].mode =0;
+ break;
+
+ case 2:
+ ptr++;
+ get_operand(& ptr, operand +0,0);
+ if (*ptr == ',') ptr++;
+ get_operand(& ptr, operand +1, 1);
+ break;
+
+ default:
+ abort();
}
+
+
+ return ptr;
}
+/* Passed a pointer to a list of opcodes which use different
+ addressing modes, return the opcode which matches the opcodes
+ provided
+ */
+static
+struct h8_opcode *
+DEFUN(get_specific,(opcode, operands),
+ struct h8_opcode *opcode AND
+ struct h8_op *operands)
+
+{
+ struct h8_opcode *this_try = opcode ;
+ int found = 0;
+ unsigned int noperands = opcode->noperands;
+
+ unsigned int dispreg;
+ unsigned int this_index = opcode->idx;
+ while (this_index == opcode->idx && !found)
+ {
+ unsigned int i;
+
+ this_try = opcode ++;
+ for (i = 0; i < noperands; i++)
+ {
+ op_type op = (this_try->args.nib[i]) & ~(B30|B31);
+ switch (op)
+ {
+ case Hex0:
+ case Hex1:
+ case Hex2:
+ case Hex3:
+ case Hex4:
+ case Hex5:
+ case Hex6:
+ case Hex7:
+ case Hex8:
+ case Hex9:
+ case HexA:
+ case HexB:
+ case HexC:
+ case HexD:
+ case HexE:
+ case HexF:
+ break;
+ case DISPSRC:
+ case DISPDST:
+ operands[0].dispreg = operands[i].reg;
+ case RD8:
+ case RS8:
+ case RDIND:
+ case RSIND:
+ case RD16:
+ case RS16:
+ case CCR:
+ case RSINC:
+ case RDDEC:
+ if (operands[i].mode != op) goto fail;
+ break;
+ case KBIT:
+ case IMM16:
+ case IMM3:
+ case IMM8:
+ if (operands[i].mode != IMM16) goto fail;
+ break;
+ case MEMIND:
+ if (operands[i].mode != MEMIND) goto fail;
+ break;
+ case ABS16SRC:
+ case ABS8SRC:
+ case ABS16OR8SRC:
+ case ABS16ORREL8SRC:
+
+ if (operands[i].mode != ABS16SRC) goto fail;
+ break;
+ case ABS16OR8DST:
+ case ABS16DST:
+ case ABS8DST:
+ if (operands[i].mode != ABS16DST) goto fail;
+ break;
+ }
+ }
+ found =1;
+ fail: ;
+ }
+ if (found)
+ return this_try;
+ else
+ return 0;
+}
+
+static void
+DEFUN(check_operand,(operand, width, string),
+ struct h8_op *operand AND
+ unsigned int width AND
+ char *string)
+{
+ if (operand->exp.X_add_symbol == 0
+ && operand->exp.X_subtract_symbol == 0)
+ {
+
+ /* No symbol involved, let's look at offset, it's dangerous if any of
+ the high bits are not 0 or ff's, find out by oring or anding with
+ the width and seeing if the answer is 0 or all fs*/
+ if ((operand->exp.X_add_number | width) != ~0 &&
+ (operand->exp.X_add_number & ~width)!= 0)
+ {
+ as_warn("operand %s0x%x out of range.", string, operand->exp.X_add_number);
+ }
+ }
+
+}
+
+/* Now we know what sort of opcodes it is, lets build the bytes -
+ */
+static void
+DEFUN (build_bytes,(this_try, operand),
+ struct h8_opcode *this_try AND
+ struct h8_op *operand)
+
+{
+ unsigned int i;
+
+ char *output = frag_more(this_try->length);
+ char *output_ptr = output;
+ op_type *nibble_ptr = this_try->data.nib;
+ char part;
+ op_type c;
+ char high;
+ int nib;
+ top: ;
+ while (*nibble_ptr != E)
+ {
+ int nibble;
+ for (nibble = 0; nibble <2; nibble++)
+ {
+ c = *nibble_ptr & ~(B30|B31);
+ switch (c)
+ {
+ default:
+ abort();
+ case KBIT:
+ switch (operand[0].exp.X_add_number)
+ {
+ case 1:
+ nib = 0;
+ break;
+ case 2:
+ nib = 8;
+ break;
+ default:
+ as_bad("Need #1 or #2 here");
+ break;
+ }
+ /* stop it making a fix */
+ operand[0].mode = 0;
+ break;
+ case 0:
+ case 1:
+ case 2: case 3: case 4: case 5: case 6:
+ case 7: case 8: case 9: case 10: case 11:
+ case 12: case 13: case 14: case 15:
+ nib = c;
+ break;
+ case DISPREG:
+ nib = operand[0].dispreg;
+ break;
+ case IMM8:
+ operand[0].mode = IMM8;
+ nib = 0;
+ break;
+
+ case DISPDST:
+ nib = 0;
+ break;
+ case IMM3:
+ if (operand[0].exp.X_add_symbol == 0) {
+ operand[0].mode = 0; /* stop it making a fix */
+ nib = (operand[0].exp.X_add_number);
+ }
+ else as_bad("can't have symbol for bit number");
+ if (nib < 0 || nib > 7)
+ {
+ as_bad("Bit number out of range %d", nib);
+ }
+
+ break;
+
+ case ABS16DST:
+ nib = 0;
+ break;
+ case ABS8DST:
+ operand[1].mode = ABS8DST;
+ nib = 0;
+ break;
+ case ABS8SRC:
+ operand[0].mode = ABS8SRC;
+ nib = 0;
+ break;
+ case ABS16OR8DST:
+ operand[1].mode = c;
+
+ nib = 0;
+
+ break;
+
+ case ABS16ORREL8SRC:
+ operand[0].mode = c;
+ nib=0;
+ break;
+
+ case ABS16OR8SRC:
+ operand[0].mode = ABS16OR8SRC;
+ nib = 0;
+ break;
+ case DISPSRC:
+ operand[0].mode = ABS16SRC;
+ nib = 0;
+ break;
+
+ case DISP8:
+ operand[0].mode = DISP8;
+ nib = 0;
+ break;
+
+ case ABS16SRC:
+ case IMM16:
+ case IGNORE:
+ case MEMIND:
+
+ nib=0;
+ break;
+ case RS8:
+ case RS16:
+ case RSIND:
+ case RSINC:
+ nib = operand[0].reg;
+ break;
+
+ case RD8:
+ case RD16:
+ case RDDEC:
+ case RDIND:
+ nib = operand[1].reg;
+ break;
+
+ case E:
+ abort();
+ break;
+ }
+ if (*nibble_ptr & B31) {
+ nib |=0x8;
+ }
+
+ if (nibble == 0) {
+ *output_ptr = nib << 4;
+ }
+ else {
+ *output_ptr |= nib;
+ output_ptr++;
+ }
+ nibble_ptr++;
+ }
+
+ }
+
+ /* output any fixes */
+ for (i = 0; i < 2; i++)
+ {
+ switch (operand[i].mode) {
+ case 0:
+ break;
+
+ case DISP8:
+ check_operand(operand+i, 0x7f,"@");
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number -1,
+ 1,
+ R_PCRBYTE);
+ break;
+ case IMM8:
+ check_operand(operand+i, 0xff,"#");
+ /* If there is nothing else going on we can safely
+ reloc in place */
+ if (operand[i].exp.X_add_symbol == 0)
+ {
+ output[1] = operand[i].exp.X_add_number;
+ }
+ else
+ {
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELBYTE);
+ }
+
+ break;
+ case MEMIND:
+ check_operand(operand+i, 0xff,"@@");
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELBYTE);
+ break;
+ case ABS8DST:
+ case ABS8SRC:
+ check_operand(operand+i, 0xff,"@");
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 1,
+ 1,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELBYTE);
+ break;
+
+ case ABS16OR8SRC:
+ case ABS16OR8DST:
+ check_operand(operand+i, 0xffff,"@");
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 2,
+ 2,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_MOVB1);
+ break;
+
+ case ABS16ORREL8SRC:
+ check_operand(operand+i, 0xffff,"@");
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 2,
+ 2,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_JMP1);
+ break;
+
+
+ case ABS16SRC:
+ case ABS16DST:
+ case IMM16:
+ case DISPSRC:
+ case DISPDST:
+ check_operand(operand+i, 0xffff,"@");
+ if (operand[i].exp.X_add_symbol == 0)
+ {
+ /* This should be done with bfd */
+ output[3] = operand[i].exp.X_add_number & 0xff;
+ output[2] = operand[i].exp.X_add_number >> 8;
+
+ }
+ else
+ {
+
+ fix_new(frag_now,
+ output - frag_now->fr_literal + 2,
+ 2,
+ operand[i].exp.X_add_symbol,
+ operand[i].exp.X_subtract_symbol,
+ operand[i].exp.X_add_number,
+ 0,
+ R_RELWORD);
+ }
+
+ break;
+ case RS8:
+ case RD8:
+ case RS16:
+ case RD16:
+ case RDDEC:
+ case KBIT:
+ case RSINC:
+ case RDIND:
+ case RSIND:
+ case CCR:
+
+ break;
+ default:
+ abort();
+ }
+ }
+
+}
/* This is the guts of the machine-dependent assembler. STR points to a
machine dependent instruction. This funciton is supposed to emit
the frags/bytes it assembles to.
char *op_start;
char *op_end;
unsigned int i;
-
+ struct h8_op operand[2];
struct h8_opcode * opcode;
+ char *dot = 0;
+ char c;
/* Drop leading whitespace */
while (*str == ' ')
str++;
-
/* find the op code end */
for (op_start = op_end = str;
*op_end != 0 && *op_end != ' ';
- op_end ++)
- ;
+ op_end ++)
+ {
+ if (*op_end == '.') {
+ dot = op_end+1;
+ *op_end = 0;
+ op_end+=2;
+ break;
+ }
+ }
+
+ ;
- if (op_end == op_start) {
- as_bad("can't find opcode ");
- }
+ if (op_end == op_start)
+ {
+ as_bad("can't find opcode ");
+ }
+ c = *op_end;
+
*op_end = 0;
+
opcode = (struct h8_opcode *) hash_find(opcode_hash_control,
op_start);
- if (opcode == NULL) {
- as_bad("unknown opcode");
- return;
- }
-
-
-{
- int ok = 1;
- int j,i;
- int dispreg = 0;
- struct h8_op operand[2];
- char *ptr = op_end+1;
- if (opcode->noperands)
- get_operand(& ptr, &operand[0],0);
- else operand[0].mode = 0;
- if (opcode->noperands==2) {
- if (*ptr == ',') ptr++;
- get_operand(& ptr, &operand[1], 1);
- }
- else operand[1].mode = 0;
-
-
+ if (opcode == NULL)
+ {
+ as_bad("unknown opcode");
+ return;
+ }
-{
- struct h8_opcode *this_try ;
- int found = 0;
- for (j = 0; j < opcode->nopcodes && !found; j++) {
- this_try = opcode + j;
- for (i = 0; i < opcode->noperands; i++) {
- op_type op = (this_try->args.nib[i]) & ~(B30|B31);
- switch (op) {
- case Hex0:
- case Hex1:
- case Hex2:
- case Hex3:
- case Hex4:
- case Hex5:
- case Hex6:
- case Hex7:
- case Hex8:
- case Hex9:
- case HexA:
- case HexB:
- case HexC:
- case HexD:
- case HexE:
- case HexF:
- break;
- case DISPSRC:
- case DISPDST:
- dispreg = operand[i].reg;
- case RD8:
- case RS8:
- case RDIND:
- case RSIND:
- case RD16:
- case RS16:
- case CCR:
- case RSINC:
- case RDDEC:
- if (operand[i].mode != op) goto fail;
- break;
- case IMM8:
- /* We have an expression, called IMM16, but we know we
- want an 8 bit value here */
- if (operand[i].mode != IMM16) goto fail;
- operand[i].mode = IMM8;
- break;
- case KBIT:
- case IMM16:
- case IMM3:
- if (operand[i].mode != IMM16) goto fail;
- break;
- case ABS16SRC:
- case ABS8SRC:
- if (operand[i].mode != ABS16SRC) goto fail;
- break;
- case ABS16DST:
- case ABS8DST:
- if (operand[i].mode != ABS16DST) goto fail;
-
- break;
- }
- }
- found =1;
- fail: ;
+
+ input_line_pointer = get_operands(opcode->noperands, op_end,
+ operand);
+ *op_end = c;
+ opcode = get_specific(opcode, operand);
+
+ if (opcode == 0)
+ {
+ /* Allocate 2 bytes for the insn anyway */
+ char *where =frag_more(2);
+ where[0] = 0xde;
+ where[1] = 0xad;
+
+
+ as_bad("illegal operands for opcode");
+ return;
+ }
+ if (opcode->size && dot)
+ {
+ if (opcode->size != *dot)
+ {
+ as_warn("mismatch between opcode size and operand size");
}
- if (found == 0)
- as_bad("illegal operands for opcode");
-
-
- /* Now we know what sort of opcodes etc, lets build the bytes -
- actually we know how big the instruction will be too. So we
- can get
- */
-{
- char *output = frag_more(this_try->length);
- char *output_ptr = output;
- op_type *nibble_ptr = this_try->data.nib;
- char part;
- op_type c;
- char high;
- int nib;
- top: ;
- while (*nibble_ptr != E) {
- int nibble;
- for (nibble = 0; nibble <2; nibble++) {
- c = *nibble_ptr & ~(B30|B31);
- switch (c) {
- default:
- abort();
- case KBIT:
- switch (operand[0].exp.X_add_number) {
- case 1:
- nib = 0;
- break;
- case 2:
- nib = 8;
- break;
- default:
- as_bad("Need #1 or #2 here");
- break;
- }
- /* stop it making a fix */
- operand[0].mode = 0;
- break;
- case 0:
- case 1:
- case 2: case 3: case 4: case 5: case 6:
- case 7: case 8: case 9: case 10: case 11:
- case 12: case 13: case 14: case 15:
- nib = c;
- break;
- case DISPREG:
- nib = dispreg;
- break;
- case IMM8:
- nib = 0;
- break;
-
- case DISPDST:
- nib = 0;
- break;
- case IMM3:
- if (operand[0].exp.X_add_symbol == 0) {
- operand[0].mode = 0; /* stop it making a fix */
- nib = (operand[0].exp.X_add_number);
- }
- else as_bad("can't have symbol for bit number");
- break;
-
- case ABS16DST:
- nib = 0;
- break;
- case DISPSRC:
- case ABS16SRC:
- case IMM16:
- nib=0;
- break;
-
-
- case ABS8DST:
- case ABS8SRC:
- case IGNORE:
-
-
- nib = 0;
- break;
- case DISP8:
- nib = 0;
- break;
-
-
- case RS8:
- case RS16:
- case RSIND:
- case RSINC:
-
- nib= operand[0].reg;
- break;
- case RD8:
- case RD16:
- case RDDEC:
- case RDIND:
- nib = operand[1].reg;
-
- break;
- case E:
- abort();
- break;
- }
- if (*nibble_ptr & B31) nib|=0x8;
- if (nibble == 0) {
- *output_ptr = nib << 4;
- }
- else {
- *output_ptr |= nib;
- output_ptr++;
- }
- nibble_ptr++;
- }
-
- }
-
- /* output any fixes */
- for (i = 0; i < 2; i++)
- {
- switch (operand[i].mode) {
- case 0:
- break;
- case DISP8:
- fix_new(frag_now,
- output - frag_now->fr_literal + 1,
- 1,
- operand[i].exp.X_add_symbol,
- operand[i].exp.X_subtract_symbol,
- operand[i].exp.X_add_number -1,
- 1,
- (int)r8pcrel);
- break;
- case IMM8:
- fix_new(frag_now,
- output - frag_now->fr_literal + 1,
- 1,
- operand[i].exp.X_add_symbol,
- operand[i].exp.X_subtract_symbol,
- operand[i].exp.X_add_number,
- 0,
- 0);
- break;
-
- case ABS16SRC:
- case ABS16DST:
- case IMM16:
- case DISPSRC:
- case DISPDST:
- fix_new(frag_now,
- output - frag_now->fr_literal + 2,
- 2,
- operand[i].exp.X_add_symbol,
- operand[i].exp.X_subtract_symbol,
- operand[i].exp.X_add_number,
- 0,
- (int)r16);
- break;
- case RS8:
- case RD8:
- case RS16:
- case RD16:
- case RDDEC:
- case KBIT:
- case RSINC:
- case RDIND:
- case RSIND:
- break;
- default:
- abort();
- }
- }
+ }
+ build_bytes(opcode, operand);
-}
-}
-}
}
void
int *cntP;
char ***vecP;
- {abort();
+ {
+ return 0;
+
}
int md_short_jump_size;
md_estimate_size_before_relax(fragP, segment_type)
register fragS *fragP;
register segT segment_type;
-{ printf("call tomd_estimate_size_before_relax \n"); abort(); }
+{
+printf("call tomd_estimate_size_before_relax \n"); abort(); }
/* Put number into target byte order */
void DEFUN(md_number_to_chars,(ptr, use, nbytes),
fixS *fixP; { abort(); }
void tc_coff_symbol_emit_hook() { }
+
+
+void tc_reloc_mangle(fix_ptr, intr, base)
+fixS *fix_ptr;
+struct internal_reloc *intr;
+bfd_vma base;
+
+{
+ symbolS *symbol_ptr;
+
+ symbol_ptr = fix_ptr->fx_addsy;
+
+ /* If this relocation is attached to a symbol then it's ok
+ to output it */
+ if (fix_ptr->fx_r_type == RELOC_32) {
+ /* cons likes to create reloc32's whatever the size of the reloc..
+ */
+ switch (fix_ptr->fx_size)
+ {
+
+ case 2:
+ intr->r_type = R_RELWORD;
+ break;
+ case 1:
+ intr->r_type = R_RELBYTE;
+ break;
+ default:
+ abort();
+
+ }
+
+ }
+ else {
+ intr->r_type = fix_ptr->fx_r_type;
+ }
+
+ intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where +base;
+ intr->r_offset = fix_ptr->fx_offset;
+
+ if (symbol_ptr)
+ intr->r_symndx = symbol_ptr->sy_number;
+ else
+ intr->r_symndx = -1;
+
+
+}
--- /dev/null
+/* listing.c - mainting assembly listings
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS 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, or (at your option)
+any later version.
+
+GAS 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 GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ Contributed by Steve Chamberlain
+ sac@cygnus.com
+
+
+ A listing page looks like:
+
+ LISTING_HEADER sourcefilename pagenumber
+ TITLE LINE
+ SUBTITLE LINE
+ linenumber address data source
+ linenumber address data source
+ linenumber address data source
+ linenumber address data source
+
+ If not overridden, the listing commands are:
+
+ .title "stuff"
+ Put "stuff" onto the title line
+ .sbttl "stuff"
+ Put stuff onto the subtitle line
+
+ If these commands come within 10 lines of the top of the page, they
+ will affect the page they are on, as well as any subsequent page
+
+ .eject
+ Thow a page
+ .list
+ Increment the enable listing counter
+ .nolist
+ Decrement the enable listing counter
+
+ .psize Y[,X]
+ Set the paper size to X wide and Y high. Setting a psize Y of
+ zero will suppress form feeds except where demanded by .eject
+
+ If the counter goes below zero, listing is suppressed.
+
+
+ Listings are a maintained by read calling various listing_<foo>
+ functions. What happens most is that the macro NO_LISTING is not
+ defined (from the Makefile), then the macro LISTING_NEWLINE expands
+ into a call to listing_newline. The call is done from read.c, every
+ time it sees a newline, and -l is on the command line.
+
+ The function listing_newline remembers the frag associated with the
+ newline, and creates a new frag - note that this is wasteful, but not
+ a big deal, since listing slows things down a lot anyway. The
+ function also rememebers when the filename changes.
+
+ When all the input has finished, and gas has had a chance to settle
+ down, the listing is output. This is done by running down the list of
+ frag/source file records, and opening the files as needed and printing
+ out the bytes and chars associated with them.
+
+ The only things which the architecture can change about the listing
+ are defined in these macros:
+
+ LISTING_HEADER The name of the architecture
+ LISTING_WORD_SIZE The make of the number of bytes in a word, this determines
+ the clumping of the output data. eg a value of
+ 2 makes words look like 1234 5678, whilst 1
+ would make the same value look like 12 34 56
+ 78
+ LISTING_LHS_WIDTH Number of words of above size for the lhs
+
+ LISTING_LHS_WIDTH_SECOND Number of words for the data on the lhs
+ for the second line
+
+ LISTING_LHS_CONT_LINES Max number of lines to use up for a continutation
+ LISTING_RHS_WIDTH Number of chars from the input file to print
+ on a line
+*/
+
+#include "as.h"
+#include <obstack.h>
+#include "input-file.h"
+#include "targ-cpu.h"
+
+#ifndef NO_LISTING
+#ifndef LISTING_HEADER
+#define LISTING_HEADER "GAS LISTING"
+#endif
+#ifndef LISTING_WORD_SIZE
+#define LISTING_WORD_SIZE 4
+#endif
+#ifndef LISTING_LHS_WIDTH
+#define LISTING_LHS_WIDTH 1
+#endif
+#ifndef LISTING_LHS_WIDTH_SECOND
+#define LISTING_LHS_WIDTH_SECOND 1
+#endif
+#ifndef LISTING_RHS_WIDTH
+#define LISTING_RHS_WIDTH 100
+#endif
+#ifndef LISTING_LHS_CONT_LINES
+#define LISTING_LHS_CONT_LINES 4
+#endif
+
+
+
+
+/* This structure remembers which files were used */
+typedef struct file_info_struct
+{
+ char *filename;
+ int linenum;
+ FILE *file;
+ struct file_info_struct *next;
+} file_info_type ;
+
+
+/* this structure rememebrs which line from which file goes into which
+ frag */
+typedef struct list_info_struct
+{
+ /* Frag which this line of source is nearest to */
+ fragS *frag;
+ /* The actual line in the source file */
+ unsigned int line;
+ /* Pointer to the file info struct for the file which this line
+ belongs to */
+ file_info_type *file;
+
+ /* Next in list */
+ struct list_info_struct *next;
+
+
+ /* Pointer to any error message associated with this line */
+ char *message;
+
+ enum
+ {
+ EDICT_NONE,
+ EDICT_SBTTL,
+ EDICT_TITLE,
+ EDICT_NOLIST,
+ EDICT_LIST,
+ EDICT_EJECT
+ } edict;
+ char *edict_arg;
+
+} list_info_type;
+
+
+static struct list_info_struct *head;
+struct list_info_struct *listing_tail;
+extern int listing;
+extern unsigned int physical_input_line;
+extern fragS *frag_now;
+
+
+static int paper_width = 200;
+static int paper_height = 60;
+
+
+/* this static array is used to keep the text of data to be printed
+ before the start of the line.
+ It is stored so we can give a bit more info on the next line. To much, and large
+ initialized arrays will use up lots of paper.
+ */
+
+static char data_buffer[100];
+static unsigned int data_buffer_size;
+
+
+static void
+DEFUN(listing_message,(name, message),
+ char *name AND
+ char *message)
+{
+ unsigned int l = strlen(name) + strlen(message)+1;
+ char *n = malloc(l);
+ strcpy(n,name);
+ strcat(n,message);
+ if(listing_tail != (list_info_type *)NULL)
+ {
+ listing_tail->message = n;
+ }
+
+}
+
+
+
+
+void
+DEFUN(listing_warning,(message),
+ char *message)
+{
+ listing_message("Warning:", message);
+}
+
+void
+DEFUN(listing_error,(message),
+ char *message)
+{
+ listing_message("Error:", message);
+}
+
+
+
+ extern char *file_name;
+static file_info_type *file_info_head;
+
+static file_info_type *
+DEFUN_VOID(file_info)
+{
+ /* Find an entry with this file name */
+ file_info_type *p = file_info_head;
+
+ while (p != (file_info_type *)NULL)
+ {
+ if (strcmp(p->filename, file_name) == 0)
+ return p;
+ p = p->next;
+ }
+
+ /* Make new entry */
+
+ p = (file_info_type *)xmalloc(sizeof(file_info_type));
+ p->next = file_info_head;
+ file_info_head = p;
+ p->filename = xmalloc(strlen(file_name)+1);
+ strcpy(p->filename, file_name);
+ p->linenum = 0;
+ p->file = fopen(p->filename,"r");
+ return p;
+
+}
+
+
+void
+DEFUN(listing_newline,(ps),
+ char *ps)
+{
+ char *s = ps;
+
+ static unsigned int last_line =0xffff ;
+
+
+ list_info_type *new;
+ if (physical_input_line != last_line)
+ {
+ last_line = physical_input_line;
+ frag_wane(frag_now);
+ frag_new(0);
+ new = (list_info_type *)malloc(sizeof(list_info_type));
+ new->frag = frag_now;
+ new->line = physical_input_line ;
+ new->file = file_info();
+
+ if (listing_tail)
+ {
+ listing_tail->next = new;
+ }
+ else
+ {
+ head = new;
+ }
+ listing_tail = new;
+ new->next = (list_info_type *)NULL;
+ new->message = (char *)NULL;
+ new->edict = EDICT_NONE;
+ frag_wane(frag_now);
+ frag_new(0);
+ }
+}
+
+
+
+
+static char *
+DEFUN(buffer_line,(ptr,line, size),
+ list_info_type *ptr AND
+ char *line AND
+ unsigned int size)
+{
+ unsigned int count = 0;
+ char *p = line;
+ int c = fgetc(ptr->file->file);
+ size -= 1; /* leave room for null */
+ while (c != EOF && c != '\n')
+ {
+ if (count < size)
+ *p++ = c;
+ count++;
+
+ c= fgetc(ptr->file->file);
+ }
+ if (c == EOF)
+ {
+ rewind(ptr->file->file);
+ }
+
+ *p++ = 0;
+ return line;
+}
+
+
+static char *fn;
+
+static unsigned int eject; /* Eject pending */
+static unsigned int page; /* Current page number */
+static char *title; /* current title */
+static char *subtitle; /* current subtitle */
+static unsigned int on_page; /* number of lines printed on current page */
+
+
+static void
+DEFUN(listing_page,(list),
+ list_info_type *list)
+{
+ /* Grope around, see if we can see a title or subtitle edict coming up
+ soon (we look down 10 lines of the page and see if it's there)*/
+ if ((eject || (on_page >= paper_height)) && paper_height != 0)
+ {
+ unsigned int c = 10;
+ int had_title = 0;
+ int had_subtitle = 0;
+
+ page++;
+
+ while (c != 0 && list)
+ {
+ if (list->edict == EDICT_SBTTL && !had_subtitle)
+ {
+ had_subtitle = 1;
+ subtitle = list->edict_arg;
+ }
+ if (list->edict == EDICT_TITLE && !had_title)
+ {
+ had_title = 1;
+ title = list->edict_arg;
+ }
+ list = list->next;
+ c--;
+ }
+
+
+ if (page > 1)
+ {
+ printf("\f");
+ }
+
+ printf("%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
+ printf("%s\n", title);
+ printf("%s\n", subtitle);
+ on_page = 3;
+ eject = 0;
+ }
+}
+
+
+static unsigned int
+DEFUN(calc_hex,(list),
+ list_info_type *list)
+{
+ list_info_type *first = list;
+ list_info_type *last = first;
+ unsigned int address = ~0;
+
+ fragS *frag;
+ fragS *frag_ptr;
+
+ unsigned int byte_in_frag = 0;
+
+ int anything = 0;
+
+ /* Find first frag which says it belongs to this line */
+ frag = list->frag;
+ while (frag && frag->line != list)
+ frag = frag->fr_next;
+
+ frag_ptr = frag;
+
+ data_buffer_size = 0;
+
+ /* Dump all the frags which belong to this line */
+ while (frag_ptr != (fragS *)NULL && frag_ptr->line == first)
+ {
+ /* Print as many bytes from the fixed part as is sensible */
+ while(byte_in_frag < frag_ptr->fr_fix && data_buffer_size < sizeof(data_buffer)-10)
+ {
+ if (address == ~0)
+ {
+ address = frag_ptr->fr_address;
+ }
+
+ sprintf(data_buffer + data_buffer_size, "%02X",(frag_ptr->fr_literal[byte_in_frag]) & 0xff);
+ data_buffer_size += 2;
+ byte_in_frag++;
+ }
+ /* Print as many bytes from the variable part as is sensible */
+ while (byte_in_frag < frag_ptr->fr_var * frag_ptr->fr_offset
+ && data_buffer_size < sizeof(data_buffer)-10)
+ {
+ if (address == ~0)
+ {
+ address = frag_ptr->fr_address;
+ }
+ data_buffer[data_buffer_size++] = '*';
+ data_buffer[data_buffer_size++] = '*';
+
+ byte_in_frag++;
+ }
+ frag_ptr = frag_ptr->fr_next;
+ }
+ data_buffer[data_buffer_size++] = 0;
+ return address;
+}
+
+
+
+
+
+
+static void
+DEFUN(print_lines,(list, string, address),
+list_info_type *list AND
+char *string AND
+unsigned int address)
+{
+ unsigned int idx;
+ unsigned int nchars;
+ unsigned int lines;
+ unsigned int byte_in_word =0;
+ char *src = data_buffer;
+
+ /* Print the stuff on the first line */
+ listing_page(list);
+ nchars = (LISTING_WORD_SIZE*2 +1) * LISTING_LHS_WIDTH ;
+ /* Print the hex for the first line */
+ if (address == ~0)
+ {
+ printf("% 4d ", list->line);
+ for (idx = 0; idx < nchars; idx++)
+ printf(" ");
+
+ printf("\t%s\n", string ? string : "");
+ on_page++;
+ listing_page(0);
+
+ }
+ else
+ {
+ if (had_errors())
+ {
+ printf("% 4d ???? ", list->line);
+ }
+ else
+ {
+ printf("% 4d %04x ", list->line, address);
+ }
+
+ /* And the data to go along with it */
+ idx = 0;
+
+ while (*src && idx < nchars)
+ {
+ printf("%c%c", src[0], src[1]);
+ src += 2;
+ byte_in_word++;
+ if (byte_in_word == LISTING_WORD_SIZE)
+ {
+ printf(" ");
+ idx++;
+ byte_in_word = 0;
+ }
+ idx+=2;
+ }
+
+ for (;idx < nchars; idx++)
+ printf(" ");
+
+ printf("\t%s\n", string ? string : "");
+ on_page++;
+ listing_page(list);
+ if (list->message)
+ {
+ printf("**** %s\n",list->message);
+ listing_page(list);
+ on_page++;
+ }
+
+ for (lines = 0;
+ lines < LISTING_LHS_CONT_LINES
+ && *src;
+ lines++) {
+ nchars = ((LISTING_WORD_SIZE*2) +1) * LISTING_LHS_WIDTH_SECOND -1;
+ idx = 0;
+ /* Print any more lines of data, but more compactly */
+ printf("% 4d ", list->line);
+
+ while (*src && idx < nchars)
+ {
+ printf("%c%c", src[0], src[1]);
+ src+=2;
+ idx+=2;
+ byte_in_word++;
+ if (byte_in_word == LISTING_WORD_SIZE)
+ {
+ printf(" ");
+ idx++;
+ byte_in_word = 0;
+ }
+ }
+
+ printf("\n");
+ on_page++;
+ listing_page(list);
+
+ }
+
+
+ }
+}
+
+
+
+
+
+
+static void
+DEFUN_VOID(list_symbol_table)
+{
+ extern symbolS *symbol_rootP;
+
+ symbolS *ptr ;
+ eject = 1;
+ listing_page(0);
+ printf("DEFINED SYMBOLS\n");
+ on_page++;
+
+ for (ptr = symbol_rootP; ptr != (symbolS*)NULL; ptr = symbol_next(ptr))
+ {
+ if (ptr->sy_frag->line)
+ {
+ printf("%20s:%-5d %2d:%08x %s \n",
+ ptr->sy_frag->line->file->filename,
+ ptr->sy_frag->line->line,
+ S_GET_SEGMENT(ptr),
+ S_GET_VALUE(ptr),
+ S_GET_NAME(ptr));
+ on_page++;
+ listing_page(0);
+
+ }
+
+ }
+ printf("\n");
+ on_page++;
+ listing_page(0);
+ printf("UNDEFINED SYMBOLS\n");
+ on_page++;
+ listing_page(0);
+
+ for (ptr = symbol_rootP; ptr != (symbolS*)NULL; ptr = symbol_next(ptr))
+ {
+ if (ptr->sy_frag->line == 0)
+ {
+
+ printf("%s\n", S_GET_NAME(ptr));
+ on_page++;
+ listing_page(0);
+
+ }
+ }
+}
+
+void
+DEFUN(listing_listing,(name),
+ char *name)
+{
+ list_info_type *list = head;
+ unsigned int page= 1;
+ unsigned int prev = 0;
+ char *message;
+ char *buffer;
+ char *p;
+ unsigned int addr = 0;
+ int on_page = 0;
+ int show_listing = 1;
+
+ buffer = malloc(LISTING_RHS_WIDTH);
+ eject = 1;
+ list = head;
+
+ while (list != (list_info_type *)NULL && 0)
+ {
+ if (list->next)
+ list->frag = list->next->frag;
+ list = list->next;
+
+ }
+
+ list = head->next;
+
+
+ while ( list)
+ {
+ p = buffer_line(list, buffer, LISTING_RHS_WIDTH > paper_width ?
+ paper_width : LISTING_RHS_WIDTH);
+
+ switch (list->edict) {
+ case EDICT_LIST:
+ show_listing++;
+ break;
+ case EDICT_NOLIST:
+ show_listing--;
+ break;
+ case EDICT_EJECT:
+ break;
+ case EDICT_NONE:
+ break;
+ case EDICT_TITLE:
+ title = list->edict_arg;
+ break;
+ case EDICT_SBTTL:
+ subtitle = list->edict_arg;
+ break;
+ default:
+ abort();
+ }
+
+ if (show_listing > 0)
+ {
+ /* Scan down the list and print all the stuff which can be done
+ with this line (or lines) */
+ message = 0;
+
+
+ print_lines(list, p, calc_hex(list));
+
+ if (list->edict == EDICT_EJECT)
+ {
+ eject = 1;
+ }
+ }
+ list = list->next;
+ }
+ free(buffer);
+}
+
+void
+DEFUN(listing_print,(name),
+ char *name)
+{
+ title = "";
+ subtitle = "";
+
+ if (listing & LISTING_NOFORM)
+ {
+ paper_height = 0;
+ }
+
+ if (listing & LISTING_LISTING)
+ {
+ listing_listing(name);
+
+ }
+ if (listing & LISTING_SYMBOLS)
+ {
+ list_symbol_table();
+ }
+}
+
+
+void
+DEFUN(listing_file,(name),
+char *name)
+{
+ fn = name;
+}
+
+void
+DEFUN_VOID(listing_eject)
+{
+ listing_tail->edict = EDICT_EJECT;
+}
+
+void
+DEFUN_VOID(listing_flags)
+{
+
+}
+void
+DEFUN(listing_list,(on),
+ unsigned int on)
+{
+ listing_tail->edict = on ? EDICT_LIST : EDICT_NOLIST;
+}
+
+
+void
+DEFUN_VOID(listing_psize)
+{
+ paper_height = get_absolute_expression();
+
+ if (paper_height < 0 || paper_height > 1000)
+ {
+ paper_height = 0;
+ as_warn("strantge paper height, set to no form");
+ }
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ paper_width = get_absolute_expression();
+ }
+}
+
+
+void
+DEFUN(listing_title,(depth),
+ unsigned int depth)
+{
+ char *start;
+ char *title;
+ unsigned int length;
+
+ SKIP_WHITESPACE();
+ if (*input_line_pointer=='\"') {
+ input_line_pointer++;
+ start = input_line_pointer;
+
+ while (*input_line_pointer)
+ {
+ if (*input_line_pointer == '\"')
+ {
+ length = input_line_pointer - start;
+ title = malloc(length + 1);
+ memcpy(title, start, length);
+ title[length] = 0;
+ listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
+ listing_tail->edict_arg = title;
+ input_line_pointer++;
+ demand_empty_rest_of_line();
+ return;
+ }
+ else if (*input_line_pointer == '\n')
+ {
+ as_bad("New line in title");
+ demand_empty_rest_of_line();
+ return;
+ }
+ else
+ {
+ input_line_pointer++;
+ }
+ }
+ }
+ else
+ {
+ as_bad("expecting title in quotes");
+ }
+}
+
+
+#else
+
+
+/* Dummy functions for when compiled without listing enabled */
+
+void
+DEFUN_VOID(listing_flags)
+{
+ s_ignore();
+}
+
+void DEFUN_VOID(listing_list)
+{
+ s_ignore();
+}
+
+void DEFUN_VOID(listing_eject)
+{
+ s_ignore();
+}
+void DEFUN(listing_psize)
+{
+ s_ignore();
+}
+
+void DEFUN(listing_title, (depth),
+unsigned int depth)
+{
+ s_ignore();
+}
+void
+DEFUN(listing_file,(name),
+char *name)
+{
+
+}
+
+void DEFUN(listing_newline,(name),
+char *name)
+{
+
+}
+
+
+#endif