687 lines
28 KiB
C
687 lines
28 KiB
C
#include "asm.h"
|
|
#include "eval.h"
|
|
#include "parse.h"
|
|
#include "report.h"
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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
|
|
}
|