* \param bc current bytecode (usually passed into higher-level
* calling function)
* \param warn enables standard warnings: zero for none;
- * nonzero for overflow/underflow floating point warnings;
- * negative for signed integer warnings,
- * positive for unsigned integer warnings
+ * nonzero for overflow/underflow floating point warnings
* \param d objfmt-specific data (passed into higher-level calling
* function)
* \return Nonzero if an error occurred, 0 otherwise.
EXTRA_DIST += modules/arch/lc3b/Makefile.inc
include modules/arch/x86/Makefile.inc
-#include modules/arch/lc3b/Makefile.inc
+include modules/arch/lc3b/Makefile.inc
dist_man_MANS += yasm_arch.7
return 1;
}
-static int
-lc3b_parse_directive(/*@unused@*/ yasm_arch *arch,
- /*@unused@*/ const char *name,
- /*@unused@*/ /*@null@*/ yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams,
- /*@unused@*/ yasm_object *object,
- /*@unused@*/ unsigned long line)
-{
- return 1;
-}
-
static const unsigned char **
lc3b_get_fill(const yasm_arch *arch)
{
}
static unsigned int
-lc3b_get_reg_size(/*@unused@*/ yasm_arch *arch, /*@unused@*/ unsigned long reg)
+lc3b_get_reg_size(/*@unused@*/ yasm_arch *arch, /*@unused@*/ uintptr_t reg)
{
return 16;
}
-static unsigned long
+static uintptr_t
lc3b_reggroup_get_reg(/*@unused@*/ yasm_arch *arch,
- /*@unused@*/ unsigned long reggroup,
+ /*@unused@*/ uintptr_t reggroup,
/*@unused@*/ unsigned long regindex)
{
return 0;
}
static void
-lc3b_reg_print(/*@unused@*/ yasm_arch *arch, unsigned long reg, FILE *f)
+lc3b_reg_print(/*@unused@*/ yasm_arch *arch, uintptr_t reg, FILE *f)
{
fprintf(f, "r%u", (unsigned int)(reg&7));
}
static yasm_effaddr *
lc3b_ea_create_expr(yasm_arch *arch, yasm_expr *e)
{
- yasm_expr_destroy(e);
- return NULL;
+ yasm_effaddr *ea = yasm_xmalloc(sizeof(yasm_effaddr));
+ yasm_value_initialize(&ea->disp, e, 0);
+ ea->need_nonzero_len = 0;
+ ea->need_disp = 1;
+ ea->nosplit = 0;
+ ea->strong = 0;
+ ea->segreg = 0;
+ return ea;
+}
+
+void
+yasm_lc3b__ea_destroy(/*@only@*/ yasm_effaddr *ea)
+{
+ yasm_value_delete(&ea->disp);
+ yasm_xfree(ea);
+}
+
+static void
+lc3b_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
+{
+ fprintf(f, "%*sDisp:\n", indent_level, "");
+ yasm_value_print(&ea->disp, f, indent_level+1);
}
/* Define lc3b machines -- see arch.h for details */
yasm_arch_module yasm_lc3b_LTX_arch = {
"LC-3b",
"lc3b",
+ NULL,
lc3b_create,
lc3b_destroy,
lc3b_get_machine,
lc3b_get_address_size,
lc3b_set_var,
- yasm_lc3b__parse_cpu,
yasm_lc3b__parse_check_insnprefix,
yasm_lc3b__parse_check_regtmod,
- lc3b_parse_directive,
lc3b_get_fill,
- yasm_lc3b__finalize_insn,
lc3b_floatnum_tobytes,
yasm_lc3b__intnum_tobytes,
lc3b_get_reg_size,
lc3b_reg_print,
NULL, /*yasm_lc3b__segreg_print*/
lc3b_ea_create_expr,
+ yasm_lc3b__ea_destroy,
+ lc3b_ea_print,
+ yasm_lc3b__create_empty_insn,
lc3b_machines,
"lc3b",
16,
- 512,
2
};
yasm_value imm; /* immediate or relative value */
lc3b_imm_type imm_type; /* size of the immediate */
- /* PC origin if needed */
- /*@null@*/ /*@dependent@*/ yasm_bytecode *origin_prevbc;
-
unsigned int opcode; /* opcode */
} lc3b_insn;
void yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn);
-void yasm_lc3b__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len);
-
yasm_arch_insnprefix yasm_lc3b__parse_check_insnprefix
- (yasm_arch *arch, unsigned long data[4], const char *id, size_t id_len);
+ (yasm_arch *arch, const char *id, size_t id_len, unsigned long line,
+ /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix);
yasm_arch_regtmod yasm_lc3b__parse_check_regtmod
- (yasm_arch *arch, unsigned long *data, const char *id, size_t id_len);
-
-void yasm_lc3b__finalize_insn
- (yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
- const unsigned long data[4], int num_operands,
- /*@null@*/ yasm_insn_operands *operands, int num_prefixes,
- unsigned long **prefixes, int num_segregs, const unsigned long *segregs);
+ (yasm_arch *arch, const char *id, size_t id_len,
+ /*@out@*/ uintptr_t *data);
int yasm_lc3b__intnum_tobytes
(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
int warn);
+
+/*@only@*/ yasm_bytecode *yasm_lc3b__create_empty_insn(yasm_arch *arch,
+ unsigned long line);
+
+void yasm_lc3b__ea_destroy(/*@only@*/ yasm_effaddr *ea);
+
#endif
static void lc3b_bc_insn_destroy(void *contents);
static void lc3b_bc_insn_print(const void *contents, FILE *f,
int indent_level);
-static yasm_bc_resolve_flags lc3b_bc_insn_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int lc3b_bc_insn_calc_len(yasm_bytecode *bc,
+ yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
static int lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
lc3b_bc_insn_destroy,
lc3b_bc_insn_print,
yasm_bc_finalize_common,
- lc3b_bc_insn_resolve,
+ lc3b_bc_insn_calc_len,
+ lc3b_bc_insn_expand,
lc3b_bc_insn_tobytes,
0
};
(unsigned int)insn->opcode);
}
-static yasm_bc_resolve_flags
-lc3b_bc_insn_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
+static int
+lc3b_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
{
lc3b_insn *insn = (lc3b_insn *)bc->contents;
yasm_bytecode *target_prevbc;
- /*@only@*/ yasm_intnum *num;
- long rel;
/* Fixed size instruction length */
- bc->len = 2;
-
- /* Only need to worry about out-of-range to PC-relative, and only if we're
- * saving.
- */
- if (insn->imm_type != LC3B_IMM_9_PC || !save)
- return YASM_BC_RESOLVE_MIN_LEN;
-
- if (!insn->imm.rel)
- num = yasm_intnum_create_uint(0);
- else if (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc)
- || target_prevbc->section != insn->origin_prevbc->section
- || !(num = calc_bc_dist(insn->origin_prevbc, target_prevbc))) {
- /* External or out of segment, so we can't check distance. */
- return YASM_BC_RESOLVE_MIN_LEN;
- }
+ bc->len += 2;
- if (insn->imm.abs) {
- /*@only@*/ yasm_expr *temp = yasm_expr_copy(insn->imm.abs);
- /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
- num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
- if (!num2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("jump target too complex"));
- yasm_expr_destroy(temp);
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- yasm_intnum_calc(num, YASM_EXPR_ADD, num2);
- yasm_expr_destroy(temp);
+ /* Only need to worry about out-of-range to PC-relative */
+ if (insn->imm_type != LC3B_IMM_9_PC)
+ return 0;
+
+ if (insn->imm.rel
+ && (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc)
+ || target_prevbc->section != bc->section)) {
+ /* External or out of segment, so we can't check distance. */
+ return 0;
}
- rel = yasm_intnum_get_int(num);
- yasm_intnum_destroy(num);
- rel -= 2;
/* 9-bit signed, word-multiple displacement */
- if (rel < -512 || rel > 511) {
- yasm_error_set(YASM_ERROR_OVERFLOW, N_("target out of range"));
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- return YASM_BC_RESOLVE_MIN_LEN;
+ add_span(add_span_data, bc, 1, &insn->imm, -512+(long)bc->len,
+ 511+(long)bc->len);
+ return 0;
+}
+
+static int
+lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ yasm_error_set(YASM_ERROR_VALUE, N_("jump target out of range"));
+ return -1;
}
static int
break;
case LC3B_IMM_5:
insn->imm.size = 5;
- if (output_value(&insn->imm, *bufp, 2, 0, bc, -1, d))
+ insn->imm.sign = 1;
+ if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_6_WORD:
break;
case LC3B_IMM_6_BYTE:
insn->imm.size = 6;
- if (output_value(&insn->imm, *bufp, 2, 0, bc, -1, d))
+ insn->imm.sign = 1;
+ if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_8:
yasm_expr_int(delta), bc->line);
insn->imm.size = 9;
- if (output_value(&insn->imm, *bufp, 2, 0, bc, -1, d))
+ insn->imm.sign = 1;
+ if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_9:
unsigned int operands[3];
} lc3b_insn_info;
-/* Define lexer arch-specific data with 0-3 modifiers. */
-#define DEF_INSN_DATA(group, mod) do { \
- data[0] = (unsigned long)group##_insn; \
- data[1] = ((mod)<<8) | \
- ((unsigned char)(sizeof(group##_insn)/sizeof(lc3b_insn_info))); \
- } while (0)
-
-#define RET_INSN(group, mod) do { \
- DEF_INSN_DATA(group, mod); \
- return YASM_ARCH_INSN; \
- } while (0)
+typedef struct lc3b_id_insn {
+ yasm_insn insn; /* base structure */
+
+ /* instruction parse group - NULL if empty instruction (just prefixes) */
+ /*@null@*/ const lc3b_insn_info *group;
+
+ /* Modifier data */
+ unsigned long mod_data;
+
+ /* Number of elements in the instruction parse group */
+ unsigned int num_info:8;
+} lc3b_id_insn;
+
+static void lc3b_id_insn_destroy(void *contents);
+static void lc3b_id_insn_print(const void *contents, FILE *f, int indent_level);
+static void lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+
+static const yasm_bytecode_callback lc3b_id_insn_callback = {
+ lc3b_id_insn_destroy,
+ lc3b_id_insn_print,
+ lc3b_id_insn_finalize,
+ yasm_bc_calc_len_common,
+ yasm_bc_expand_common,
+ yasm_bc_tobytes_common,
+ YASM_BC_SPECIAL_INSN
+};
/*
* Instruction groupings
*/
+static const lc3b_insn_info empty_insn[] = {
+ { 0, 0, 0, {0, 0, 0} }
+};
+
static const lc3b_insn_info addand_insn[] = {
{ MOD_OpHAdd, 0x1000, 3,
{OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Reg|OPA_Imm|OPI_5} },
{ 0, 0xF000, 1, {OPT_Imm|OPA_Imm|OPI_8, 0, 0} }
};
-void
-yasm_lc3b__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
- yasm_bytecode *prev_bc, const unsigned long data[4],
- int num_operands,
- /*@null@*/ yasm_insn_operands *operands,
- int num_prefixes, unsigned long **prefixes,
- int num_segregs, const unsigned long *segregs)
+static void
+lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
{
+ lc3b_id_insn *id_insn = (lc3b_id_insn *)bc->contents;
lc3b_insn *insn;
- int num_info = (int)(data[1]&0xFF);
- lc3b_insn_info *info = (lc3b_insn_info *)data[0];
- unsigned long mod_data = data[1] >> 8;
+ int num_info = id_insn->num_info;
+ const lc3b_insn_info *info = id_insn->group;
+ unsigned long mod_data = id_insn->mod_data;
int found = 0;
yasm_insn_operand *op;
int i;
+ yasm_insn_finalize(&id_insn->insn);
+
/* Just do a simple linear search through the info array for a match.
* First match wins.
*/
int mismatch = 0;
/* Match # of operands */
- if (num_operands != info->num_operands)
+ if (id_insn->insn.num_operands != info->num_operands)
continue;
- if (!operands) {
+ if (id_insn->insn.num_operands == 0) {
found = 1; /* no operands -> must have a match here. */
break;
}
/* Match each operand type and size */
- for(i = 0, op = yasm_ops_first(operands); op && i<info->num_operands &&
- !mismatch; op = yasm_operand_next(op), i++) {
+ for(i = 0, op = yasm_insn_ops_first(&id_insn->insn);
+ op && i<info->num_operands && !mismatch;
+ op = yasm_insn_op_next(op), i++) {
/* Check operand type */
switch ((int)(info->operands[i] & OPT_MASK)) {
case OPT_Imm:
insn = yasm_xmalloc(sizeof(lc3b_insn));
yasm_value_initialize(&insn->imm, NULL, 0);
insn->imm_type = LC3B_IMM_NONE;
- insn->origin_prevbc = NULL;
insn->opcode = info->opcode;
/* Apply modifiers */
}
/* Go through operands and assign */
- if (operands) {
- for(i = 0, op = yasm_ops_first(operands); op && i<info->num_operands;
- op = yasm_operand_next(op), i++) {
+ if (id_insn->insn.num_operands > 0) {
+ for(i = 0, op = yasm_insn_ops_first(&id_insn->insn);
+ op && i<info->num_operands; op = yasm_insn_op_next(op), i++) {
switch ((int)(info->operands[i] & OPA_MASK)) {
case OPA_None:
yasm_expr_int(yasm_intnum_create_uint(1)),
op->data.val->line);
if (yasm_value_finalize_expr(&insn->imm,
- op->data.val, 0))
+ op->data.val,
+ prev_bc, 0))
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
N_("immediate expression too complex"));
break;
if (yasm_value_finalize_expr(&insn->imm,
yasm_expr_create_ident(yasm_expr_int(
yasm_intnum_create_uint(op->data.reg & 0x7)),
- bc->line), 0))
+ bc->line), prev_bc, 0))
yasm_internal_error(N_("reg expr too complex?"));
break;
default:
default:
yasm_internal_error(N_("unknown operand action"));
}
+
+ /* Clear so it doesn't get destroyed */
+ op->type = YASM_INSN__OPERAND_REG;
}
if (insn->imm_type == LC3B_IMM_9_PC) {
- insn->origin_prevbc = prev_bc;
if (insn->imm.seg_of || insn->imm.rshift > 1
|| insn->imm.curpos_rel)
yasm_error_set(YASM_ERROR_VALUE, N_("invalid jump target"));
#define YYMARKER marker
#define YYFILL(n) (void)(n)
-void
-yasm_lc3b__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len)
-{
-}
-
yasm_arch_regtmod
-yasm_lc3b__parse_check_regtmod(yasm_arch *arch, unsigned long *data,
- const char *oid, size_t id_len)
+yasm_lc3b__parse_check_regtmod(yasm_arch *arch, const char *oid, size_t id_len,
+ uintptr_t *data)
{
const YYCTYPE *id = (const YYCTYPE *)oid;
/*const char *marker;*/
*/
}
+#define RET_INSN(g, m) \
+ do { \
+ group = g##_insn; \
+ mod = m; \
+ nelems = NELEMS(g##_insn); \
+ goto done; \
+ } while(0)
+
yasm_arch_insnprefix
-yasm_lc3b__parse_check_insnprefix(yasm_arch *arch, unsigned long data[4],
- const char *oid, size_t id_len)
+yasm_lc3b__parse_check_insnprefix(yasm_arch *arch, const char *oid,
+ size_t id_len, unsigned long line,
+ yasm_bytecode **bc, uintptr_t *prefix)
{
const YYCTYPE *id = (const YYCTYPE *)oid;
+ const lc3b_insn_info *group = empty_insn;
+ unsigned long mod = 0;
+ unsigned int nelems = NELEMS(empty_insn);
+ lc3b_id_insn *id_insn;
+
+ *bc = (yasm_bytecode *)NULL;
+ *prefix = 0;
+
/*const char *marker;*/
/*!re2c
/* instructions */
return YASM_ARCH_NOTINSNPREFIX;
}
*/
+
+done:
+ id_insn = yasm_xmalloc(sizeof(lc3b_id_insn));
+ yasm_insn_initialize(&id_insn->insn);
+ id_insn->group = group;
+ id_insn->mod_data = mod;
+ id_insn->num_info = nelems;
+ *bc = yasm_bc_create_common(&lc3b_id_insn_callback, id_insn, line);
+ return YASM_ARCH_INSN;
+}
+
+static void
+lc3b_id_insn_destroy(void *contents)
+{
+ lc3b_id_insn *id_insn = (lc3b_id_insn *)contents;
+ yasm_insn_delete(&id_insn->insn, yasm_lc3b__ea_destroy);
+ yasm_xfree(contents);
+}
+
+static void
+lc3b_id_insn_print(const void *contents, FILE *f, int indent_level)
+{
+ const lc3b_id_insn *id_insn = (const lc3b_id_insn *)contents;
+ yasm_insn_print(&id_insn->insn, f, indent_level);
+ /*TODO*/
+}
+
+/*@only@*/ yasm_bytecode *
+yasm_lc3b__create_empty_insn(yasm_arch *arch, unsigned long line)
+{
+ lc3b_id_insn *id_insn = yasm_xmalloc(sizeof(lc3b_id_insn));
+
+ yasm_insn_initialize(&id_insn->insn);
+ id_insn->group = empty_insn;
+ id_insn->mod_data = 0;
+ id_insn->num_info = NELEMS(empty_insn);
+
+ return yasm_bc_create_common(&lc3b_id_insn_callback, id_insn, line);
}
yasm_expr_int(delta), bc->line);
jmp->target.size = 8;
+ jmp->target.sign = 1;
if (output_value(&jmp->target, *bufp, 1,
- (unsigned long)(*bufp-bufp_orig), bc, -1, d))
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
return 1;
*bufp += 1;
break;
yasm_expr_int(delta), bc->line);
jmp->target.size = i*8;
+ jmp->target.sign = 1;
if (output_value(&jmp->target, *bufp, i,
- (unsigned long)(*bufp-bufp_orig), bc, -1, d))
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
return 1;
*bufp += i;
break;