| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package xeddata |
| |
| import ( |
| "errors" |
| "strings" |
| ) |
| |
| // OperandVisibility describes operand visibility in XED terms. |
| type OperandVisibility int |
| |
| const ( |
| // VisExplicit is a default operand visibility. |
| // Explicit operand is "real" kind of operands that |
| // is shown in syntax and can be specified by the programmer. |
| VisExplicit OperandVisibility = iota |
| |
| // VisImplicit is for fixed arg (like EAX); usually shown in syntax. |
| VisImplicit |
| |
| // VisSuppressed is like VisImplicit, but not shown in syntax. |
| // In some very rare exceptions, they are also shown in syntax string. |
| VisSuppressed |
| |
| // VisEcond is encoder-only conditions. Can be ignored. |
| VisEcond |
| ) |
| |
| // Operand holds data that is encoded inside |
| // instruction's "OPERANDS" field. |
| // |
| // Use NewOperand function to decode operand fields into Operand object. |
| type Operand struct { |
| // Name is an ID with optional nonterminal name part. |
| // |
| // Possible values: "REG0=GPRv_B", "REG1", "MEM0", ... |
| // |
| // If nonterminal part is present, name |
| // can be split into LHS and RHS with NonTerminalName method. |
| Name string |
| |
| // Action describes argument types. |
| // |
| // Possible values: "r", "w", "rw", "cr", "cw", "crw". |
| // Optional "c" prefix represents conditional access. |
| Action string |
| |
| // Width descriptor. It can express simple width like "w" (word, 16bit) |
| // or meta-width like "v", which corresponds to {16, 32, 64} bits. |
| // |
| // Possible values: "", "q", "ds", "dq", ... |
| // Optional. |
| Width string |
| |
| // Xtype holds XED-specific type information. |
| // |
| // Possible values: "", "f64", "i32", ... |
| // Optional. |
| Xtype string |
| |
| // Attributes serves as container for all other properties. |
| // |
| // Possible values: |
| // EVEX.b context { |
| // TXT=ZEROSTR - zeroing |
| // TXT=SAESTR - suppress all exceptions |
| // TXT=ROUNDC - rounding |
| // TXT=BCASTSTR - broadcasting |
| // } |
| // MULTISOURCE4 - 4FMA multi-register operand. |
| // |
| // Optional. For most operands, it's nil. |
| Attributes map[string]bool |
| |
| // Visibility tells if operand is explicit, implicit or suspended. |
| Visibility OperandVisibility |
| } |
| |
| var xedVisibilities = map[string]OperandVisibility{ |
| "EXPL": VisExplicit, |
| "IMPL": VisImplicit, |
| "SUPP": VisSuppressed, |
| "ECOND": VisEcond, |
| } |
| |
| // NewOperand decodes operand string. |
| // |
| // See "$XED/pysrc/opnds.py" to learn about fields format |
| // and valid combinations. |
| // |
| // Requires database with xtypes and widths info. |
| func NewOperand(db *Database, s string) (*Operand, error) { |
| if db.widths == nil { |
| return nil, errors.New("Database.widths is nil") |
| } |
| |
| fields := strings.Split(s, ":") |
| switch len(fields) { |
| case 0: |
| return nil, errors.New("empty operand fields string") |
| case 1: |
| return &Operand{Name: fields[0]}, nil |
| } |
| var op Operand |
| |
| // First two fields are fixed. |
| op.Name = fields[0] |
| op.Action = fields[1] |
| |
| // Optional fields. |
| for _, f := range fields[2:] { |
| if db.widths[f] != nil && op.Width == "" { |
| op.Width = f |
| } else if vis, ok := xedVisibilities[f]; ok { |
| op.Visibility = vis |
| } else if xtype := db.xtypes[f]; xtype != nil { |
| op.Xtype = f |
| } else { |
| if op.Attributes == nil { |
| op.Attributes = make(map[string]bool) |
| } |
| op.Attributes[f] = true |
| } |
| } |
| |
| return &op, nil |
| } |
| |
| // NonterminalName returns true if op.Name consist |
| // of LHS and RHS parts. |
| // |
| // RHS is non-terminal name lookup function expression. |
| // Example: "REG0=GPRv()" has "GPRv()" name lookup function. |
| func (op *Operand) NonterminalName() bool { |
| return strings.Contains(op.Name, "=") |
| } |
| |
| // NameLHS returns left hand side part of the non-terminal name. |
| // Example: NameLHS("REG0=GPRv()") => "REG0". |
| func (op *Operand) NameLHS() string { |
| return strings.Split(op.Name, "=")[0] |
| } |
| |
| // NameRHS returns right hand side part of the non-terminal name. |
| // Example: NameLHS("REG0=GPRv()") => "GPRv()". |
| func (op *Operand) NameRHS() string { |
| return strings.Split(op.Name, "=")[1] |
| } |
| |
| // IsVisible returns true for operands that are usually |
| // shown in syntax strings. |
| func (op *Operand) IsVisible() bool { |
| return op.Visibility == VisExplicit || |
| op.Visibility == VisImplicit |
| } |