qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jan Bobek <jan.bobek@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Jan Bobek" <jan.bobek@gmail.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Richard Henderson" <richard.henderson@linaro.org>
Subject: [Qemu-devel] [RISU RFC PATCH v2 02/14] risugen_x86_asm: add module
Date: Mon,  1 Jul 2019 00:35:24 -0400	[thread overview]
Message-ID: <20190701043536.26019-3-jan.bobek@gmail.com> (raw)
In-Reply-To: <20190701043536.26019-1-jan.bobek@gmail.com>

The module risugen_x86_asm.pm exports several constants and the
function write_insn, which work in tandem to allow emission of x86
instructions in more clear and structured manner.

Signed-off-by: Jan Bobek <jan.bobek@gmail.com>
---
 risugen_x86_asm.pm | 252 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 252 insertions(+)
 create mode 100644 risugen_x86_asm.pm

diff --git a/risugen_x86_asm.pm b/risugen_x86_asm.pm
new file mode 100644
index 0000000..5640531
--- /dev/null
+++ b/risugen_x86_asm.pm
@@ -0,0 +1,252 @@
+#!/usr/bin/perl -w
+###############################################################################
+# Copyright (c) 2019 Linaro Limited
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     Jan Bobek - initial implementation
+###############################################################################
+
+# risugen_x86_asm -- risugen_x86's helper module for x86 assembly
+package risugen_x86_asm;
+
+use strict;
+use warnings;
+
+use risugen_common;
+
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(
+    write_insn
+    VEX_L_128 VEX_L_256
+    VEX_P_NONE VEX_P_DATA16 VEX_P_REP VEX_P_REPNE
+    VEX_M_0F VEX_M_0F38 VEX_M_0F3A
+    VEX_V_UNUSED
+    REG_EAX REG_ECX REG_EDX REG_EBX REG_ESP REG_EBP REG_ESI REG_EDI
+    MOD_INDIRECT MOD_INDIRECT_DISP8 MOD_INDIRECT_DISP32 MOD_DIRECT
+    X86PFX_DATA16 X86PFX_REPNE X86PFX_REP
+    X86OP_LEA X86OP_XOR X86OP_ALU_imm8 X86OP_MOV X86OP_SAHF X86OP_CALL
+    X86OP_JMP X86OP_UD1 X86OP_VMOVAPS X86OP_MOVAPS
+    );
+
+use constant {
+    VEX_L_128 => 0,
+    VEX_L_256 => 1,
+
+    VEX_P_NONE   => 0b00,
+    VEX_P_DATA16 => 0b01,
+    VEX_P_REP    => 0b10,
+    VEX_P_REPNE  => 0b11,
+
+    VEX_M_0F   => 0b00001,
+    VEX_M_0F38 => 0b00010,
+    VEX_M_0F3A => 0b00011,
+
+    VEX_V_UNUSED => 0b1111,
+
+    REG_EAX => 0,
+    REG_ECX => 1,
+    REG_EDX => 2,
+    REG_EBX => 3,
+    REG_ESP => 4,
+    REG_EBP => 5,
+    REG_ESI => 6,
+    REG_EDI => 7,
+
+    MOD_INDIRECT        => 0b00,
+    MOD_INDIRECT_DISP8  => 0b01,
+    MOD_INDIRECT_DISP32 => 0b10,
+    MOD_DIRECT          => 0b11,
+
+    X86PFX_DATA16 => {value => 0x66, len => 1},
+    X86PFX_REPNE  => {value => 0xF2, len => 1},
+    X86PFX_REP    => {value => 0xF3, len => 1},
+
+    X86OP_LEA      => {value => 0x8D, len => 1},
+    X86OP_XOR      => {value => 0x33, len => 1},
+    X86OP_ALU_imm8 => {value => 0x83, len => 1},
+    X86OP_MOV      => {value => 0x8B, len => 1},
+    X86OP_SAHF     => {value => 0x9E, len => 1},
+    X86OP_CALL     => {value => 0xE8, len => 1},
+    X86OP_JMP      => {value => 0xE9, len => 1},
+
+    X86OP_UD1      => {value => 0x0FB9, len => 2},
+    X86OP_VMOVAPS  => {value => 0x28, len => 1},
+    X86OP_MOVAPS   => {value => 0x0F28, len => 2},
+};
+
+sub rex_encode(%)
+{
+    my (%args) = @_;
+
+    $args{w} = 0 unless defined $args{w};
+    $args{r} = 0 unless defined $args{r};
+    $args{x} = 0 unless defined $args{x};
+    $args{b} = 0 unless defined $args{b};
+
+    return (value => 0x40
+            | (($args{w} ? 1 : 0) << 3)
+            | (($args{r} ? 1 : 0) << 2)
+            | (($args{x} ? 1 : 0) << 1)
+            | ($args{b} ? 1 : 0),
+            len => 1);
+}
+
+sub vex_encode(%)
+{
+    my (%args) = @_;
+
+    $args{r} = 1 unless defined $args{r};
+    $args{x} = 1 unless defined $args{x};
+    $args{b} = 1 unless defined $args{b};
+    $args{v} = VEX_V_UNUSED unless defined $args{v};
+    $args{p} = VEX_P_NONE unless defined $args{p};
+
+    die "l field undefined"
+        unless defined $args{l};
+    die "v field out-of-range: $args{v}"
+        unless 0b0000 <= $args{v} && $args{v} <= 0b1111;
+    die "p field out-of-range: $args{p}"
+        unless 0b00 <= $args{p} && $args{p} <= 0b11;
+
+    if ($args{x} && $args{b} && !defined $args{m} && !defined $args{w}) {
+        # We can use the 2-byte VEX prefix
+        return (value => (0xC5 << 8)
+                | (($args{r} ? 1 : 0) << 7)
+                | ($args{v} << 3)
+                | (($args{l} ? 1 : 0) << 2)
+                | $args{p},
+                len => 2);
+    } else {
+        # We have to use the 3-byte VEX prefix
+        die "m field undefined"
+            unless defined $args{m};
+        die "m field out-of-range: $args{m}"
+            unless 0b00000 <= $args{m} && $args{m} <= 0b11111;
+        die "w field undefined"
+            unless defined $args{w};
+
+        return (value => (0xC4 << 16)
+                | (($args{r} ? 1 : 0) << 15)
+                | (($args{x} ? 1 : 0) << 14)
+                | (($args{b} ? 1 : 0) << 13)
+                | ($args{m} << 8)
+                | (($args{w} ? 1 : 0) << 7)
+                | ($args{v} << 3)
+                | (($args{l} ? 1 : 0) << 2)
+                | $args{p},
+                len => 3);
+    }
+}
+
+sub modrm_encode(%)
+{
+    my (%args) = @_;
+
+    die "MOD field out-of-range: $args{mod}"
+        unless 0 <= $args{mod} && $args{mod} <= 3;
+    die "REG field out-of-range: $args{reg}"
+        unless 0 <= $args{reg} && $args{reg} <= 7;
+    die "RM field out-of-range: $args{rm}"
+        unless 0 <= $args{rm} && $args{rm} <= 7;
+
+    return (value =>
+            ($args{mod} << 6)
+            | ($args{reg} << 3)
+            | $args{rm},
+            len => 1);
+}
+
+sub sib_encode(%)
+{
+    my (%args) = @_;
+
+    die "SS field out-of-range: $args{ss}"
+        unless 0 <= $args{ss} && $args{ss} <= 3;
+    die "INDEX field out-of-range: $args{index}"
+        unless 0 <= $args{index} && $args{index} <= 7;
+    die "BASE field out-of-range: $args{base}"
+        unless 0 <= $args{base} && $args{base} <= 7;
+
+    return (value =>
+            ($args{ss} << 6)
+            | ($args{index} << 3)
+            | $args{base},
+            len => 1);
+}
+
+sub write_insn(%)
+{
+    my (%insn) = @_;
+
+    my @tokens;
+    push @tokens, "EVEX"   if defined $insn{evex};
+    push @tokens, "VEX"    if defined $insn{vex};
+    push @tokens, "REP"    if defined $insn{rep};
+    push @tokens, "REPNE"  if defined $insn{repne};
+    push @tokens, "DATA16" if defined $insn{data16};
+    push @tokens, "REX"    if defined $insn{rex};
+    push @tokens, "OP"     if defined $insn{opcode};
+    push @tokens, "MODRM"  if defined $insn{modrm};
+    push @tokens, "SIB"    if defined $insn{sib};
+    push @tokens, "DISP"   if defined $insn{disp};
+    push @tokens, "IMM"    if defined $insn{imm};
+    push @tokens, "END";
+
+    # (EVEX | VEX | ((REP | REPNE)? DATA16? REX?)) OP (MODRM SIB? DISP?)? IMM? END
+
+    my $token = shift @tokens;
+    if ($token eq "EVEX") {
+        insnv(evex_encode(%{$insn{evex}}));
+        $token = shift @tokens;
+    } elsif ($token eq "VEX") {
+        insnv(vex_encode(%{$insn{vex}}));
+        $token = shift @tokens;
+    } else {
+        if ($token eq "REP") {
+            insnv(%{&X86PFX_REP});
+            $token = shift @tokens;
+        } elsif ($token eq "REPNE") {
+            insnv(%{&X86PFX_REPNE});
+            $token = shift @tokens;
+        }
+        if ($token eq "DATA16") {
+            insnv(%{&X86PFX_DATA16});
+            $token = shift @tokens;
+        }
+        if ($token eq "REX") {
+            insnv(rex_encode(%{$insn{rex}}));
+            $token = shift @tokens;
+        }
+    }
+
+    die "Unexpected instruction tokens where OP expected: $token @tokens\n"
+        unless $token eq "OP";
+
+    insnv(%{$insn{opcode}});
+    $token = shift @tokens;
+
+    if ($token eq "MODRM") {
+        insnv(modrm_encode(%{$insn{modrm}}));
+        $token = shift @tokens;
+
+        if ($token eq "SIB") {
+            insnv(sib_encode(%{$insn{sib}}));
+            $token = shift @tokens;
+        }
+        if ($token eq "DISP") {
+            insnv(%{$insn{disp}}, bigendian => 0);
+            $token = shift @tokens;
+        }
+    }
+    if ($token eq "IMM") {
+        insnv(%{$insn{imm}}, bigendian => 0);
+        $token = shift @tokens;
+    }
+
+    die "Unexpected junk tokens at the end of instruction: $token @tokens\n"
+        unless $token eq "END";
+}
-- 
2.20.1



  parent reply	other threads:[~2019-07-01  4:37 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-01  4:35 [Qemu-devel] [RISU RFC PATCH v2 00/14] Support for generating x86 MMX/SSE/AVX test images Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 01/14] risugen_common: add insnv, randint_constr, rand_fill Jan Bobek
2019-07-03 15:22   ` Richard Henderson
2019-07-10 17:48     ` Jan Bobek
2019-07-01  4:35 ` Jan Bobek [this message]
2019-07-03 15:37   ` [Qemu-devel] [RISU RFC PATCH v2 02/14] risugen_x86_asm: add module Richard Henderson
2019-07-10 18:02     ` Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 03/14] risugen_x86_emit: " Jan Bobek
2019-07-03 15:47   ` Richard Henderson
2019-07-10 18:08     ` Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 04/14] risugen_x86: " Jan Bobek
2019-07-03 16:11   ` Richard Henderson
2019-07-10 18:21     ` Jan Bobek
2019-07-11  9:26       ` Richard Henderson
2019-07-11 13:10         ` Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 05/14] risugen: allow all byte-aligned instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 06/14] x86.risu: add MMX instructions Jan Bobek
2019-07-03 21:35   ` Richard Henderson
2019-07-10 18:29     ` Jan Bobek
2019-07-11  9:32       ` Richard Henderson
2019-07-11 13:29         ` Jan Bobek
2019-07-11 13:57           ` Richard Henderson
2019-07-11 21:29             ` Jan Bobek
2019-07-03 21:49   ` Richard Henderson
2019-07-10 18:32     ` Jan Bobek
2019-07-11  9:34       ` Richard Henderson
2019-07-11  9:44         ` Alex Bennée
2019-07-03 22:01   ` Peter Maydell
2019-07-10 18:35     ` Jan Bobek
2019-07-11  6:45       ` Alex Bennée
2019-07-11 13:33         ` Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 07/14] x86.risu: add SSE instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 08/14] x86.risu: add SSE2 instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 09/14] x86.risu: add SSE3 instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 10/14] x86.risu: add SSSE3 instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 11/14] x86.risu: add SSE4.1 and SSE4.2 instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 13/14] x86.risu: add AVX instructions Jan Bobek
2019-07-01  4:35 ` [Qemu-devel] [RISU RFC PATCH v2 14/14] x86.risu: add AVX2 instructions Jan Bobek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190701043536.26019-3-jan.bobek@gmail.com \
    --to=jan.bobek@gmail.com \
    --cc=alex.bennee@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).