mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-02-17 17:19:35 +08:00
insns: drop special handling of conditional instructions
Instead of handling conditional instructions ad hoc, generate individual instruction patterns as normal. This simplifies the code and makes CMPccXADD support simpler (otherwise it would be necessary to hack in the handling of a condition code in the middle of an instruction.) Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
5fd5426832
commit
a2eabbe1d7
@ -304,17 +304,17 @@ doc/warnings.src : doc/warnings.src.time
|
||||
@: Side effect
|
||||
|
||||
# Assembler token hash
|
||||
asm/tokhash.c: x86/insns.dat x86/regs.dat asm/tokens.dat asm/tokhash.pl \
|
||||
asm/tokhash.c: x86/insns.dat x86/insnsn.c asm/tokens.dat asm/tokhash.pl \
|
||||
perllib/phash.ph
|
||||
$(RUNPERL) $(srcdir)/asm/tokhash.pl c \
|
||||
$(srcdir)/x86/insns.dat $(srcdir)/x86/regs.dat \
|
||||
x86/insnsn.c $(srcdir)/x86/regs.dat \
|
||||
$(srcdir)/asm/tokens.dat > asm/tokhash.c
|
||||
|
||||
# Assembler token metadata
|
||||
asm/tokens.h: x86/insns.dat x86/regs.dat asm/tokens.dat asm/tokhash.pl \
|
||||
asm/tokens.h: x86/insns.dat x86/insnsn.c asm/tokens.dat asm/tokhash.pl \
|
||||
perllib/phash.ph
|
||||
$(RUNPERL) $(srcdir)/asm/tokhash.pl h \
|
||||
$(srcdir)/x86/insns.dat $(srcdir)/x86/regs.dat \
|
||||
x86/insnsn.c $(srcdir)/x86/regs.dat \
|
||||
$(srcdir)/asm/tokens.dat > asm/tokens.h
|
||||
|
||||
# Preprocessor token hash
|
||||
|
@ -234,7 +234,7 @@ x86\regs.h: x86\regs.dat x86\regs.pl
|
||||
WARNFILES = asm\warnings.c include\warnings.h doc\warnings.src
|
||||
|
||||
warnings:
|
||||
$(RM_F) $(WARNFILES)
|
||||
$(RM_F) $(WARNFILES) $(WARNFILES:=.time)
|
||||
$(MAKE) asm\warnings.time
|
||||
|
||||
asm\warnings.time: $(ALLOBJ_NW:.$(O)=.c)
|
||||
@ -263,17 +263,17 @@ doc\warnings.src : doc\warnings.src.time
|
||||
@: Side effect
|
||||
|
||||
# Assembler token hash
|
||||
asm\tokhash.c: x86\insns.dat x86\regs.dat asm\tokens.dat asm\tokhash.pl \
|
||||
asm\tokhash.c: x86\insns.dat x86\insnsn.c asm\tokens.dat asm\tokhash.pl \
|
||||
perllib\phash.ph
|
||||
$(RUNPERL) $(srcdir)\asm\tokhash.pl c \
|
||||
$(srcdir)\x86\insns.dat $(srcdir)\x86\regs.dat \
|
||||
x86\insnsn.c $(srcdir)\x86\regs.dat \
|
||||
$(srcdir)\asm\tokens.dat > asm\tokhash.c
|
||||
|
||||
# Assembler token metadata
|
||||
asm\tokens.h: x86\insns.dat x86\regs.dat asm\tokens.dat asm\tokhash.pl \
|
||||
asm\tokens.h: x86\insns.dat x86\insnsn.c asm\tokens.dat asm\tokhash.pl \
|
||||
perllib\phash.ph
|
||||
$(RUNPERL) $(srcdir)\asm\tokhash.pl h \
|
||||
$(srcdir)\x86\insns.dat $(srcdir)\x86\regs.dat \
|
||||
x86\insnsn.c $(srcdir)\x86\regs.dat \
|
||||
$(srcdir)\asm\tokens.dat > asm\tokens.h
|
||||
|
||||
# Preprocessor token hash
|
||||
|
@ -247,7 +247,7 @@ x86\regs.h: x86\regs.dat x86\regs.pl
|
||||
WARNFILES = asm\warnings.c include\warnings.h doc\warnings.src
|
||||
|
||||
warnings:
|
||||
$(RM_F) $(WARNFILES)
|
||||
$(RM_F) $(WARNFILES) $(WARNFILES:=.time)
|
||||
$(MAKE) asm\warnings.time
|
||||
|
||||
asm\warnings.time: $(ALLOBJ_NW:.$(O)=.c)
|
||||
@ -276,17 +276,17 @@ doc\warnings.src : doc\warnings.src.time
|
||||
@: Side effect
|
||||
|
||||
# Assembler token hash
|
||||
asm\tokhash.c: x86\insns.dat x86\regs.dat asm\tokens.dat asm\tokhash.pl &
|
||||
asm\tokhash.c: x86\insns.dat x86\insnsn.c asm\tokens.dat asm\tokhash.pl &
|
||||
perllib\phash.ph
|
||||
$(RUNPERL) $(srcdir)\asm\tokhash.pl c &
|
||||
$(srcdir)\x86\insns.dat $(srcdir)\x86\regs.dat &
|
||||
x86\insnsn.c $(srcdir)\x86\regs.dat &
|
||||
$(srcdir)\asm\tokens.dat > asm\tokhash.c
|
||||
|
||||
# Assembler token metadata
|
||||
asm\tokens.h: x86\insns.dat x86\regs.dat asm\tokens.dat asm\tokhash.pl &
|
||||
asm\tokens.h: x86\insns.dat x86\insnsn.c asm\tokens.dat asm\tokhash.pl &
|
||||
perllib\phash.ph
|
||||
$(RUNPERL) $(srcdir)\asm\tokhash.pl h &
|
||||
$(srcdir)\x86\insns.dat $(srcdir)\x86\regs.dat &
|
||||
x86\insnsn.c $(srcdir)\x86\regs.dat &
|
||||
$(srcdir)\asm\tokens.dat > asm\tokens.h
|
||||
|
||||
# Preprocessor token hash
|
||||
|
@ -146,8 +146,6 @@
|
||||
* \325 nohi instruction which always uses spl/bpl/sil/dil
|
||||
* \326 nof3 instruction not valid with 0xF3 REP prefix. Hint for
|
||||
disassembler only; for SSE instructions.
|
||||
* \330 a literal byte follows in the code stream, to be added
|
||||
* to the condition code value of the instruction.
|
||||
* \331 norep instruction not valid with REP prefix. Hint for
|
||||
* disassembler only; for SSE instructions.
|
||||
* \332 f2i REP prefix (0xF2 byte) used as opcode extension.
|
||||
@ -1472,10 +1470,6 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
|
||||
case 0326:
|
||||
break;
|
||||
|
||||
case 0330:
|
||||
codes++, length++;
|
||||
break;
|
||||
|
||||
case 0331:
|
||||
break;
|
||||
|
||||
@ -2188,10 +2182,6 @@ static void gencode(struct out_data *data, insn *ins)
|
||||
case 0326:
|
||||
break;
|
||||
|
||||
case 0330:
|
||||
out_rawbyte(data, *codes++ ^ get_cond_opcode(ins->condition));
|
||||
break;
|
||||
|
||||
case 0331:
|
||||
break;
|
||||
|
||||
|
@ -748,7 +748,6 @@ restart_parse:
|
||||
}
|
||||
|
||||
result->opcode = tokval.t_integer;
|
||||
result->condition = tokval.t_inttwo;
|
||||
|
||||
/*
|
||||
* INCBIN cannot be satisfied with incorrectly
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
require 'phash.ph';
|
||||
|
||||
my($output, $insns_dat, $regs_dat, $tokens_dat) = @ARGV;
|
||||
my($output, $insnsn_c, $regs_dat, $tokens_dat) = @ARGV;
|
||||
|
||||
%tokens = ();
|
||||
@tokendata = ();
|
||||
@ -53,33 +53,18 @@ my($output, $insns_dat, $regs_dat, $tokens_dat) = @ARGV;
|
||||
'nle', 'no', 'np', 'ns', 'nz', 'o', 'p', 'pe', 'po', 's', 'z');
|
||||
|
||||
#
|
||||
# Read insns.dat
|
||||
# Read insnsn.c
|
||||
#
|
||||
open(ID, '<', $insns_dat) or die "$0: cannot open $insns_dat: $!\n";
|
||||
open(ID, '<', $insnsn_c) or die "$0: cannot open $insnsn_c: $!\n";
|
||||
while (defined($line = <ID>)) {
|
||||
if ($line =~ /^([\?\@A-Z0-9_]+)(|cc)\s/) {
|
||||
$insn = $1.$2;
|
||||
($token = $1) =~ tr/A-Z/a-z/;
|
||||
next unless ($line =~ /^\s*\"([\?\@a-z0-9_]+)\"/);
|
||||
|
||||
if ($2 eq '') {
|
||||
# Single instruction token
|
||||
if (!defined($tokens{$token})) {
|
||||
$tokens{$token} = scalar @tokendata;
|
||||
push(@tokendata, "\"${token}\", ".length($token).
|
||||
", TOKEN_INSN, C_none, 0, I_${insn}");
|
||||
}
|
||||
} else {
|
||||
# Conditional instruction
|
||||
foreach $cc (@conditions) {
|
||||
my $etok = $token.$cc;
|
||||
if (!defined($tokens{$etok})) {
|
||||
$tokens{$etok} = scalar @tokendata;
|
||||
push(@tokendata, "\"${etok}\", ".length($etok).
|
||||
", TOKEN_INSN, C_\U$cc\E, 0, I_${insn}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
my $token = $1;
|
||||
next if (defined($tokens{$token})); # This should never happen
|
||||
|
||||
$tokens{$token} = scalar @tokendata;
|
||||
push(@tokendata, "\"${token}\", ".length($token).
|
||||
", TOKEN_INSN, 0, 0, I_\U${token}");
|
||||
}
|
||||
close(ID);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* ----------------------------------------------------------------------- *
|
||||
*
|
||||
* Copyright 1996-2012 The NASM Authors - All Rights Reserved
|
||||
* Copyright 1996-2022 The NASM Authors - All Rights Reserved
|
||||
* See the file AUTHORS included with the NASM distribution for
|
||||
* the specific copyright holders.
|
||||
*
|
||||
@ -506,7 +506,6 @@ static int matches(const struct itemplate *t, uint8_t *data,
|
||||
ins->oprs[i].segment = ins->oprs[i].disp_size =
|
||||
(segsize == 64 ? SEG_64BIT : segsize == 32 ? SEG_32BIT : 0);
|
||||
}
|
||||
ins->condition = -1;
|
||||
ins->evex_tuple = 0;
|
||||
ins->rex = prefix->rex;
|
||||
memset(ins->prefixes, 0, sizeof ins->prefixes);
|
||||
@ -957,16 +956,6 @@ static int matches(const struct itemplate *t, uint8_t *data,
|
||||
ins->rex |= REX_NH;
|
||||
break;
|
||||
|
||||
case 0330:
|
||||
{
|
||||
int t = *r++, d = *data++;
|
||||
if (d < t || d > t + 15)
|
||||
return 0;
|
||||
else
|
||||
ins->condition = d - t;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0326:
|
||||
if (prefix->rep == 0xF3)
|
||||
return 0;
|
||||
@ -1126,12 +1115,6 @@ static int matches(const struct itemplate *t, uint8_t *data,
|
||||
return data - origdata;
|
||||
}
|
||||
|
||||
/* Condition names for disassembly, sorted by x86 code */
|
||||
static const char * const condition_name[16] = {
|
||||
"o", "no", "c", "nc", "z", "nz", "na", "a",
|
||||
"s", "ns", "pe", "po", "l", "nl", "ng", "g"
|
||||
};
|
||||
|
||||
int32_t disasm(uint8_t *data, int32_t data_size, char *output, int outbufsize, int segsize,
|
||||
int64_t offset, int autosync, iflag_t *prefer)
|
||||
{
|
||||
@ -1424,12 +1407,8 @@ int32_t disasm(uint8_t *data, int32_t data_size, char *output, int outbufsize, i
|
||||
}
|
||||
|
||||
i = (*p)->opcode;
|
||||
if (i >= FIRST_COND_OPCODE)
|
||||
slen += snprintf(output + slen, outbufsize - slen, "%s%s",
|
||||
nasm_insn_names[i], condition_name[ins.condition]);
|
||||
else
|
||||
slen += snprintf(output + slen, outbufsize - slen, "%s",
|
||||
nasm_insn_names[i]);
|
||||
slen += snprintf(output + slen, outbufsize - slen, "%s",
|
||||
nasm_insn_names[i]);
|
||||
|
||||
colon = false;
|
||||
is_evex = !!(ins.rex & REX_EV);
|
||||
|
@ -523,13 +523,6 @@ static inline bool is_register(int reg)
|
||||
return reg >= EXPR_REG_START && reg < REG_ENUM_LIMIT;
|
||||
}
|
||||
|
||||
enum ccode { /* condition code names */
|
||||
C_A, C_AE, C_B, C_BE, C_C, C_E, C_G, C_GE, C_L, C_LE, C_NA, C_NAE,
|
||||
C_NB, C_NBE, C_NC, C_NE, C_NG, C_NGE, C_NL, C_NLE, C_NO, C_NP,
|
||||
C_NS, C_NZ, C_O, C_P, C_PE, C_PO, C_S, C_Z,
|
||||
C_none = -1
|
||||
};
|
||||
|
||||
/*
|
||||
* token flags
|
||||
*/
|
||||
@ -540,17 +533,6 @@ enum ccode { /* condition code names */
|
||||
#define TFLAG_WARN (1 << 3) /* warning only, treat as ID */
|
||||
#define TFLAG_DUP (1 << 4) /* valid ID but also has context-specific use */
|
||||
|
||||
static inline uint8_t get_cond_opcode(enum ccode c)
|
||||
{
|
||||
static const uint8_t ccode_opcodes[] = {
|
||||
0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xf, 0xd, 0xc, 0xe, 0x6, 0x2,
|
||||
0x3, 0x7, 0x3, 0x5, 0xe, 0xc, 0xd, 0xf, 0x1, 0xb, 0x9, 0x5,
|
||||
0x0, 0xa, 0xa, 0xb, 0x8, 0x4
|
||||
};
|
||||
|
||||
return ccode_opcodes[(int)c];
|
||||
}
|
||||
|
||||
/*
|
||||
* REX flags
|
||||
*/
|
||||
@ -766,7 +748,6 @@ typedef struct insn { /* an instruction itself */
|
||||
char *label; /* the label defined, or NULL */
|
||||
int prefixes[MAXPREFIX]; /* instruction prefixes, if any */
|
||||
enum opcode opcode; /* the opcode - not just the string */
|
||||
enum ccode condition; /* the condition code, if Jcc/SETcc */
|
||||
int operands; /* how many operands? 0-3 (more if db et al) */
|
||||
int addr_size; /* address size */
|
||||
operand oprs[MAX_OPERANDS]; /* the operands, defined as above */
|
||||
|
@ -98,8 +98,10 @@ if_("AMXTILE", "AMX tile configuration instructions");
|
||||
if_("AMXBF16", "AMX bfloat16 multiplication");
|
||||
if_("AMXINT8", "AMX 8-bit integer multiplication");
|
||||
if_("FRED", "Flexible Return and Exception Delivery (FRED)");
|
||||
if_("RAOINT", "Remote atomic operations (RAO-INT)");
|
||||
if_("UINTR", "User interrupts");
|
||||
|
||||
# Put these last [hpa: why?]
|
||||
# Put these last to minimize their relevance
|
||||
if_("OBSOLETE", "Instruction removed from architecture");
|
||||
if_("NEVER", "Instruction never implemented");
|
||||
if_("NOP", "Instruction is always a (nonintentional) NOP");
|
||||
|
238
x86/insns.pl
238
x86/insns.pl
@ -59,10 +59,115 @@ for ($c = 0; $c < $vex_classes; $c++) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@disasm_prefixes = (@vexlist, @disasm_prefixes);
|
||||
@disasm_prefixes = (@vexlist, @disasm_prefixes, '');
|
||||
%disasm_prefixes = map { $_ => 1 } @disasm_prefixes;
|
||||
|
||||
@bytecode_count = (0) x 256;
|
||||
|
||||
# Push to an array reference, creating the array if needed
|
||||
sub xpush($@) {
|
||||
my $ref = shift @_;
|
||||
|
||||
$$ref = [] unless (defined($$ref));
|
||||
return push(@$$ref, @_);
|
||||
}
|
||||
|
||||
# Generate relaxed form patterns if applicable
|
||||
sub relaxed_forms(@) {
|
||||
my @field_list = @_;
|
||||
|
||||
foreach my $fields (@_) {
|
||||
next unless ($fields->[1] =~ /\*/);
|
||||
|
||||
# This instruction has relaxed form(s)
|
||||
if ($fields->[2] !~ /^\[/) {
|
||||
warn "$fname:$line: has an * operand but uses raw bytecodes\n";
|
||||
next;
|
||||
}
|
||||
|
||||
my $opmask = 0;
|
||||
my @ops = split(/,/, $fields->[1]);
|
||||
for (my $oi = 0; $oi < scalar @ops; $oi++) {
|
||||
if ($ops[$oi] =~ /\*$/) {
|
||||
if ($oi == 0) {
|
||||
warn "$fname:$line: has a first operand with a *\n";
|
||||
next;
|
||||
}
|
||||
$opmask |= 1 << $oi;
|
||||
}
|
||||
}
|
||||
|
||||
for (my $oi = 1; $oi < (1 << scalar @ops); $oi++) {
|
||||
if (($oi & ~$opmask) == 0) {
|
||||
my @xops = ();
|
||||
my $omask = ~$oi;
|
||||
for ($oj = 0; $oj < scalar(@ops); $oj++) {
|
||||
if ($omask & 1) {
|
||||
push(@xops, $ops[$oj]);
|
||||
}
|
||||
$omask >>= 1;
|
||||
}
|
||||
my @ff = @$fields;
|
||||
$ff[1] = join(',', @xops);
|
||||
$ff[4] = $oi;
|
||||
push(@field_list, [@ff]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @field_list;
|
||||
}
|
||||
|
||||
# Condition codes used by the disassembler
|
||||
my %condd = ( 'o' => 0, 'no' => 1, 'c' => 2, 'nc' => 3,
|
||||
'z' => 4, 'nz' => 5, 'na' => 6, 'a' => 7,
|
||||
's' => 8, 'ns' => 9, 'pe' => 10, 'po' => 11,
|
||||
'l' => 12, 'nl' => 13, 'ng' => 14, 'g' => 15 );
|
||||
|
||||
# All condition code aliases
|
||||
my %conds = ( %condd,
|
||||
'ae' => 3, 'b' => 2, 'be' => 6, 'e' => 4,
|
||||
'ge' => 13, 'le' => 14, 'nae' => 2, 'nb' => 3,
|
||||
'nbe' => 7, 'ne' => 5, 'nge' => 12, 'nle' => 15,
|
||||
'np' => 11, 'p' => 10 );
|
||||
|
||||
# Generate conditional form patterns if applicable
|
||||
sub conditional_forms(@) {
|
||||
my @field_list = ();
|
||||
|
||||
foreach my $fields (@_) {
|
||||
# This is a case sensitive match!
|
||||
if ($fields->[0] !~ /cc/) {
|
||||
push(@field_list, $fields);
|
||||
next;
|
||||
}
|
||||
|
||||
if ($fields->[2] !~ /^\[/) {
|
||||
warn "$fname:$line: conditional instruction using raw bytecodes\n";
|
||||
next;
|
||||
}
|
||||
|
||||
foreach my $cc (keys(%conds)) {
|
||||
my @ff = @$fields;
|
||||
|
||||
$ff[0] =~ s/cc/\U$cc/;
|
||||
|
||||
unless ($ff[2] =~ /^(\[.*?)\b([0-9a-f]{2})\+c\b(.*\])$/) {
|
||||
warn "$fname:$line: invalid conditional encoding";
|
||||
next;
|
||||
}
|
||||
|
||||
$ff[2] = $1.sprintf('%02x', hex($2)^$conds{$cc}).$3;
|
||||
unless (defined($condd{$cc}) || $ff[3] =~ /\bND\b/) {
|
||||
$ff[3] .= ',ND';
|
||||
}
|
||||
|
||||
push(@field_list, [@ff]);
|
||||
}
|
||||
}
|
||||
return @field_list;
|
||||
}
|
||||
|
||||
print STDERR "Reading insns.dat...\n";
|
||||
|
||||
@args = ();
|
||||
@ -86,10 +191,13 @@ open(F, '<', $fname) || die "unable to open $fname";
|
||||
|
||||
%dinstables = ();
|
||||
@bytecode_list = ();
|
||||
%aname = ();
|
||||
|
||||
$line = 0;
|
||||
$insns = 0;
|
||||
$n_opcodes = $n_opcodes_cc = 0;
|
||||
$n_opcodes = 0;
|
||||
my @allpatterns = ();
|
||||
|
||||
while (<F>) {
|
||||
$line++;
|
||||
chomp;
|
||||
@ -99,71 +207,24 @@ while (<F>) {
|
||||
warn "line $line does not contain four fields\n";
|
||||
next;
|
||||
}
|
||||
@fields = ($1, $2, $3, $4);
|
||||
@field_list = ([@fields, 0]);
|
||||
my @field_list = ([$1, $2, $3, $4, 0]);
|
||||
@field_list = relaxed_forms(@field_list);
|
||||
@field_list = conditional_forms(@field_list);
|
||||
|
||||
if ($fields[1] =~ /\*/) {
|
||||
# This instruction has relaxed form(s)
|
||||
if ($fields[2] !~ /^\[/) {
|
||||
warn "line $line has an * operand but uses raw bytecodes\n";
|
||||
next;
|
||||
}
|
||||
|
||||
$opmask = 0;
|
||||
@ops = split(/,/, $fields[1]);
|
||||
for ($oi = 0; $oi < scalar @ops; $oi++) {
|
||||
if ($ops[$oi] =~ /\*$/) {
|
||||
if ($oi == 0) {
|
||||
warn "line $line has a first operand with a *\n";
|
||||
next;
|
||||
}
|
||||
$opmask |= 1 << $oi;
|
||||
}
|
||||
}
|
||||
|
||||
for ($oi = 1; $oi < (1 << scalar @ops); $oi++) {
|
||||
if (($oi & ~$opmask) == 0) {
|
||||
my @xops = ();
|
||||
my $omask = ~$oi;
|
||||
for ($oj = 0; $oj < scalar(@ops); $oj++) {
|
||||
if ($omask & 1) {
|
||||
push(@xops, $ops[$oj]);
|
||||
}
|
||||
$omask >>= 1;
|
||||
}
|
||||
push(@field_list, [$fields[0], join(',', @xops),
|
||||
$fields[2], $fields[3], $oi]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach $fptr (@field_list) {
|
||||
@fields = @$fptr;
|
||||
($formatted, $nd) = format_insn(@fields);
|
||||
foreach my $fields (@field_list) {
|
||||
($formatted, $nd) = format_insn(@$fields);
|
||||
if ($formatted) {
|
||||
$insns++;
|
||||
$aname = "aa_$fields[0]";
|
||||
push @$aname, $formatted;
|
||||
}
|
||||
if ( $fields[0] =~ /cc$/ ) {
|
||||
# Conditional instruction
|
||||
if (!defined($k_opcodes_cc{$fields[0]})) {
|
||||
$k_opcodes_cc{$fields[0]} = $n_opcodes_cc++;
|
||||
}
|
||||
} else {
|
||||
# Unconditional instruction
|
||||
if (!defined($k_opcodes{$fields[0]})) {
|
||||
$k_opcodes{$fields[0]} = $n_opcodes++;
|
||||
}
|
||||
xpush(\$aname{$fields->[0]}, $formatted);
|
||||
}
|
||||
if (!defined($k_opcodes{$fields->[0]})) {
|
||||
$k_opcodes{$fields->[0]} = $n_opcodes++;
|
||||
}
|
||||
if ($formatted && !$nd) {
|
||||
push @big, $formatted;
|
||||
my @sseq = startseq($fields[2], $fields[4]);
|
||||
foreach $i (@sseq) {
|
||||
if (!defined($dinstables{$i})) {
|
||||
$dinstables{$i} = [];
|
||||
}
|
||||
push(@{$dinstables{$i}}, $#big);
|
||||
my @sseq = startseq($fields->[2], $fields->[4]);
|
||||
foreach my $i (@sseq) {
|
||||
xpush(\$dinstables{$i}, $#big);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,8 +255,7 @@ foreach $bl (@bytecode_list) {
|
||||
}
|
||||
undef @bytecode_list;
|
||||
|
||||
@opcodes = sort { $k_opcodes{$a} <=> $k_opcodes{$b} } keys(%k_opcodes);
|
||||
@opcodes_cc = sort { $k_opcodes_cc{$a} <=> $k_opcodes_cc{$b} } keys(%k_opcodes_cc);
|
||||
@opcodes = sort { $k_opcodes{$a} <=> $k_opcodes{$b} } keys(%k_opcodes);
|
||||
|
||||
if ( $output eq 'b') {
|
||||
print STDERR "Writing $oname...\n";
|
||||
@ -249,16 +309,15 @@ if ( $output eq 'a' ) {
|
||||
print A "#include \"nasm.h\"\n";
|
||||
print A "#include \"insns.h\"\n\n";
|
||||
|
||||
foreach $i (@opcodes, @opcodes_cc) {
|
||||
foreach $i (@opcodes) {
|
||||
print A "static const struct itemplate instrux_${i}[] = {\n";
|
||||
$aname = "aa_$i";
|
||||
foreach $j (@$aname) {
|
||||
foreach $j (@{$aname{$i}}) {
|
||||
print A " ", codesubst($j), "\n";
|
||||
}
|
||||
print A " ITEMPLATE_END\n};\n\n";
|
||||
}
|
||||
print A "const struct itemplate * const nasm_instructions[] = {\n";
|
||||
foreach $i (@opcodes, @opcodes_cc) {
|
||||
foreach $i (@opcodes) {
|
||||
print A " instrux_${i},\n";
|
||||
}
|
||||
print A "};\n";
|
||||
@ -286,7 +345,7 @@ if ( $output eq 'd' ) {
|
||||
|
||||
foreach $h (sort(keys(%dinstables))) {
|
||||
next if ($h eq ''); # Skip pseudo-instructions
|
||||
print D "\nstatic const struct itemplate * const itable_${h}[] = {\n";
|
||||
print D "\nstatic const struct itemplate * const itable_${h}[] = {\n";
|
||||
foreach $j (@{$dinstables{$h}}) {
|
||||
print D " instrux + $j,\n";
|
||||
}
|
||||
@ -294,7 +353,7 @@ if ( $output eq 'd' ) {
|
||||
}
|
||||
|
||||
@prefix_list = ();
|
||||
foreach $h (@disasm_prefixes, '') {
|
||||
foreach $h (@disasm_prefixes) {
|
||||
for ($c = 0; $c < 256; $c++) {
|
||||
$nn = sprintf("%s%02X", $h, $c);
|
||||
if ($is_prefix{$nn} || defined($dinstables{$nn})) {
|
||||
@ -315,10 +374,15 @@ if ( $output eq 'd' ) {
|
||||
for ($c = 0; $c < 256; $c++) {
|
||||
$nn = sprintf("%s%02X", $h, $c);
|
||||
if ($is_prefix{$nn}) {
|
||||
die "$fname:$line: ambiguous decoding of $nn\n"
|
||||
if (defined($dinstables{$nn}));
|
||||
if ($dinstables{$nn}) {
|
||||
print STDERR "$fname: ambiguous decoding, prefix $nn aliases:\n";
|
||||
foreach my $dc (@{$dinstables{$nn}}) {
|
||||
print STDERR codesubst($big[$dc]), "\n";
|
||||
}
|
||||
exit 1;
|
||||
}
|
||||
printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn;
|
||||
} elsif (defined($dinstables{$nn})) {
|
||||
} elsif ($dinstables{$nn}) {
|
||||
printf D " /* 0x%02x */ { itable_%s, %u },\n", $c,
|
||||
$nn, scalar(@{$dinstables{$nn}});
|
||||
} else {
|
||||
@ -362,10 +426,9 @@ if ( $output eq 'i' ) {
|
||||
print I "#define NASM_INSNSI_H 1\n\n";
|
||||
print I "enum opcode {\n";
|
||||
$maxlen = 0;
|
||||
foreach $i (@opcodes, @opcodes_cc) {
|
||||
foreach $i (@opcodes) {
|
||||
print I "\tI_${i},\n";
|
||||
$len = length($i);
|
||||
$len++ if ( $i =~ /cc$/ ); # Condition codes can be 3 characters long
|
||||
$maxlen = $len if ( $len > $maxlen );
|
||||
}
|
||||
print I "\tI_none = -1\n";
|
||||
@ -373,7 +436,6 @@ if ( $output eq 'i' ) {
|
||||
print I "#define MAX_INSLEN ", $maxlen, "\n";
|
||||
print I "#define NASM_VEX_CLASSES ", $vex_classes, "\n";
|
||||
print I "#define NO_DECORATOR\t{", join(',',(0) x $MAX_OPERANDS), "}\n";
|
||||
print I "#define FIRST_COND_OPCODE I_", $opcodes_cc[0], "\n\n";
|
||||
print I "#endif /* NASM_INSNSI_H */\n";
|
||||
|
||||
close I;
|
||||
@ -389,14 +451,9 @@ if ( $output eq 'n' ) {
|
||||
print N "#include \"tables.h\"\n\n";
|
||||
|
||||
print N "const char * const nasm_insn_names[] = {";
|
||||
$first = 1;
|
||||
foreach $i (@opcodes, @opcodes_cc) {
|
||||
print N "," if ( !$first );
|
||||
$first = 0;
|
||||
$ilower = $i;
|
||||
$ilower =~ s/cc$//; # Remove conditional cc suffix
|
||||
$ilower =~ tr/A-Z/a-z/; # Change to lower case (Perl 4 compatible)
|
||||
print N "\n\t\"${ilower}\"";
|
||||
foreach $i (@opcodes) {
|
||||
print N "\n\t\"\L$i\"";
|
||||
print N ',' if ($i < $#opcodes);
|
||||
}
|
||||
print N "\n};\n";
|
||||
close N;
|
||||
@ -658,7 +715,6 @@ sub hexstr(@) {
|
||||
# instruction. We need only consider the codes:
|
||||
# \[1234] mean literal bytes, of course
|
||||
# \1[0123] mean byte plus register value
|
||||
# \330 means byte plus condition code
|
||||
# \0 or \340 mean give up and return empty set
|
||||
# \34[4567] mean PUSH/POP of segment registers: special case
|
||||
# \17[234] skip is4 control byte
|
||||
@ -691,15 +747,16 @@ sub startseq($$) {
|
||||
}
|
||||
|
||||
foreach $pfx (@disasm_prefixes) {
|
||||
if (substr($fbs, 0, length($pfx)) eq $pfx) {
|
||||
my $len = length($pfx);
|
||||
if (substr($fbs, 0, $len) eq $pfx) {
|
||||
$prefix = $pfx;
|
||||
$fbs = substr($fbs, length($pfx));
|
||||
$fbs = substr($fbs, $len, 2);
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fbs ne '') {
|
||||
return ($prefix.substr($fbs,0,2));
|
||||
return ($prefix.$fbs);
|
||||
}
|
||||
|
||||
unshift(@codes, $c0);
|
||||
@ -707,8 +764,6 @@ sub startseq($$) {
|
||||
return addprefix($prefix, $c1..($c1+7));
|
||||
} elsif (($c0 & ~013) == 0144) {
|
||||
return addprefix($prefix, $c1, $c1|2);
|
||||
} elsif ($c0 == 0330) {
|
||||
return addprefix($prefix, $c1..($c1+15));
|
||||
} elsif ($c0 == 0 || $c0 == 0340) {
|
||||
return $prefix;
|
||||
} elsif (($c0 & ~3) == 0260 || $c0 == 0270 ||
|
||||
@ -729,7 +784,7 @@ sub startseq($$) {
|
||||
# and "ignorable" codes here
|
||||
}
|
||||
}
|
||||
return $prefix;
|
||||
return ();
|
||||
}
|
||||
|
||||
# EVEX tuple types offset is 0300. e.g. 0301 is for full vector(fv).
|
||||
@ -1090,9 +1145,6 @@ sub byte_code_compile($$) {
|
||||
}
|
||||
push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ /^([0-9a-f]{2})\+c$/) {
|
||||
push(@codes, 0330, hex $1);
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ /^([0-9a-f]{2})\+r$/) {
|
||||
if (!defined($oppos{'r'})) {
|
||||
die "$fname:$line: $op without 'r' operand\n";
|
||||
|
Loading…
Reference in New Issue
Block a user