Simplify generate_interpreter.js
This commit is contained in:
parent
bda133ba49
commit
dac9b4591b
|
@ -76,31 +76,17 @@ function gen_call(name, args)
|
|||
return `${name}(${args.join(", ")});`;
|
||||
}
|
||||
|
||||
function gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)
|
||||
{
|
||||
return {
|
||||
type: "if-else",
|
||||
if_blocks: [{
|
||||
condition: "modrm_byte < 0xC0",
|
||||
body: (modrm_resolve_prefix ? [modrm_resolve_prefix] : []).concat(gen_call(`${name}_mem`, mem_args)),
|
||||
}],
|
||||
else_block: {
|
||||
body: [gen_call(`${name}_reg`, reg_args)],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Current naming scheme:
|
||||
* instr(16|32|)_((66|F2|F3)?0F)?[0-9a-f]{2}(_[0-7])?(_mem|_reg|)
|
||||
*/
|
||||
|
||||
function make_instruction_name(encoding, size, prefix_variant)
|
||||
function make_instruction_name(encoding, size)
|
||||
{
|
||||
const suffix = encoding.os ? String(size) : "";
|
||||
const opcode_hex = hex(encoding.opcode & 0xFF, 2);
|
||||
const prefix_0f = (encoding.opcode & 0xFF00) === 0x0F00 ? "0F" : "";
|
||||
const prefix = prefix_variant === undefined ? "" : hex(prefix_variant, 2);
|
||||
const prefix = (encoding.opcode & 0xFF0000) === 0 ? "" : hex(encoding.opcode >> 16 & 0xFF, 2);
|
||||
const fixed_g_suffix = encoding.fixed_g === undefined ? "" : `_${encoding.fixed_g}`;
|
||||
|
||||
return `instr${suffix}_${prefix}${prefix_0f}${opcode_hex}${fixed_g_suffix}`;
|
||||
|
@ -110,26 +96,78 @@ function gen_instruction_body(encodings, size)
|
|||
{
|
||||
const encoding = encodings[0];
|
||||
|
||||
let has_66 = false;
|
||||
let has_F2 = false;
|
||||
let has_F3 = false;
|
||||
let has_66 = [];
|
||||
let has_F2 = [];
|
||||
let has_F3 = [];
|
||||
let no_prefix = [];
|
||||
|
||||
for(let e of encodings)
|
||||
{
|
||||
if((e.opcode >>> 16) === 0x66) has_66 = true;
|
||||
if((e.opcode >>> 16) === 0xF2) has_F2 = true;
|
||||
if((e.opcode >>> 16) === 0xF3) has_F3 = true;
|
||||
if((e.opcode >>> 16) === 0x66) has_66.push(e);
|
||||
else if((e.opcode >>> 16) === 0xF2) has_F2.push(e);
|
||||
else if((e.opcode >>> 16) === 0xF3) has_F3.push(e);
|
||||
else no_prefix.push(e);
|
||||
}
|
||||
|
||||
if(has_66 || has_F2 || has_F3)
|
||||
if(has_66.length || has_F2.length || has_F3.length)
|
||||
{
|
||||
console.assert((encoding.opcode & 0xFF00) === 0x0F00);
|
||||
}
|
||||
|
||||
const instruction_postfix = encoding.block_boundary ? ["after_block_boundary();"] : [];
|
||||
const code = [];
|
||||
|
||||
if(encoding.e)
|
||||
{
|
||||
code.push("int32_t modrm_byte = read_imm8();");
|
||||
}
|
||||
|
||||
if(has_66.length || has_F2.length || has_F3.length)
|
||||
{
|
||||
const if_blocks = [];
|
||||
|
||||
if(has_66.length) {
|
||||
const body = gen_instruction_body_after_prefix(has_66, size);
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
|
||||
}
|
||||
if(has_F2.length) {
|
||||
const body = gen_instruction_body_after_prefix(has_F2, size);
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
|
||||
}
|
||||
if(has_F3.length) {
|
||||
const body = gen_instruction_body_after_prefix(has_F3, size);
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
|
||||
}
|
||||
|
||||
const else_block = {
|
||||
body: gen_instruction_body_after_prefix(no_prefix, size),
|
||||
};
|
||||
|
||||
return [].concat(
|
||||
"int32_t prefixes_ = *prefixes;",
|
||||
code,
|
||||
{
|
||||
type: "if-else",
|
||||
if_blocks,
|
||||
else_block,
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
return [].concat(
|
||||
code,
|
||||
gen_instruction_body_after_prefix(encodings, size)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function gen_instruction_body_after_prefix(encodings, size)
|
||||
{
|
||||
const encoding = encodings[0];
|
||||
|
||||
if(encoding.fixed_g !== undefined)
|
||||
{
|
||||
console.assert(encoding.e);
|
||||
|
||||
// instruction with modrm byte where the middle 3 bits encode the instruction
|
||||
|
||||
// group by opcode without prefix plus middle bits of modrm byte
|
||||
|
@ -141,77 +179,17 @@ function gen_instruction_body(encodings, size)
|
|||
cases = Object.values(cases).sort((e1, e2) => e1.fixed_g - e2.fixed_g);
|
||||
|
||||
return [
|
||||
"int32_t modrm_byte = read_imm8();",
|
||||
{
|
||||
type: "switch",
|
||||
condition: "modrm_byte >> 3 & 7",
|
||||
cases: cases.map(case_ => {
|
||||
const fixed_g = case_.fixed_g;
|
||||
const instruction_name = make_instruction_name(case_, size, undefined);
|
||||
const instruction_postfix = case_.block_boundary ? ["after_block_boundary();"] : [];
|
||||
const body = gen_instruction_body_after_fixed_g(case_, size);
|
||||
|
||||
let modrm_resolve_prefix = undefined;
|
||||
|
||||
if(case_.requires_prefix_call)
|
||||
{
|
||||
modrm_resolve_prefix = gen_call(instruction_name + "_mem_pre");
|
||||
}
|
||||
|
||||
const mem_args = ["modrm_resolve(modrm_byte)"];
|
||||
const reg_args = ["modrm_byte & 7"];
|
||||
|
||||
const imm_read = gen_read_imm_call(case_, size);
|
||||
if(imm_read)
|
||||
{
|
||||
mem_args.push(imm_read);
|
||||
reg_args.push(imm_read);
|
||||
}
|
||||
|
||||
if(has_66 || has_F2 || has_F3)
|
||||
{
|
||||
const if_blocks = [];
|
||||
|
||||
if(has_66) {
|
||||
const name = make_instruction_name(case_, size, 0x66);
|
||||
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
|
||||
}
|
||||
if(has_F2) {
|
||||
const name = make_instruction_name(case_, size, 0xF2);
|
||||
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
|
||||
}
|
||||
if(has_F3) {
|
||||
const name = make_instruction_name(case_, size, 0xF3);
|
||||
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
|
||||
}
|
||||
|
||||
const else_block = {
|
||||
body: [gen_modrm_mem_reg_split(instruction_name, modrm_resolve_prefix, mem_args, reg_args)],
|
||||
};
|
||||
|
||||
return {
|
||||
conditions: [fixed_g],
|
||||
body: [
|
||||
"int32_t prefixes_ = *prefixes;",
|
||||
{
|
||||
type: "if-else",
|
||||
if_blocks,
|
||||
else_block,
|
||||
},
|
||||
].concat(instruction_postfix),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
const body = [gen_modrm_mem_reg_split(instruction_name, modrm_resolve_prefix, mem_args, reg_args)].concat(instruction_postfix);
|
||||
|
||||
return {
|
||||
conditions: [fixed_g],
|
||||
body,
|
||||
};
|
||||
}
|
||||
return {
|
||||
conditions: [fixed_g],
|
||||
body,
|
||||
};
|
||||
}),
|
||||
|
||||
default_case: {
|
||||
|
@ -220,66 +198,24 @@ function gen_instruction_body(encodings, size)
|
|||
"trigger_ud();",
|
||||
],
|
||||
}
|
||||
}
|
||||
].concat(instruction_postfix);
|
||||
},
|
||||
];
|
||||
}
|
||||
else if(has_66 || has_F2 || has_F3)
|
||||
{
|
||||
// instruction without modrm byte but with prefix
|
||||
|
||||
console.assert(encoding.e);
|
||||
console.assert(!encoding.ignore_mod);
|
||||
console.assert(!encoding.requires_prefix_call, "Unexpected instruction (66/f2/f3 with prefix call)");
|
||||
|
||||
const imm_read = gen_read_imm_call(encoding, size);
|
||||
|
||||
const mem_args = ["modrm_resolve(modrm_byte)", "modrm_byte >> 3 & 7"];
|
||||
const reg_args = ["modrm_byte & 7", "modrm_byte >> 3 & 7"];
|
||||
|
||||
if(imm_read)
|
||||
{
|
||||
mem_args.push(imm_read);
|
||||
reg_args.push(imm_read);
|
||||
}
|
||||
|
||||
const if_blocks = [];
|
||||
const modrm_resolve_prefix = undefined;
|
||||
|
||||
if(has_66) {
|
||||
const name = make_instruction_name(encoding, size, 0x66);
|
||||
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
|
||||
}
|
||||
if(has_F2) {
|
||||
const name = make_instruction_name(encoding, size, 0xF2);
|
||||
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
|
||||
}
|
||||
if(has_F3) {
|
||||
const name = make_instruction_name(encoding, size, 0xF3);
|
||||
const body = [gen_modrm_mem_reg_split(name, modrm_resolve_prefix, mem_args, reg_args)];
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
|
||||
}
|
||||
|
||||
const else_block = {
|
||||
body: [gen_modrm_mem_reg_split(make_instruction_name(encoding, size), modrm_resolve_prefix, mem_args, reg_args)],
|
||||
};
|
||||
|
||||
return [
|
||||
"int32_t modrm_byte = read_imm8();",
|
||||
"int32_t prefixes_ = *prefixes;",
|
||||
{
|
||||
type: "if-else",
|
||||
if_blocks,
|
||||
else_block,
|
||||
}
|
||||
].concat(instruction_postfix);
|
||||
}
|
||||
else if(encoding.fixed_g === undefined && encoding.e)
|
||||
{
|
||||
// instruction with modrm byte where the middle 3 bits encode a register
|
||||
|
||||
else {
|
||||
console.assert(encodings.length === 1);
|
||||
return gen_instruction_body_after_fixed_g(encodings[0], size);
|
||||
}
|
||||
}
|
||||
|
||||
function gen_instruction_body_after_fixed_g(encoding, size)
|
||||
{
|
||||
const instruction_postfix = encoding.block_boundary ? ["after_block_boundary();"] : [];
|
||||
const imm_read = gen_read_imm_call(encoding, size);
|
||||
const instruction_name = make_instruction_name(encoding, size);
|
||||
|
||||
if(encoding.e)
|
||||
{
|
||||
// instruction with modrm byte
|
||||
|
||||
const instruction_name = make_instruction_name(encoding, size);
|
||||
|
||||
|
@ -300,15 +236,21 @@ function gen_instruction_body(encodings, size)
|
|||
// Has modrm byte, but the 2 mod bits are ignored and both
|
||||
// operands are always registers (0f20-0f24)
|
||||
|
||||
return [
|
||||
"int32_t modrm_byte = read_imm8();",
|
||||
return [].concat(
|
||||
gen_call(instruction_name, ["modrm_byte & 7", "modrm_byte >> 3 & 7"]),
|
||||
].concat(instruction_postfix);
|
||||
instruction_postfix
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
const mem_args = ["modrm_resolve(modrm_byte)", "modrm_byte >> 3 & 7"];
|
||||
const reg_args = ["modrm_byte & 7", "modrm_byte >> 3 & 7"];
|
||||
const mem_args = ["modrm_resolve(modrm_byte)"];
|
||||
const reg_args = ["modrm_byte & 7"];
|
||||
|
||||
if(encoding.fixed_g === undefined)
|
||||
{
|
||||
mem_args.push("modrm_byte >> 3 & 7");
|
||||
reg_args.push("modrm_byte >> 3 & 7");
|
||||
}
|
||||
|
||||
if(imm_read)
|
||||
{
|
||||
|
@ -316,19 +258,28 @@ function gen_instruction_body(encodings, size)
|
|||
reg_args.push(imm_read);
|
||||
}
|
||||
|
||||
return [
|
||||
"int32_t modrm_byte = read_imm8();",
|
||||
gen_modrm_mem_reg_split(instruction_name, modrm_resolve_prefix, mem_args, reg_args),
|
||||
].concat(instruction_postfix);
|
||||
return [].concat(
|
||||
{
|
||||
type: "if-else",
|
||||
if_blocks: [
|
||||
{
|
||||
condition: "modrm_byte < 0xC0",
|
||||
body: [].concat(
|
||||
modrm_resolve_prefix ? [modrm_resolve_prefix] : [],
|
||||
gen_call(`${instruction_name}_mem`, mem_args)
|
||||
),
|
||||
}
|
||||
],
|
||||
else_block: {
|
||||
body: [gen_call(`${instruction_name}_reg`, reg_args)],
|
||||
},
|
||||
},
|
||||
instruction_postfix
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// instruction without modrm byte or prefix
|
||||
|
||||
const imm_read = gen_read_imm_call(encoding, size);
|
||||
const instruction_name = make_instruction_name(encoding, size);
|
||||
|
||||
const args = [];
|
||||
|
||||
if(imm_read)
|
||||
|
@ -347,7 +298,10 @@ function gen_instruction_body(encodings, size)
|
|||
args.push("read_imm8()");
|
||||
}
|
||||
|
||||
return [gen_call(instruction_name, args)].concat(instruction_postfix);
|
||||
return [].concat(
|
||||
gen_call(instruction_name, args),
|
||||
instruction_postfix
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue