OUT_LABEL,
} type;
+ /* Set to true, if this is a jump instruction.
+ * This is only used when assembling RET to check
+ * whether the previous instruction was a jump or not. */
+ bool is_jump_insn;
+
unsigned int opcode;
struct out_operand operands[3];
case SPR:
/* format: 0b100. .... .... */
val |= 0x800;
- if (ctx->arch == 15) //FIXME is this ok?
+ if (ctx->arch == 15)
val <<= 1;
if (reg->nr & ~0x1FF)
asm_error(ctx, "SPR-nr too big");
case OFFR:
/* format: 0b1000 0110 0rrr */
val |= 0x860;
- if (ctx->arch == 15) //FIXME is this ok?
+ if (ctx->arch == 15)
val <<= 1;
if (reg->nr & ~0x7)
asm_error(ctx, "OFFR-nr too big");
}
}
-static void do_assemble_insn(struct assembler_context *ctx,
- struct instruction *insn,
- unsigned int opcode)
+static struct code_output * do_assemble_insn(struct assembler_context *ctx,
+ struct instruction *insn,
+ unsigned int opcode)
{
int i;
struct operlist *ol;
"lowlevel do_assemble_insn");
list_add_tail(&out->list, &ctx->output);
+
+ return out;
}
static unsigned int merge_ext_into_opcode(struct assembler_context *ctx,
unsigned int opbase,
struct instruction *insn)
{
+ struct operand *fake;
+ struct registr *fake_reg;
+ struct operand *target;
struct operlist *ol;
unsigned int cond;
unsigned int opcode;
ol = insn->operands;
opcode = opbase;
- cond = ol->oper[0]->u.raw;
+ cond = ol->oper[0]->u.imm->imm;
if (cond & ~0xFF)
asm_error(ctx, "External jump condition value too big (> 0xFF)");
opcode |= cond;
- ol->oper[0] = ol->oper[1];
- ol->oper[1] = ol->oper[2];
- ol->oper[2] = ol->oper[3];
+ target = ol->oper[1];
+ memset(ol->oper, 0, sizeof(ol->oper));
+
+ /* This instruction has two fake r0 operands
+ * at position 0 and 1. */
+ fake = xmalloc(sizeof(struct operand));
+ fake_reg = xmalloc(sizeof(struct operand));
+ fake->type = OPER_REG;
+ fake->u.reg = fake_reg;
+ fake_reg->type = GPR;
+ fake_reg->nr = 0;
+
+ ol->oper[0] = fake;
+ ol->oper[1] = fake;
+ ol->oper[2] = target;
return opcode;
}
struct instruction *insn,
int inverted)
{
+ struct code_output *out;
struct instruction em_insn;
struct operlist em_ol;
struct operand em_op_shift;
/* Do a normal JAND/JNAND instruction */
if (inverted)
- do_assemble_insn(ctx, insn, 0x040 | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x040 | 0x1);
else
- do_assemble_insn(ctx, insn, 0x040);
+ out = do_assemble_insn(ctx, insn, 0x040);
+ out->is_jump_insn = 1;
}
static void assemble_instruction(struct assembler_context *ctx,
struct instruction *insn)
{
+ struct code_output *out;
unsigned int opcode;
switch (insn->op) {
emulate_jand_insn(ctx, insn, 1);
return;
case OP_JS:
- do_assemble_insn(ctx, insn, 0x050);
+ out = do_assemble_insn(ctx, insn, 0x050);
+ out->is_jump_insn = 1;
break;
case OP_JNS:
- do_assemble_insn(ctx, insn, 0x050 | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x050 | 0x1);
+ out->is_jump_insn = 1;
break;
case OP_JE:
- do_assemble_insn(ctx, insn, 0x0D0);
+ out = do_assemble_insn(ctx, insn, 0x0D0);
+ out->is_jump_insn = 1;
break;
case OP_JNE:
- do_assemble_insn(ctx, insn, 0x0D0 | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x0D0 | 0x1);
+ out->is_jump_insn = 1;
break;
case OP_JLS:
- do_assemble_insn(ctx, insn, 0x0D2);
+ out = do_assemble_insn(ctx, insn, 0x0D2);
+ out->is_jump_insn = 1;
break;
case OP_JGES:
- do_assemble_insn(ctx, insn, 0x0D2 | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x0D2 | 0x1);
+ out->is_jump_insn = 1;
break;
case OP_JGS:
- do_assemble_insn(ctx, insn, 0x0D4);
+ out = do_assemble_insn(ctx, insn, 0x0D4);
+ out->is_jump_insn = 1;
break;
case OP_JLES:
- do_assemble_insn(ctx, insn, 0x0D4 | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x0D4 | 0x1);
+ out->is_jump_insn = 1;
break;
case OP_JL:
- do_assemble_insn(ctx, insn, 0x0DA);
+ out = do_assemble_insn(ctx, insn, 0x0DA);
+ out->is_jump_insn = 1;
break;
case OP_JGE:
- do_assemble_insn(ctx, insn, 0x0DA | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x0DA | 0x1);
+ out->is_jump_insn = 1;
break;
case OP_JG:
- do_assemble_insn(ctx, insn, 0x0DC);
+ out = do_assemble_insn(ctx, insn, 0x0DC);
break;
case OP_JLE:
- do_assemble_insn(ctx, insn, 0x0DC | 0x1);
+ out = do_assemble_insn(ctx, insn, 0x0DC | 0x1);
+ out->is_jump_insn = 1;
break;
case OP_JZX:
opcode = merge_ext_into_opcode(ctx, 0x400, insn);
- do_assemble_insn(ctx, insn, opcode);
+ out = do_assemble_insn(ctx, insn, opcode);
+ out->is_jump_insn = 1;
break;
case OP_JNZX:
opcode = merge_ext_into_opcode(ctx, 0x500, insn);
- do_assemble_insn(ctx, insn, opcode);
+ out = do_assemble_insn(ctx, insn, opcode);
+ out->is_jump_insn = 1;
break;
case OP_JEXT:
opcode = merge_external_jmp_into_opcode(ctx, 0x700, insn);
- do_assemble_insn(ctx, insn, opcode);
+ out = do_assemble_insn(ctx, insn, opcode);
+ out->is_jump_insn = 1;
break;
case OP_JNEXT:
opcode = merge_external_jmp_into_opcode(ctx, 0x600, insn);
- do_assemble_insn(ctx, insn, opcode);
+ out = do_assemble_insn(ctx, insn, opcode);
+ out->is_jump_insn = 1;
break;
case OP_CALL:
do_assemble_insn(ctx, insn, 0x002);
break;
case OP_RET:
+ if (!list_empty(&ctx->output)) {
+ /* Get the previous instruction and check whether it
+ * is a jump instruction. */
+ out = list_entry(ctx->output.prev, struct code_output, list);
+ if (out->is_jump_insn) {
+ asm_error(ctx, "RET instruction directly after "
+ "jump instruction. The hardware won't like this.");
+ }
+ }
do_assemble_insn(ctx, insn, 0x003);
break;
case OP_TKIPH:
if (addr < 0)
goto does_not_exist;
c->operands[i].u.operand = addr;
- if (i != 2) /* Is not a jump target */
- c->operands[i].u.operand |= 0xC00; /* Make it be an immediate */
+ if (i != 2) {
+ /* Is not a jump target.
+ * Make it be an immediate */
+ if (ctx->arch == 5)
+ c->operands[i].u.operand |= 0xC00;
+ else if (ctx->arch == 15)
+ c->operands[i].u.operand |= 0xC00 << 1;
+ else
+ asm_error(ctx, "Internal error: label res imm");
+ }
}
break;
case OUT_LABEL:
int err, res = 1;
err = parse_args(argc, argv);
- if (err)
+ if (err < 0)
goto out;
+ if (err > 0) {
+ res = 0;
+ goto out;
+ }
err = open_input_file();
if (err)
goto out;