#include "asm.h" #include "eval.h" #include "parse.h" #include "report.h" #include #include #include #include typedef enum { // clang-format off M_err, M_d8, M_d16, M_nop, M_hlt, M_jmp, M_jmpf, M_jnz, M_cmp, M_mov, M_in, M_out, M_call, M_callf, M_ret, M_retf, M_lit, M_int, M_iret, M_or, M_xor, M_and, M_shl, M_rshl, M_shr, M_rshr, M_add, M_sub, M_rsub, M_mul, M_imul, M_div, M_idiv, M_rdiv, M_ridiv, M_mod, M_rmod, M_push, M_pop // clang-format on } Mnemonic; static const char* mnemonic_str[] = { // clang-format off "err", "d8", "d16", "nop", "hlt", "jmp", "jmpf", "jnz", "cmp", "mov", "in", "out", "call", "callf", "ret", "retf", "lit", "int", "iret", "or", "xor", "and", "shl", "rshl", "shr", "rshr", "add", "sub", "rsub", "mul", "imul", "div", "idiv", "rdiv", "ridiv", "mod", "rmod", "push", "pop" // clang-format on }; uint16_t pline_assemble(OperandEvaluator* evaluator, uint16_t* object, const PLine* line, Reporter* rep) { #define CHECK_OPERAND(OP) \ do { \ if ((OP).ty == EoTy_Err) { \ return 0; \ } \ } while (0) #define ASSEMBLE_ONE(RVAL) \ do { \ Line l = (RVAL); \ return assemble_line(object, &l); \ } while (0) size_t mnemonics_amount = sizeof(mnemonic_str) / sizeof(mnemonic_str[0]); Mnemonic m = M_err; for (size_t i = 0; i < mnemonics_amount; ++i) { if (strcmp(mnemonic_str[i], line->op) == 0) { m = (Mnemonic)i; break; } } switch (m) { case M_err: { REPORTF_ERROR("unrecognized mnemonic '%s'", line->op); reporter_print_loc(rep, line->loc); return 0; } case M_d8: { if (line->ops_size > 64) { reporter_error_with_loc( rep, "too many operands (max is 64)", line->loc); return 0; } size_t buffer_capacity = 128; uint8_t* buffer = malloc(sizeof(uint8_t) * buffer_capacity); size_t buffer_size = 0; for (size_t i = 0; i < line->ops_size; ++i) { EvaledOperand val = eval_operand(evaluator, line->ops[i]); CHECK_OPERAND(val); switch (val.ty) { case EoTy_Imm: buffer[buffer_size++] = (uint8_t)val.imm; break; case EoTy_Str: { for (size_t si = 0; si < line->ops[i]->str_len; ++si) { buffer[buffer_size++] = (uint8_t)line->ops[i]->str[si]; } break; } default: reporter_error_with_loc( rep, "invalid operand", line->ops[i]->loc); return 0; } } uint16_t ip_diff = 0; for (size_t i = 0; i < buffer_size; i += 2) { uint16_t data = 0; // XXX: little endian data |= buffer[i]; if (i + 1 < buffer_size) { data |= (uint16_t)((uint16_t)buffer[i] << 8); } Line l = s_data_i(data); ip_diff += assemble_line(object, &l); } return ip_diff; } case M_d16: { if (line->ops_size > 32) { reporter_error_with_loc( rep, "too many operands (max is 32)", line->loc); return 0; } uint16_t ip_diff = 0; for (size_t i = 0; i < line->ops_size; ++i) { EvaledOperand val = eval_operand(evaluator, line->ops[i]); CHECK_OPERAND(val); switch (val.ty) { case EoTy_Imm: { Line l = s_data_i(val.imm); ip_diff += assemble_line(object, &l); break; } default: reporter_error_with_loc( rep, "invalid operand", line->ops[i]->loc); return 0; } } return ip_diff; } case M_nop: if (line->ops_size == 0) ASSEMBLE_ONE(s_nop()); break; case M_hlt: if (line->ops_size == 0) ASSEMBLE_ONE(s_hlt()); break; case M_jmp: if (line->ops_size == 1) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); if (op1.ty == EoTy_Reg) ASSEMBLE_ONE(s_jmp_r(op1.reg)); if (op1.ty == EoTy_Imm) ASSEMBLE_ONE(s_jmp_i(op1.imm)); } break; case M_jmpf: if (line->ops_size == 2) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op2); if (op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_jmpf_r_r(op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_jmpf_r_i(op1.reg, op2.imm)); } if (op1.ty == EoTy_Imm) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_jmpf_i_r(op1.imm, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_jmpf_i_i(op1.imm, op2.imm)); } } break; case M_jnz: if (line->ops_size == 2) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op2); if (op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_jnz_r(op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_jnz_i(op1.reg, op2.imm)); } } break; case M_cmp: if (line->ops_size == 2) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op2); if (op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_cmp_r(op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_cmp_i(op1.reg, op2.imm)); } } break; case M_mov: if (line->ops_size == 2) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op2); if (op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_mov16_r_r(op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_mov16_r_i(op1.reg, op2.imm)); if (op2.ty == EoTy_Mem8Reg) ASSEMBLE_ONE(s_mov8_r_mr(op1.reg, op2.reg, op2.offset)); if (op2.ty == EoTy_Mem8Imm) ASSEMBLE_ONE(s_mov8_r_mi(op1.reg, op2.imm)); if (op2.ty == EoTy_MemU16Reg) ASSEMBLE_ONE( s_mov16_r_mr(op1.reg, op2.reg, op2.offset)); if (op2.ty == EoTy_MemU16Imm) { ASSEMBLE_ONE(s_mov16_r_mi(op1.reg, op2.imm)); } } if (op1.ty == EoTy_Mem8Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_mov8_mr_r(op1.reg, op1.offset, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_mov8_mr_i(op1.reg, op1.offset, op2.imm)); } if (op1.ty == EoTy_Mem8Imm) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_mov8_mi_r(op1.imm, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_mov8_mi_i(op1.imm, op2.imm)); } if (op1.ty == EoTy_MemU16Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE( s_mov16_mr_r(op1.reg, op1.offset, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE( s_mov16_mr_i(op1.reg, op1.offset, op2.imm)); } if (op1.ty == EoTy_MemU16Imm) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_mov16_mi_r(op1.imm, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_mov16_mi_i(op1.imm, op2.imm)); } } break; case M_in: if (line->ops_size == 2) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); if (dst.ty == EoTy_Reg) { if (op1.ty == EoTy_Reg) ASSEMBLE_ONE(s_in_r(dst.reg, op1.reg)); if (op1.ty == EoTy_Imm) ASSEMBLE_ONE(s_in_i(dst.reg, op1.imm)); } } break; case M_out: if (line->ops_size == 2) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op2); if (op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_out_r_r(op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_out_r_i(op1.reg, op2.imm)); } if (op1.ty == EoTy_Imm) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_out_i_r(op1.imm, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_out_i_i(op1.imm, op2.imm)); } } break; case M_call: if (line->ops_size == 1) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); if (op1.ty == EoTy_Reg) ASSEMBLE_ONE(s_call_r(op1.reg)); if (op1.ty == EoTy_Imm) ASSEMBLE_ONE(s_call_i(op1.imm)); } break; case M_callf: if (line->ops_size == 2) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op2); if (op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_callf_r_r(op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_callf_r_i(op1.reg, op2.imm)); } if (op1.ty == EoTy_Imm) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_callf_i_r(op1.imm, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_callf_i_i(op1.imm, op2.imm)); } } break; case M_ret: if (line->ops_size == 0) { ASSEMBLE_ONE(s_ret()); } break; case M_retf: if (line->ops_size == 0) { ASSEMBLE_ONE(s_retf()); } break; case M_lit: if (line->ops_size == 1) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); if (op1.ty == EoTy_Reg) ASSEMBLE_ONE(s_lit_r(op1.reg)); if (op1.ty == EoTy_Imm) ASSEMBLE_ONE(s_lit_i(op1.imm)); } break; case M_int: if (line->ops_size == 1) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); if (op1.ty == EoTy_Imm) { if (op1.imm > 0xff) { reporter_error_with_loc( rep, "interrupt id exceeds 1 byte", line->loc); return 0; } ASSEMBLE_ONE(s_int((uint8_t)op1.imm)); } } break; case M_iret: if (line->ops_size == 0) { ASSEMBLE_ONE(s_iret()); } break; case M_or: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_or_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) { ASSEMBLE_ONE(s_or_i(dst.reg, op1.reg, op2.imm)); } } } break; case M_xor: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_xor_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_xor_i(dst.reg, op1.reg, op2.imm)); } } break; case M_and: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_and_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_and_i(dst.reg, op1.reg, op2.imm)); } } break; case M_shl: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_shl_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_shl_i(dst.reg, op1.reg, op2.imm)); } } break; case M_rshl: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_rshl_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_rshl_i(dst.reg, op1.reg, op2.imm)); } } break; case M_shr: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_shr_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_shr_i(dst.reg, op1.reg, op2.imm)); } } break; case M_rshr: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_rshr_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_rshr_i(dst.reg, op1.reg, op2.imm)); } } break; case M_add: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_add_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_add_i(dst.reg, op1.reg, op2.imm)); } } break; case M_sub: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_sub_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_sub_i(dst.reg, op1.reg, op2.imm)); } } break; case M_rsub: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_rsub_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_rsub_i(dst.reg, op1.reg, op2.imm)); } } break; case M_mul: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_mul_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_mul_i(dst.reg, op1.reg, op2.imm)); } } break; case M_imul: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_imul_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_imul_i(dst.reg, op1.reg, op2.imm)); } } break; case M_div: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_div_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_div_i(dst.reg, op1.reg, op2.imm)); } } break; case M_idiv: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_idiv_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_idiv_i(dst.reg, op1.reg, op2.imm)); } } break; case M_rdiv: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_rdiv_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_rdiv_i(dst.reg, op1.reg, op2.imm)); } } break; case M_ridiv: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_ridiv_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_ridiv_i(dst.reg, op1.reg, op2.imm)); } } break; case M_mod: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_mod_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_mod_i(dst.reg, op1.reg, op2.imm)); } } break; case M_rmod: if (line->ops_size == 3) { EvaledOperand dst = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(dst); EvaledOperand op1 = eval_operand(evaluator, line->ops[1]); CHECK_OPERAND(op1); EvaledOperand op2 = eval_operand(evaluator, line->ops[2]); CHECK_OPERAND(op2); if (dst.ty == EoTy_Reg && op1.ty == EoTy_Reg) { if (op2.ty == EoTy_Reg) ASSEMBLE_ONE(s_rmod_r(dst.reg, op1.reg, op2.reg)); if (op2.ty == EoTy_Imm) ASSEMBLE_ONE(s_rmod_i(dst.reg, op1.reg, op2.imm)); } } break; case M_push: if (line->ops_size == 1) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); if (op1.ty == EoTy_Reg) { uint16_t size = 0; Line l; l = s_add_i(Rsp, Rsp, 2); size += assemble_line(object, &l); l = s_mov16_mr_r(Rsp, 0, op1.reg); size += assemble_line(object, &l); return size; } if (op1.ty == EoTy_Imm) { uint16_t size = 0; Line l; l = s_add_i(Rsp, Rsp, 2); size += assemble_line(object, &l); l = s_mov16_mr_i(Rsp, 0, op1.imm); size += assemble_line(object, &l); return size; } } break; case M_pop: if (line->ops_size == 1) { EvaledOperand op1 = eval_operand(evaluator, line->ops[0]); CHECK_OPERAND(op1); if (op1.ty == EoTy_Reg) { uint16_t size = 0; Line l; l = s_mov16_r_mr(op1.reg, Rsp, 0); size += assemble_line(object, &l); l = s_sub_i(Rsp, Rsp, 2); size += assemble_line(object, &l); return size; } } break; } reporter_error_with_loc(rep, "malformed instruction", line->loc); return 0; #undef CHECK_OPERAND #undef ASSEMBLE_ONE }