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];
asm_warn(ctx, "INDIRECT memoffset 0x%X too long (> 6 bits)", off);
off &= 0x3F;
}
- if (reg & ~0x7)
+ if (reg > 6) {
+ /* Assembler bug. The parser shouldn't pass this value. */
asm_error(ctx, "OFFR-nr too big");
+ }
+ if (reg == 6) {
+ asm_warn(ctx, "Using offset register 6. This register is broken "
+ "on certain devices. Use off0 to off5 only.");
+ }
val |= off;
val |= (reg << 6);
break;
}
}
-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;
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(*fake));
+ fake_reg = xmalloc(sizeof(*fake_reg));
+ 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 em_insn;
struct operlist em_ol;
- struct operand em_op;
- struct immediate em_imm;
-
- /* This is a pseudo-OP. We emulate it by JE */
-
- em_insn.op = OP_JE;
- em_imm.imm = 1;
- em_op.type = OPER_IMM;
- em_op.u.imm = &em_imm;
- em_ol.oper[0] = &em_op;
- em_ol.oper[1] = &em_op;
- em_ol.oper[2] = insn->operands->oper[0];
+ struct immediate em_condition;
+ struct operand em_cond_op;
+
+ /* This is a pseudo-OP. We emulate it with
+ * JEXT 0x7F, target */
+
+ em_insn.op = OP_JEXT;
+ em_condition.imm = 0x7F; /* Ext cond: Always true */
+ em_cond_op.type = OPER_IMM;
+ em_cond_op.u.imm = &em_condition;
+ em_ol.oper[0] = &em_cond_op;
+ em_ol.oper[1] = insn->operands->oper[0]; /* Target */
em_insn.operands = &em_ol;
+
assemble_instruction(ctx, &em_insn); /* recurse */
}
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:
+ /* Get the previous instruction and check whether it
+ * is a jump instruction. */
+ list_for_each_entry_reverse(out, &ctx->output, list) {
+ /* Search the last insn. */
+ if (out->type == OUT_INSN) {
+ if (out->is_jump_insn) {
+ asm_warn(ctx, "RET instruction directly after "
+ "jump instruction. The hardware won't like this.");
+ }
+ break;
+ }
+ }
do_assemble_insn(ctx, insn, 0x003);
break;
case OP_TKIPH:
static void emit_code(struct assembler_context *ctx)
{
FILE *fd;
- char *fn;
- size_t fn_len;
+ const char *fn;
struct code_output *c;
uint64_t code;
unsigned char outbuf[8];
unsigned int insn_count = 0;
struct fw_header hdr;
- fn_len = strlen(outfile_name) + 20;
- fn = xmalloc(fn_len);
- snprintf(fn, fn_len, "%s.ucode", outfile_name);
+ fn = outfile_name;
fd = fopen(fn, "w+");
if (!fd) {
fprintf(stderr, "Could not open microcode output file \"%s\"\n", fn);
- free(fn);
exit(1);
}
if (IS_VERBOSE_DEBUG)
break;
}
}
+
+ if (arg_print_sizes) {
+ printf("%s: text = %u instructions (%u bytes)\n",
+ fn, insn_count,
+ (unsigned int)(insn_count * sizeof(uint64_t)));
+ }
+
fclose(fd);
- free(fn);
}
static void assemble(void)