mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 03:43:37 +08:00
Break out documentation to docs/devel/.
Add support for pattern groups. Other misc cleanups for multiple decode functions. -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJch+V5AAoJEGTfOOivfiFfsFsH/1KW6UWAiieZ1+HPYEp24Ku8 hCNxlfj0iKe1ZEuC8qp2U27GzePi71IlIJ7p5AuAhiTQBBWz8bPzJJUALm3EliaI V4/13fLnTYALnPWoUJclU5frdHBhpIWxFUtnLdB50dSU1cTbFFyS+63JsW3wSSXt UqntlhSsAmAQr3ULnKufwDZQJgQoft/8G4YzvMOm/7E0ZeV3B9mARAkn6m/30gLx nXgLI2OQrA1ATLeTfzNRup9G+YjLx0nW2LRhAseIWcQAW8PyfJsfW6tJeou93+bf fK6BkLMgor74QH37Y3u7KVJGJ04u2Gtu0p2JzBA9MU/0l07WihWPA0eJGnP396I= =BxBC -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-dt-20190312' into staging Break out documentation to docs/devel/. Add support for pattern groups. Other misc cleanups for multiple decode functions. # gpg: Signature made Tue 12 Mar 2019 16:59:37 GMT # gpg: using RSA key 64DF38E8AF7E215F # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-dt-20190312: decodetree: Properly diagnose fields overflowing an insn decodetree: Prefix extract function names with decode_function decodetree: Allow +- to begin a number initializing a field decodetree: Produce clean output for an empty input file decodetree: Add --static-decode option test/decode: Add tests for PatternGroups decodetree: Allow grouping of overlapping patterns decodetree: Do not unconditionaly return from Pattern.output_code decodetree: Ensure build_tree does not include values outside insnmask decodetree: Document the usefulness of argument sets decodetree: Move documentation to docs/devel/decodetree.rst MAINTAINERS: Add scripts/decodetree.py to the TCG section Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
f39901d59f
@ -117,6 +117,8 @@ F: cpus.c
|
|||||||
F: exec.c
|
F: exec.c
|
||||||
F: accel/tcg/
|
F: accel/tcg/
|
||||||
F: accel/stubs/tcg-stub.c
|
F: accel/stubs/tcg-stub.c
|
||||||
|
F: scripts/decodetree.py
|
||||||
|
F: docs/devel/decodetree.rst
|
||||||
F: include/exec/cpu*.h
|
F: include/exec/cpu*.h
|
||||||
F: include/exec/exec-all.h
|
F: include/exec/exec-all.h
|
||||||
F: include/exec/helper*.h
|
F: include/exec/helper*.h
|
||||||
|
221
docs/devel/decodetree.rst
Normal file
221
docs/devel/decodetree.rst
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
========================
|
||||||
|
Decodetree Specification
|
||||||
|
========================
|
||||||
|
|
||||||
|
A *decodetree* is built from instruction *patterns*. A pattern may
|
||||||
|
represent a single architectural instruction or a group of same, depending
|
||||||
|
on what is convenient for further processing.
|
||||||
|
|
||||||
|
Each pattern has both *fixedbits* and *fixedmask*, the combination of which
|
||||||
|
describes the condition under which the pattern is matched::
|
||||||
|
|
||||||
|
(insn & fixedmask) == fixedbits
|
||||||
|
|
||||||
|
Each pattern may have *fields*, which are extracted from the insn and
|
||||||
|
passed along to the translator. Examples of such are registers,
|
||||||
|
immediates, and sub-opcodes.
|
||||||
|
|
||||||
|
In support of patterns, one may declare *fields*, *argument sets*, and
|
||||||
|
*formats*, each of which may be re-used to simplify further definitions.
|
||||||
|
|
||||||
|
Fields
|
||||||
|
======
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
field_def := '%' identifier ( unnamed_field )+ ( !function=identifier )?
|
||||||
|
unnamed_field := number ':' ( 's' ) number
|
||||||
|
|
||||||
|
For *unnamed_field*, the first number is the least-significant bit position
|
||||||
|
of the field and the second number is the length of the field. If the 's' is
|
||||||
|
present, the field is considered signed. If multiple ``unnamed_fields`` are
|
||||||
|
present, they are concatenated. In this way one can define disjoint fields.
|
||||||
|
|
||||||
|
If ``!function`` is specified, the concatenated result is passed through the
|
||||||
|
named function, taking and returning an integral value.
|
||||||
|
|
||||||
|
FIXME: the fields of the structure into which this result will be stored
|
||||||
|
is restricted to ``int``. Which means that we cannot expand 64-bit items.
|
||||||
|
|
||||||
|
Field examples:
|
||||||
|
|
||||||
|
+---------------------------+---------------------------------------------+
|
||||||
|
| Input | Generated code |
|
||||||
|
+===========================+=============================================+
|
||||||
|
| %disp 0:s16 | sextract(i, 0, 16) |
|
||||||
|
+---------------------------+---------------------------------------------+
|
||||||
|
| %imm9 16:6 10:3 | extract(i, 16, 6) << 3 | extract(i, 10, 3) |
|
||||||
|
+---------------------------+---------------------------------------------+
|
||||||
|
| %disp12 0:s1 1:1 2:10 | sextract(i, 0, 1) << 11 | |
|
||||||
|
| | extract(i, 1, 1) << 10 | |
|
||||||
|
| | extract(i, 2, 10) |
|
||||||
|
+---------------------------+---------------------------------------------+
|
||||||
|
| %shimm8 5:s8 13:1 | expand_shimm8(sextract(i, 5, 8) << 1 | |
|
||||||
|
| !function=expand_shimm8 | extract(i, 13, 1)) |
|
||||||
|
+---------------------------+---------------------------------------------+
|
||||||
|
|
||||||
|
Argument Sets
|
||||||
|
=============
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
args_def := '&' identifier ( args_elt )+ ( !extern )?
|
||||||
|
args_elt := identifier
|
||||||
|
|
||||||
|
Each *args_elt* defines an argument within the argument set.
|
||||||
|
Each argument set will be rendered as a C structure "arg_$name"
|
||||||
|
with each of the fields being one of the member arguments.
|
||||||
|
|
||||||
|
If ``!extern`` is specified, the backing structure is assumed
|
||||||
|
to have been already declared, typically via a second decoder.
|
||||||
|
|
||||||
|
Argument sets are useful when one wants to define helper functions
|
||||||
|
for the translator functions that can perform operations on a common
|
||||||
|
set of arguments. This can ensure, for instance, that the ``AND``
|
||||||
|
pattern and the ``OR`` pattern put their operands into the same named
|
||||||
|
structure, so that a common ``gen_logic_insn`` may be able to handle
|
||||||
|
the operations common between the two.
|
||||||
|
|
||||||
|
Argument set examples::
|
||||||
|
|
||||||
|
®3 ra rb rc
|
||||||
|
&loadstore reg base offset
|
||||||
|
|
||||||
|
|
||||||
|
Formats
|
||||||
|
=======
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
fmt_def := '@' identifier ( fmt_elt )+
|
||||||
|
fmt_elt := fixedbit_elt | field_elt | field_ref | args_ref
|
||||||
|
fixedbit_elt := [01.-]+
|
||||||
|
field_elt := identifier ':' 's'? number
|
||||||
|
field_ref := '%' identifier | identifier '=' '%' identifier
|
||||||
|
args_ref := '&' identifier
|
||||||
|
|
||||||
|
Defining a format is a handy way to avoid replicating groups of fields
|
||||||
|
across many instruction patterns.
|
||||||
|
|
||||||
|
A *fixedbit_elt* describes a contiguous sequence of bits that must
|
||||||
|
be 1, 0, or don't care. The difference between '.' and '-'
|
||||||
|
is that '.' means that the bit will be covered with a field or a
|
||||||
|
final 0 or 1 from the pattern, and '-' means that the bit is really
|
||||||
|
ignored by the cpu and will not be specified.
|
||||||
|
|
||||||
|
A *field_elt* describes a simple field only given a width; the position of
|
||||||
|
the field is implied by its position with respect to other *fixedbit_elt*
|
||||||
|
and *field_elt*.
|
||||||
|
|
||||||
|
If any *fixedbit_elt* or *field_elt* appear, then all bits must be defined.
|
||||||
|
Padding with a *fixedbit_elt* of all '.' is an easy way to accomplish that.
|
||||||
|
|
||||||
|
A *field_ref* incorporates a field by reference. This is the only way to
|
||||||
|
add a complex field to a format. A field may be renamed in the process
|
||||||
|
via assignment to another identifier. This is intended to allow the
|
||||||
|
same argument set be used with disjoint named fields.
|
||||||
|
|
||||||
|
A single *args_ref* may specify an argument set to use for the format.
|
||||||
|
The set of fields in the format must be a subset of the arguments in
|
||||||
|
the argument set. If an argument set is not specified, one will be
|
||||||
|
inferred from the set of fields.
|
||||||
|
|
||||||
|
It is recommended, but not required, that all *field_ref* and *args_ref*
|
||||||
|
appear at the end of the line, not interleaving with *fixedbit_elf* or
|
||||||
|
*field_elt*.
|
||||||
|
|
||||||
|
Format examples::
|
||||||
|
|
||||||
|
@opr ...... ra:5 rb:5 ... 0 ....... rc:5
|
||||||
|
@opi ...... ra:5 lit:8 1 ....... rc:5
|
||||||
|
|
||||||
|
Patterns
|
||||||
|
========
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
pat_def := identifier ( pat_elt )+
|
||||||
|
pat_elt := fixedbit_elt | field_elt | field_ref | args_ref | fmt_ref | const_elt
|
||||||
|
fmt_ref := '@' identifier
|
||||||
|
const_elt := identifier '=' number
|
||||||
|
|
||||||
|
The *fixedbit_elt* and *field_elt* specifiers are unchanged from formats.
|
||||||
|
A pattern that does not specify a named format will have one inferred
|
||||||
|
from a referenced argument set (if present) and the set of fields.
|
||||||
|
|
||||||
|
A *const_elt* allows a argument to be set to a constant value. This may
|
||||||
|
come in handy when fields overlap between patterns and one has to
|
||||||
|
include the values in the *fixedbit_elt* instead.
|
||||||
|
|
||||||
|
The decoder will call a translator function for each pattern matched.
|
||||||
|
|
||||||
|
Pattern examples::
|
||||||
|
|
||||||
|
addl_r 010000 ..... ..... .... 0000000 ..... @opr
|
||||||
|
addl_i 010000 ..... ..... .... 0000000 ..... @opi
|
||||||
|
|
||||||
|
which will, in part, invoke::
|
||||||
|
|
||||||
|
trans_addl_r(ctx, &arg_opr, insn)
|
||||||
|
|
||||||
|
and::
|
||||||
|
|
||||||
|
trans_addl_i(ctx, &arg_opi, insn)
|
||||||
|
|
||||||
|
Pattern Groups
|
||||||
|
==============
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
group := '{' ( pat_def | group )+ '}'
|
||||||
|
|
||||||
|
A *group* begins with a lone open-brace, with all subsequent lines
|
||||||
|
indented two spaces, and ending with a lone close-brace. Groups
|
||||||
|
may be nested, increasing the required indentation of the lines
|
||||||
|
within the nested group to two spaces per nesting level.
|
||||||
|
|
||||||
|
Unlike ungrouped patterns, grouped patterns are allowed to overlap.
|
||||||
|
Conflicts are resolved by selecting the patterns in order. If all
|
||||||
|
of the fixedbits for a pattern match, its translate function will
|
||||||
|
be called. If the translate function returns false, then subsequent
|
||||||
|
patterns within the group will be matched.
|
||||||
|
|
||||||
|
The following example from PA-RISC shows specialization of the *or*
|
||||||
|
instruction::
|
||||||
|
|
||||||
|
{
|
||||||
|
{
|
||||||
|
nop 000010 ----- ----- 0000 001001 0 00000
|
||||||
|
copy 000010 00000 r1:5 0000 001001 0 rt:5
|
||||||
|
}
|
||||||
|
or 000010 rt2:5 r1:5 cf:4 001001 0 rt:5
|
||||||
|
}
|
||||||
|
|
||||||
|
When the *cf* field is zero, the instruction has no side effects,
|
||||||
|
and may be specialized. When the *rt* field is zero, the output
|
||||||
|
is discarded and so the instruction has no effect. When the *rt2*
|
||||||
|
field is zero, the operation is ``reg[rt] | 0`` and so encodes
|
||||||
|
the canonical register copy operation.
|
||||||
|
|
||||||
|
The output from the generator might look like::
|
||||||
|
|
||||||
|
switch (insn & 0xfc000fe0) {
|
||||||
|
case 0x08000240:
|
||||||
|
/* 000010.. ........ ....0010 010..... */
|
||||||
|
if ((insn & 0x0000f000) == 0x00000000) {
|
||||||
|
/* 000010.. ........ 00000010 010..... */
|
||||||
|
if ((insn & 0x0000001f) == 0x00000000) {
|
||||||
|
/* 000010.. ........ 00000010 01000000 */
|
||||||
|
extract_decode_Fmt_0(&u.f_decode0, insn);
|
||||||
|
if (trans_nop(ctx, &u.f_decode0)) return true;
|
||||||
|
}
|
||||||
|
if ((insn & 0x03e00000) == 0x00000000) {
|
||||||
|
/* 00001000 000..... 00000010 010..... */
|
||||||
|
extract_decode_Fmt_1(&u.f_decode1, insn);
|
||||||
|
if (trans_copy(ctx, &u.f_decode1)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extract_decode_Fmt_2(&u.f_decode2, insn);
|
||||||
|
if (trans_or(ctx, &u.f_decode2)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
@ -19,4 +19,4 @@ Contents:
|
|||||||
migration
|
migration
|
||||||
stable-process
|
stable-process
|
||||||
testing
|
testing
|
||||||
|
decodetree
|
||||||
|
@ -17,139 +17,7 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# Generate a decoding tree from a specification file.
|
# Generate a decoding tree from a specification file.
|
||||||
#
|
# See the syntax and semantics in docs/devel/decodetree.rst.
|
||||||
# The tree is built from instruction "patterns". A pattern may represent
|
|
||||||
# a single architectural instruction or a group of same, depending on what
|
|
||||||
# is convenient for further processing.
|
|
||||||
#
|
|
||||||
# Each pattern has "fixedbits" & "fixedmask", the combination of which
|
|
||||||
# describes the condition under which the pattern is matched:
|
|
||||||
#
|
|
||||||
# (insn & fixedmask) == fixedbits
|
|
||||||
#
|
|
||||||
# Each pattern may have "fields", which are extracted from the insn and
|
|
||||||
# passed along to the translator. Examples of such are registers,
|
|
||||||
# immediates, and sub-opcodes.
|
|
||||||
#
|
|
||||||
# In support of patterns, one may declare fields, argument sets, and
|
|
||||||
# formats, each of which may be re-used to simplify further definitions.
|
|
||||||
#
|
|
||||||
# *** Field syntax:
|
|
||||||
#
|
|
||||||
# field_def := '%' identifier ( unnamed_field )+ ( !function=identifier )?
|
|
||||||
# unnamed_field := number ':' ( 's' ) number
|
|
||||||
#
|
|
||||||
# For unnamed_field, the first number is the least-significant bit position of
|
|
||||||
# the field and the second number is the length of the field. If the 's' is
|
|
||||||
# present, the field is considered signed. If multiple unnamed_fields are
|
|
||||||
# present, they are concatenated. In this way one can define disjoint fields.
|
|
||||||
#
|
|
||||||
# If !function is specified, the concatenated result is passed through the
|
|
||||||
# named function, taking and returning an integral value.
|
|
||||||
#
|
|
||||||
# FIXME: the fields of the structure into which this result will be stored
|
|
||||||
# is restricted to "int". Which means that we cannot expand 64-bit items.
|
|
||||||
#
|
|
||||||
# Field examples:
|
|
||||||
#
|
|
||||||
# %disp 0:s16 -- sextract(i, 0, 16)
|
|
||||||
# %imm9 16:6 10:3 -- extract(i, 16, 6) << 3 | extract(i, 10, 3)
|
|
||||||
# %disp12 0:s1 1:1 2:10 -- sextract(i, 0, 1) << 11
|
|
||||||
# | extract(i, 1, 1) << 10
|
|
||||||
# | extract(i, 2, 10)
|
|
||||||
# %shimm8 5:s8 13:1 !function=expand_shimm8
|
|
||||||
# -- expand_shimm8(sextract(i, 5, 8) << 1
|
|
||||||
# | extract(i, 13, 1))
|
|
||||||
#
|
|
||||||
# *** Argument set syntax:
|
|
||||||
#
|
|
||||||
# args_def := '&' identifier ( args_elt )+ ( !extern )?
|
|
||||||
# args_elt := identifier
|
|
||||||
#
|
|
||||||
# Each args_elt defines an argument within the argument set.
|
|
||||||
# Each argument set will be rendered as a C structure "arg_$name"
|
|
||||||
# with each of the fields being one of the member arguments.
|
|
||||||
#
|
|
||||||
# If !extern is specified, the backing structure is assumed to
|
|
||||||
# have been already declared, typically via a second decoder.
|
|
||||||
#
|
|
||||||
# Argument set examples:
|
|
||||||
#
|
|
||||||
# ®3 ra rb rc
|
|
||||||
# &loadstore reg base offset
|
|
||||||
#
|
|
||||||
# *** Format syntax:
|
|
||||||
#
|
|
||||||
# fmt_def := '@' identifier ( fmt_elt )+
|
|
||||||
# fmt_elt := fixedbit_elt | field_elt | field_ref | args_ref
|
|
||||||
# fixedbit_elt := [01.-]+
|
|
||||||
# field_elt := identifier ':' 's'? number
|
|
||||||
# field_ref := '%' identifier | identifier '=' '%' identifier
|
|
||||||
# args_ref := '&' identifier
|
|
||||||
#
|
|
||||||
# Defining a format is a handy way to avoid replicating groups of fields
|
|
||||||
# across many instruction patterns.
|
|
||||||
#
|
|
||||||
# A fixedbit_elt describes a contiguous sequence of bits that must
|
|
||||||
# be 1, 0, [.-] for don't care. The difference between '.' and '-'
|
|
||||||
# is that '.' means that the bit will be covered with a field or a
|
|
||||||
# final [01] from the pattern, and '-' means that the bit is really
|
|
||||||
# ignored by the cpu and will not be specified.
|
|
||||||
#
|
|
||||||
# A field_elt describes a simple field only given a width; the position of
|
|
||||||
# the field is implied by its position with respect to other fixedbit_elt
|
|
||||||
# and field_elt.
|
|
||||||
#
|
|
||||||
# If any fixedbit_elt or field_elt appear then all bits must be defined.
|
|
||||||
# Padding with a fixedbit_elt of all '.' is an easy way to accomplish that.
|
|
||||||
#
|
|
||||||
# A field_ref incorporates a field by reference. This is the only way to
|
|
||||||
# add a complex field to a format. A field may be renamed in the process
|
|
||||||
# via assignment to another identifier. This is intended to allow the
|
|
||||||
# same argument set be used with disjoint named fields.
|
|
||||||
#
|
|
||||||
# A single args_ref may specify an argument set to use for the format.
|
|
||||||
# The set of fields in the format must be a subset of the arguments in
|
|
||||||
# the argument set. If an argument set is not specified, one will be
|
|
||||||
# inferred from the set of fields.
|
|
||||||
#
|
|
||||||
# It is recommended, but not required, that all field_ref and args_ref
|
|
||||||
# appear at the end of the line, not interleaving with fixedbit_elf or
|
|
||||||
# field_elt.
|
|
||||||
#
|
|
||||||
# Format examples:
|
|
||||||
#
|
|
||||||
# @opr ...... ra:5 rb:5 ... 0 ....... rc:5
|
|
||||||
# @opi ...... ra:5 lit:8 1 ....... rc:5
|
|
||||||
#
|
|
||||||
# *** Pattern syntax:
|
|
||||||
#
|
|
||||||
# pat_def := identifier ( pat_elt )+
|
|
||||||
# pat_elt := fixedbit_elt | field_elt | field_ref
|
|
||||||
# | args_ref | fmt_ref | const_elt
|
|
||||||
# fmt_ref := '@' identifier
|
|
||||||
# const_elt := identifier '=' number
|
|
||||||
#
|
|
||||||
# The fixedbit_elt and field_elt specifiers are unchanged from formats.
|
|
||||||
# A pattern that does not specify a named format will have one inferred
|
|
||||||
# from a referenced argument set (if present) and the set of fields.
|
|
||||||
#
|
|
||||||
# A const_elt allows a argument to be set to a constant value. This may
|
|
||||||
# come in handy when fields overlap between patterns and one has to
|
|
||||||
# include the values in the fixedbit_elt instead.
|
|
||||||
#
|
|
||||||
# The decoder will call a translator function for each pattern matched.
|
|
||||||
#
|
|
||||||
# Pattern examples:
|
|
||||||
#
|
|
||||||
# addl_r 010000 ..... ..... .... 0000000 ..... @opr
|
|
||||||
# addl_i 010000 ..... ..... .... 0000000 ..... @opi
|
|
||||||
#
|
|
||||||
# which will, in part, invoke
|
|
||||||
#
|
|
||||||
# trans_addl_r(ctx, &arg_opr, insn)
|
|
||||||
# and
|
|
||||||
# trans_addl_i(ctx, &arg_opi, insn)
|
|
||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -163,6 +31,7 @@ fields = {}
|
|||||||
arguments = {}
|
arguments = {}
|
||||||
formats = {}
|
formats = {}
|
||||||
patterns = []
|
patterns = []
|
||||||
|
allpatterns = []
|
||||||
|
|
||||||
translate_prefix = 'trans'
|
translate_prefix = 'trans'
|
||||||
translate_scope = 'static '
|
translate_scope = 'static '
|
||||||
@ -432,13 +301,7 @@ class General:
|
|||||||
self.fields = flds
|
self.fields = flds
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
r = self.name
|
return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
|
||||||
if self.base:
|
|
||||||
r = r + ' ' + self.base.name
|
|
||||||
else:
|
|
||||||
r = r + ' ' + str(self.fields)
|
|
||||||
r = r + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
|
|
||||||
return r
|
|
||||||
|
|
||||||
def str1(self, i):
|
def str1(self, i):
|
||||||
return str_indent(i) + self.__str__()
|
return str_indent(i) + self.__str__()
|
||||||
@ -449,7 +312,8 @@ class Format(General):
|
|||||||
"""Class representing an instruction format"""
|
"""Class representing an instruction format"""
|
||||||
|
|
||||||
def extract_name(self):
|
def extract_name(self):
|
||||||
return 'extract_' + self.name
|
global decode_function
|
||||||
|
return decode_function + '_extract_' + self.name
|
||||||
|
|
||||||
def output_extract(self):
|
def output_extract(self):
|
||||||
output('static void ', self.extract_name(), '(',
|
output('static void ', self.extract_name(), '(',
|
||||||
@ -480,11 +344,52 @@ class Pattern(General):
|
|||||||
output(ind, self.base.extract_name(), '(&u.f_', arg, ', insn);\n')
|
output(ind, self.base.extract_name(), '(&u.f_', arg, ', insn);\n')
|
||||||
for n, f in self.fields.items():
|
for n, f in self.fields.items():
|
||||||
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
|
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
|
||||||
output(ind, 'return ', translate_prefix, '_', self.name,
|
output(ind, 'if (', translate_prefix, '_', self.name,
|
||||||
'(ctx, &u.f_', arg, ');\n')
|
'(ctx, &u.f_', arg, ')) return true;\n')
|
||||||
# end Pattern
|
# end Pattern
|
||||||
|
|
||||||
|
|
||||||
|
class MultiPattern(General):
|
||||||
|
"""Class representing an overlapping set of instruction patterns"""
|
||||||
|
|
||||||
|
def __init__(self, lineno, pats, fixb, fixm, udfm):
|
||||||
|
self.file = input_file
|
||||||
|
self.lineno = lineno
|
||||||
|
self.pats = pats
|
||||||
|
self.base = None
|
||||||
|
self.fixedbits = fixb
|
||||||
|
self.fixedmask = fixm
|
||||||
|
self.undefmask = udfm
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
r = "{"
|
||||||
|
for p in self.pats:
|
||||||
|
r = r + ' ' + str(p)
|
||||||
|
return r + "}"
|
||||||
|
|
||||||
|
def output_decl(self):
|
||||||
|
for p in self.pats:
|
||||||
|
p.output_decl()
|
||||||
|
|
||||||
|
def output_code(self, i, extracted, outerbits, outermask):
|
||||||
|
global translate_prefix
|
||||||
|
ind = str_indent(i)
|
||||||
|
for p in self.pats:
|
||||||
|
if outermask != p.fixedmask:
|
||||||
|
innermask = p.fixedmask & ~outermask
|
||||||
|
innerbits = p.fixedbits & ~outermask
|
||||||
|
output(ind, 'if ((insn & ',
|
||||||
|
'0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
|
||||||
|
') {\n')
|
||||||
|
output(ind, ' /* ',
|
||||||
|
str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
|
||||||
|
p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
|
||||||
|
output(ind, '}\n')
|
||||||
|
else:
|
||||||
|
p.output_code(i, extracted, p.fixedbits, p.fixedmask)
|
||||||
|
#end MultiPattern
|
||||||
|
|
||||||
|
|
||||||
def parse_field(lineno, name, toks):
|
def parse_field(lineno, name, toks):
|
||||||
"""Parse one instruction field from TOKS at LINENO"""
|
"""Parse one instruction field from TOKS at LINENO"""
|
||||||
global fields
|
global fields
|
||||||
@ -637,6 +542,7 @@ def parse_generic(lineno, is_format, name, toks):
|
|||||||
global arguments
|
global arguments
|
||||||
global formats
|
global formats
|
||||||
global patterns
|
global patterns
|
||||||
|
global allpatterns
|
||||||
global re_ident
|
global re_ident
|
||||||
global insnwidth
|
global insnwidth
|
||||||
global insnmask
|
global insnmask
|
||||||
@ -684,7 +590,7 @@ def parse_generic(lineno, is_format, name, toks):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# 'Foo=number' sets an argument field to a constant value
|
# 'Foo=number' sets an argument field to a constant value
|
||||||
if re_fullmatch(re_ident + '=[0-9]+', t):
|
if re_fullmatch(re_ident + '=[+-]?[0-9]+', t):
|
||||||
(fname, value) = t.split('=')
|
(fname, value) = t.split('=')
|
||||||
value = int(value)
|
value = int(value)
|
||||||
flds = add_field(lineno, flds, fname, ConstField(value))
|
flds = add_field(lineno, flds, fname, ConstField(value))
|
||||||
@ -716,6 +622,8 @@ def parse_generic(lineno, is_format, name, toks):
|
|||||||
sign = True
|
sign = True
|
||||||
flen = flen[1:]
|
flen = flen[1:]
|
||||||
shift = int(flen, 10)
|
shift = int(flen, 10)
|
||||||
|
if shift + width > insnwidth:
|
||||||
|
error(lineno, 'field {0} exceeds insnwidth'.format(fname))
|
||||||
f = Field(sign, insnwidth - width - shift, shift)
|
f = Field(sign, insnwidth - width - shift, shift)
|
||||||
flds = add_field(lineno, flds, fname, f)
|
flds = add_field(lineno, flds, fname, f)
|
||||||
fixedbits <<= shift
|
fixedbits <<= shift
|
||||||
@ -781,6 +689,7 @@ def parse_generic(lineno, is_format, name, toks):
|
|||||||
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
||||||
undefmask, fieldmask, flds)
|
undefmask, fieldmask, flds)
|
||||||
patterns.append(pat)
|
patterns.append(pat)
|
||||||
|
allpatterns.append(pat)
|
||||||
|
|
||||||
# Validate the masks that we have assembled.
|
# Validate the masks that we have assembled.
|
||||||
if fieldmask & fixedmask:
|
if fieldmask & fixedmask:
|
||||||
@ -799,17 +708,66 @@ def parse_generic(lineno, is_format, name, toks):
|
|||||||
.format(allbits ^ insnmask))
|
.format(allbits ^ insnmask))
|
||||||
# end parse_general
|
# end parse_general
|
||||||
|
|
||||||
|
def build_multi_pattern(lineno, pats):
|
||||||
|
"""Validate the Patterns going into a MultiPattern."""
|
||||||
|
global patterns
|
||||||
|
global insnmask
|
||||||
|
|
||||||
|
if len(pats) < 2:
|
||||||
|
error(lineno, 'less than two patterns within braces')
|
||||||
|
|
||||||
|
fixedmask = insnmask
|
||||||
|
undefmask = insnmask
|
||||||
|
|
||||||
|
# Collect fixed/undefmask for all of the children.
|
||||||
|
# Move the defining lineno back to that of the first child.
|
||||||
|
for p in pats:
|
||||||
|
fixedmask &= p.fixedmask
|
||||||
|
undefmask &= p.undefmask
|
||||||
|
if p.lineno < lineno:
|
||||||
|
lineno = p.lineno
|
||||||
|
|
||||||
|
repeat = True
|
||||||
|
while repeat:
|
||||||
|
if fixedmask == 0:
|
||||||
|
error(lineno, 'no overlap in patterns within braces')
|
||||||
|
fixedbits = None
|
||||||
|
for p in pats:
|
||||||
|
thisbits = p.fixedbits & fixedmask
|
||||||
|
if fixedbits is None:
|
||||||
|
fixedbits = thisbits
|
||||||
|
elif fixedbits != thisbits:
|
||||||
|
fixedmask &= ~(fixedbits ^ thisbits)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
repeat = False
|
||||||
|
|
||||||
|
mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask)
|
||||||
|
patterns.append(mp)
|
||||||
|
# end build_multi_pattern
|
||||||
|
|
||||||
def parse_file(f):
|
def parse_file(f):
|
||||||
"""Parse all of the patterns within a file"""
|
"""Parse all of the patterns within a file"""
|
||||||
|
|
||||||
|
global patterns
|
||||||
|
|
||||||
# Read all of the lines of the file. Concatenate lines
|
# Read all of the lines of the file. Concatenate lines
|
||||||
# ending in backslash; discard empty lines and comments.
|
# ending in backslash; discard empty lines and comments.
|
||||||
toks = []
|
toks = []
|
||||||
lineno = 0
|
lineno = 0
|
||||||
|
nesting = 0
|
||||||
|
saved_pats = []
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
lineno += 1
|
lineno += 1
|
||||||
|
|
||||||
|
# Expand and strip spaces, to find indent.
|
||||||
|
line = line.rstrip()
|
||||||
|
line = line.expandtabs()
|
||||||
|
len1 = len(line)
|
||||||
|
line = line.lstrip()
|
||||||
|
len2 = len(line)
|
||||||
|
|
||||||
# Discard comments
|
# Discard comments
|
||||||
end = line.find('#')
|
end = line.find('#')
|
||||||
if end >= 0:
|
if end >= 0:
|
||||||
@ -819,10 +777,18 @@ def parse_file(f):
|
|||||||
if len(toks) != 0:
|
if len(toks) != 0:
|
||||||
# Next line after continuation
|
# Next line after continuation
|
||||||
toks.extend(t)
|
toks.extend(t)
|
||||||
elif len(t) == 0:
|
|
||||||
# Empty line
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
|
# Allow completely blank lines.
|
||||||
|
if len1 == 0:
|
||||||
|
continue
|
||||||
|
indent = len1 - len2
|
||||||
|
# Empty line due to comment.
|
||||||
|
if len(t) == 0:
|
||||||
|
# Indentation must be correct, even for comment lines.
|
||||||
|
if indent != nesting:
|
||||||
|
error(lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
continue
|
||||||
|
start_lineno = lineno
|
||||||
toks = t
|
toks = t
|
||||||
|
|
||||||
# Continuation?
|
# Continuation?
|
||||||
@ -830,21 +796,47 @@ def parse_file(f):
|
|||||||
toks.pop()
|
toks.pop()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(toks) < 2:
|
|
||||||
error(lineno, 'short line')
|
|
||||||
|
|
||||||
name = toks[0]
|
name = toks[0]
|
||||||
del toks[0]
|
del toks[0]
|
||||||
|
|
||||||
|
# End nesting?
|
||||||
|
if name == '}':
|
||||||
|
if nesting == 0:
|
||||||
|
error(start_lineno, 'mismatched close brace')
|
||||||
|
if len(toks) != 0:
|
||||||
|
error(start_lineno, 'extra tokens after close brace')
|
||||||
|
nesting -= 2
|
||||||
|
if indent != nesting:
|
||||||
|
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
pats = patterns
|
||||||
|
patterns = saved_pats.pop()
|
||||||
|
build_multi_pattern(lineno, pats)
|
||||||
|
toks = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Everything else should have current indentation.
|
||||||
|
if indent != nesting:
|
||||||
|
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
|
||||||
|
# Start nesting?
|
||||||
|
if name == '{':
|
||||||
|
if len(toks) != 0:
|
||||||
|
error(start_lineno, 'extra tokens after open brace')
|
||||||
|
saved_pats.append(patterns)
|
||||||
|
patterns = []
|
||||||
|
nesting += 2
|
||||||
|
toks = []
|
||||||
|
continue
|
||||||
|
|
||||||
# Determine the type of object needing to be parsed.
|
# Determine the type of object needing to be parsed.
|
||||||
if name[0] == '%':
|
if name[0] == '%':
|
||||||
parse_field(lineno, name[1:], toks)
|
parse_field(start_lineno, name[1:], toks)
|
||||||
elif name[0] == '&':
|
elif name[0] == '&':
|
||||||
parse_arguments(lineno, name[1:], toks)
|
parse_arguments(start_lineno, name[1:], toks)
|
||||||
elif name[0] == '@':
|
elif name[0] == '@':
|
||||||
parse_generic(lineno, True, name[1:], toks)
|
parse_generic(start_lineno, True, name[1:], toks)
|
||||||
else:
|
else:
|
||||||
parse_generic(lineno, False, name, toks)
|
parse_generic(start_lineno, False, name, toks)
|
||||||
toks = []
|
toks = []
|
||||||
# end parse_file
|
# end parse_file
|
||||||
|
|
||||||
@ -909,23 +901,22 @@ class Tree:
|
|||||||
output(ind, ' /* ',
|
output(ind, ' /* ',
|
||||||
str_match_bits(innerbits, innermask), ' */\n')
|
str_match_bits(innerbits, innermask), ' */\n')
|
||||||
s.output_code(i + 4, extracted, innerbits, innermask)
|
s.output_code(i + 4, extracted, innerbits, innermask)
|
||||||
|
output(ind, ' return false;\n')
|
||||||
output(ind, '}\n')
|
output(ind, '}\n')
|
||||||
output(ind, 'return false;\n')
|
|
||||||
# end Tree
|
# end Tree
|
||||||
|
|
||||||
|
|
||||||
def build_tree(pats, outerbits, outermask):
|
def build_tree(pats, outerbits, outermask):
|
||||||
# Find the intersection of all remaining fixedmask.
|
# Find the intersection of all remaining fixedmask.
|
||||||
innermask = ~outermask
|
innermask = ~outermask & insnmask
|
||||||
for i in pats:
|
for i in pats:
|
||||||
innermask &= i.fixedmask
|
innermask &= i.fixedmask
|
||||||
|
|
||||||
if innermask == 0:
|
if innermask == 0:
|
||||||
pnames = []
|
text = 'overlapping patterns:'
|
||||||
for p in pats:
|
for p in pats:
|
||||||
pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
|
text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
|
||||||
error_with_file(pats[0].file, pats[0].lineno,
|
error_with_file(pats[0].file, pats[0].lineno, text)
|
||||||
'overlapping patterns:', pnames)
|
|
||||||
|
|
||||||
fullmask = outermask | innermask
|
fullmask = outermask | innermask
|
||||||
|
|
||||||
@ -978,6 +969,7 @@ def main():
|
|||||||
global arguments
|
global arguments
|
||||||
global formats
|
global formats
|
||||||
global patterns
|
global patterns
|
||||||
|
global allpatterns
|
||||||
global translate_scope
|
global translate_scope
|
||||||
global translate_prefix
|
global translate_prefix
|
||||||
global output_fd
|
global output_fd
|
||||||
@ -990,7 +982,8 @@ def main():
|
|||||||
|
|
||||||
decode_scope = 'static '
|
decode_scope = 'static '
|
||||||
|
|
||||||
long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=']
|
long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
|
||||||
|
'static-decode=']
|
||||||
try:
|
try:
|
||||||
(opts, args) = getopt.getopt(sys.argv[1:], 'o:w:', long_opts)
|
(opts, args) = getopt.getopt(sys.argv[1:], 'o:w:', long_opts)
|
||||||
except getopt.GetoptError as err:
|
except getopt.GetoptError as err:
|
||||||
@ -1001,6 +994,8 @@ def main():
|
|||||||
elif o == '--decode':
|
elif o == '--decode':
|
||||||
decode_function = a
|
decode_function = a
|
||||||
decode_scope = ''
|
decode_scope = ''
|
||||||
|
elif o == '--static-decode':
|
||||||
|
decode_function = a
|
||||||
elif o == '--translate':
|
elif o == '--translate':
|
||||||
translate_prefix = a
|
translate_prefix = a
|
||||||
translate_scope = ''
|
translate_scope = ''
|
||||||
@ -1039,7 +1034,7 @@ def main():
|
|||||||
# Make sure that the argument sets are the same, and declare the
|
# Make sure that the argument sets are the same, and declare the
|
||||||
# function only once.
|
# function only once.
|
||||||
out_pats = {}
|
out_pats = {}
|
||||||
for i in patterns:
|
for i in allpatterns:
|
||||||
if i.name in out_pats:
|
if i.name in out_pats:
|
||||||
p = out_pats[i.name]
|
p = out_pats[i.name]
|
||||||
if i.base.base != p.base.base:
|
if i.base.base != p.base.base:
|
||||||
@ -1057,14 +1052,16 @@ def main():
|
|||||||
'(DisasContext *ctx, ', insntype, ' insn)\n{\n')
|
'(DisasContext *ctx, ', insntype, ' insn)\n{\n')
|
||||||
|
|
||||||
i4 = str_indent(4)
|
i4 = str_indent(4)
|
||||||
output(i4, 'union {\n')
|
|
||||||
for n in sorted(arguments.keys()):
|
|
||||||
f = arguments[n]
|
|
||||||
output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
|
|
||||||
output(i4, '} u;\n\n')
|
|
||||||
|
|
||||||
t.output_code(4, False, 0, 0)
|
if len(allpatterns) != 0:
|
||||||
|
output(i4, 'union {\n')
|
||||||
|
for n in sorted(arguments.keys()):
|
||||||
|
f = arguments[n]
|
||||||
|
output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
|
||||||
|
output(i4, '} u;\n\n')
|
||||||
|
t.output_code(4, False, 0, 0)
|
||||||
|
|
||||||
|
output(i4, 'return false;\n')
|
||||||
output('}\n')
|
output('}\n')
|
||||||
|
|
||||||
if output_file:
|
if output_file:
|
||||||
|
@ -15,4 +15,10 @@ for i in err_*.decode; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for i in succ_*.decode; do
|
||||||
|
if ! $PYTHON $DECODETREE $i > /dev/null 2> /dev/null; then
|
||||||
|
echo FAIL:$i 1>&2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
exit $E
|
exit $E
|
||||||
|
6
tests/decode/err_pattern_group_empty.decode
Normal file
6
tests/decode/err_pattern_group_empty.decode
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# empty groups are not allowed
|
||||||
|
{
|
||||||
|
}
|
10
tests/decode/err_pattern_group_ident1.decode
Normal file
10
tests/decode/err_pattern_group_ident1.decode
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
%sub1 0:8
|
||||||
|
|
||||||
|
# Make sure that indentation is enforced
|
||||||
|
{
|
||||||
|
top 00000000 00000000 00000000 00000000
|
||||||
|
sub1 00000000 00000000 00000000 ........ %sub1
|
||||||
|
}
|
11
tests/decode/err_pattern_group_ident2.decode
Normal file
11
tests/decode/err_pattern_group_ident2.decode
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
%sub1 0:8
|
||||||
|
|
||||||
|
# Make sure that indentation is enforced
|
||||||
|
{
|
||||||
|
top 00000000 00000000 00000000 00000000
|
||||||
|
sub1 00000000 00000000 00000000 ........ %sub1
|
||||||
|
# comments are suposed to be indented
|
||||||
|
}
|
13
tests/decode/err_pattern_group_nest1.decode
Normal file
13
tests/decode/err_pattern_group_nest1.decode
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
%sub1 0:8
|
||||||
|
%sub2 8:8
|
||||||
|
%sub3 16:8
|
||||||
|
%sub4 24:8
|
||||||
|
|
||||||
|
# Groups with no overlap are supposed to fail
|
||||||
|
{
|
||||||
|
top 00000000 00000000 00000000 00000000
|
||||||
|
sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4
|
||||||
|
}
|
6
tests/decode/err_pattern_group_overlap1.decode
Normal file
6
tests/decode/err_pattern_group_overlap1.decode
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
one 00000000000000000000000000000000
|
||||||
|
{
|
||||||
|
two 0000000000000000000000000000000 s:1
|
||||||
|
three 000000000000000000000000000000 s:1 0
|
||||||
|
}
|
||||||
|
|
5
tests/decode/err_width1.decode
Normal file
5
tests/decode/err_width1.decode
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# Diagnose too many bits (33 of 32)
|
||||||
|
one 000000000000000000000000000000000
|
5
tests/decode/err_width2.decode
Normal file
5
tests/decode/err_width2.decode
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# Diagnose too few bits (31 of 32)
|
||||||
|
one 0000000000000000000000000000000
|
5
tests/decode/err_width3.decode
Normal file
5
tests/decode/err_width3.decode
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# Diagnose too many bits (33 of 32)
|
||||||
|
one 0 s:32
|
5
tests/decode/err_width4.decode
Normal file
5
tests/decode/err_width4.decode
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# Diagnose too few bits (31 of 32)
|
||||||
|
one 0 s:30
|
22
tests/decode/succ_pattern_group_nest1.decode
Normal file
22
tests/decode/succ_pattern_group_nest1.decode
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
%sub1 0:8
|
||||||
|
%sub2 8:8
|
||||||
|
%sub3 16:8
|
||||||
|
%sub4 24:7
|
||||||
|
|
||||||
|
# Make sure deep netsting works, as few targets will actually exercise it
|
||||||
|
{
|
||||||
|
top 00000000 00000000 00000000 00000000
|
||||||
|
{
|
||||||
|
sub1 00000000 00000000 00000000 ........ %sub1
|
||||||
|
{
|
||||||
|
sub2 00000000 00000000 ........ ........ %sub1 %sub2
|
||||||
|
{
|
||||||
|
sub3 00000000 ........ ........ ........ %sub1 %sub2 %sub3
|
||||||
|
sub4 0....... ........ ........ ........ %sub1 %sub2 %sub3 %sub4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user