...

Source file src/golang.org/x/arch/arm/armmap/map.go

Documentation: golang.org/x/arch/arm/armmap

     1  // Copyright 2014 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Armmap constructs the ARM opcode map from the instruction set CSV file.
     6  //
     7  // Usage:
     8  //
     9  //	armmap [-fmt=format] arm.csv
    10  //
    11  // The known output formats are:
    12  //
    13  //	text (default) - print decoding tree in text form
    14  //	decoder - print decoding tables for the armasm package
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"encoding/csv"
    20  	"flag"
    21  	"fmt"
    22  	"log"
    23  	"os"
    24  	"sort"
    25  	"strconv"
    26  	"strings"
    27  )
    28  
    29  var format = flag.String("fmt", "text", "output format: text, decoder")
    30  
    31  var inputFile string
    32  
    33  func usage() {
    34  	fmt.Fprintf(os.Stderr, "usage: armmap [-fmt=format] x86.csv\n")
    35  	os.Exit(2)
    36  }
    37  
    38  func main() {
    39  	log.SetFlags(0)
    40  	log.SetPrefix("armmap: ")
    41  
    42  	flag.Usage = usage
    43  	flag.Parse()
    44  	if flag.NArg() != 1 {
    45  		usage()
    46  	}
    47  
    48  	inputFile = flag.Arg(0)
    49  
    50  	var print func(*Prog)
    51  	switch *format {
    52  	default:
    53  		log.Fatalf("unknown output format %q", *format)
    54  	case "text":
    55  		print = printText
    56  	case "decoder":
    57  		print = printDecoder
    58  	}
    59  
    60  	p, err := readCSV(flag.Arg(0))
    61  	if err != nil {
    62  		log.Fatal(err)
    63  	}
    64  
    65  	print(p)
    66  }
    67  
    68  // readCSV reads the CSV file and returns the corresponding Prog.
    69  // It may print details about problems to standard error using the log package.
    70  func readCSV(file string) (*Prog, error) {
    71  	// Read input.
    72  	// Skip leading blank and # comment lines.
    73  	f, err := os.Open(file)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	b := bufio.NewReader(f)
    78  	for {
    79  		c, err := b.ReadByte()
    80  		if err != nil {
    81  			break
    82  		}
    83  		if c == '\n' {
    84  			continue
    85  		}
    86  		if c == '#' {
    87  			b.ReadBytes('\n')
    88  			continue
    89  		}
    90  		b.UnreadByte()
    91  		break
    92  	}
    93  	table, err := csv.NewReader(b).ReadAll()
    94  	if err != nil {
    95  		return nil, fmt.Errorf("parsing %s: %v", file, err)
    96  	}
    97  	if len(table) == 0 {
    98  		return nil, fmt.Errorf("empty csv input")
    99  	}
   100  	if len(table[0]) < 5 {
   101  		return nil, fmt.Errorf("csv too narrow: need at least five columns")
   102  	}
   103  
   104  	p := &Prog{}
   105  	for _, row := range table {
   106  		add(p, row[0], row[1], row[2], row[3], row[4])
   107  	}
   108  	return p, nil
   109  }
   110  
   111  type Prog struct {
   112  	Inst     []Inst
   113  	OpRanges map[string]string
   114  }
   115  
   116  type Inst struct {
   117  	Text     string
   118  	Encoding string
   119  	Mask     uint32
   120  	Value    uint32
   121  	Priority int
   122  	OpBase   string
   123  	OpBits   uint64
   124  	Args     []string
   125  }
   126  
   127  type Arg struct {
   128  	Name string
   129  	Bits uint64
   130  }
   131  
   132  // add adds the entry from the CSV described by maskstr, valuestr, text, encoding, tags
   133  // to the program p.
   134  func add(p *Prog, maskstr, valuestr, text, encoding, tags string) {
   135  	if strings.Contains(tags, "pseudo") {
   136  		return
   137  	}
   138  
   139  	// For now, ignore the VFP floating point instructions.
   140  	if strings.HasPrefix(text, "V") && !strings.Contains(tags, "vfp") {
   141  		// TODO
   142  		return
   143  	}
   144  
   145  	mask, err := strconv.ParseUint(maskstr, 0, 32)
   146  	if err != nil {
   147  		log.Printf("invalid mask %q", maskstr)
   148  		return
   149  	}
   150  	value, err := strconv.ParseUint(valuestr, 0, 32)
   151  	if err != nil {
   152  		log.Printf("invalid value %q", valuestr)
   153  		return
   154  	}
   155  
   156  	// Parse encoding, building size and offset of each field.
   157  	// The first field in the encoding is the largest offset.
   158  	fuzzy := uint32(0) // mask of 'should be' bits
   159  	fieldOffset := map[string]int{}
   160  	fieldWidth := map[string]int{}
   161  	off := 32
   162  	for _, f := range strings.Split(encoding, "|") {
   163  		n := 1
   164  		if i := strings.Index(f, ":"); i >= 0 {
   165  			n, _ = strconv.Atoi(f[i+1:])
   166  		}
   167  		off -= n
   168  		fieldOffset[f] = off
   169  		fieldWidth[f] = n
   170  		if f == "(0)" || f == "(1)" {
   171  			fuzzy |= 1 << uint(off)
   172  		}
   173  	}
   174  	if off != 0 {
   175  		fmt.Fprintf(os.Stderr, "%s: counted %d bits in %s\n", text, 32-off, encoding)
   176  	}
   177  
   178  	// Track which encoding fields we found uses for.
   179  	// If we do not find a use for a field, that's an error in the input tables.
   180  	fieldUsed := map[string]bool{}
   181  
   182  	// Split text into opcode and arguments.
   183  	var op, argstr string
   184  	if i := strings.Index(text, " "); i >= 0 {
   185  		op = text[:i]
   186  		argstr = text[i:]
   187  	} else {
   188  		op = text
   189  	}
   190  	op = strings.TrimSpace(op)
   191  	argstr = strings.TrimSpace(argstr)
   192  
   193  	// Parse opcode suffixes.
   194  	i := strings.Index(op, "<")
   195  	if i < 0 {
   196  		i = len(op)
   197  	}
   198  	if j := strings.Index(op, "{"); j >= 0 && j < i {
   199  		i = j
   200  	}
   201  	op, suffix := op[:i], op[i:]
   202  	if suffix != "" && opSuffix[suffix] == "" {
   203  		fmt.Fprintf(os.Stderr, "%s: invalid op suffix %q in %s\n", text, suffix, op+suffix)
   204  	}
   205  
   206  	// Make sure fields needed by opcode suffix are available.
   207  	for _, f := range strings.Split(opSuffix[suffix], ",") {
   208  		if f != "" && fieldWidth[f] == 0 {
   209  			fmt.Fprintf(os.Stderr, "%s: opsuffix %s missing %s in encoding %s\n", text, suffix, f, encoding)
   210  		}
   211  		fieldUsed[f] = true
   212  	}
   213  
   214  	// Build list of opcodes that can be generated by this suffix.
   215  	// For example, the opcodes generated by ADD<c> are ADD.EQ, ADD.NE, etc.
   216  	// To simplify the decoding of instruction opcodes, we arrange that this
   217  	// sequence aligns with the encoding, so that decoding amounts to extracting
   218  	// the right bits, concatenating them, and adding them to the first opcode in
   219  	// the sequence. If the condition code is present, we always place it in the
   220  	// low order bits, so that x&^15 == FOO_EQ tests whether x is any of the
   221  	// conditional FOO instructions.
   222  	ops := []string{op}
   223  	opBits := uint64(0) // record of bits to extract and add to opcode base
   224  	opFields := strings.Split(opSuffix[suffix], ",")
   225  	// First the optional elements, like {S} meaning "" or ".S".
   226  	for strings.HasPrefix(suffix, "{") {
   227  		i := strings.Index(suffix, "}")
   228  		var f, option string
   229  		option, suffix = suffix[1:i], suffix[i+1:]
   230  		f, opFields = opFields[0], opFields[1:]
   231  		if option == "W" {
   232  			// The {W} option on PLD{W} uses the R bit which is !W.
   233  			ops = cross(ops, "."+option, "")
   234  		} else {
   235  			ops = cross(ops, "", "."+option)
   236  		}
   237  		if fieldWidth[f] != 1 {
   238  			fmt.Fprintf(os.Stderr, "%s: have %d bits for {%s}\n", text, fieldWidth[f], option)
   239  		}
   240  		// opBits is a sequence of 16-bit chunks describing contiguous bit sections.
   241  		// Each chunk is 8-bit offset followed by 8-bit size.
   242  		opBits = opBits<<16 | uint64(fieldOffset[f])<<8 | 1
   243  	}
   244  	// Then the true field substitutions.
   245  	haveCond := false
   246  	for strings.Contains(suffix, "<") {
   247  		var f, literal, x string
   248  		if len(opFields) == 0 {
   249  			fmt.Fprintf(os.Stderr, "%s: ran out of suffix fields for <%s>\n", text, x)
   250  			break
   251  		}
   252  		f, opFields = opFields[0], opFields[1:]
   253  		i := strings.Index(suffix, "<")
   254  		j := strings.Index(suffix, ">")
   255  		literal, x, suffix = suffix[:i], suffix[i+1:j], suffix[j+1:]
   256  
   257  		// Add leading literal text to all opcodes.
   258  		ops = cross(ops, literal)
   259  
   260  		// The <c> condition can happen anywhere in the opcode text
   261  		// but we want to generate the actual variation in the low bits
   262  		// of the list index. Remember when and where we've seen <c> and apply
   263  		// it after the loop has finished.
   264  		if x == "c" && f == "cond:4" {
   265  			haveCond = true
   266  			ops = cross(ops, "_COND_")
   267  			continue
   268  		}
   269  
   270  		// Otherwise, choices[x] lists the possible expansions of <x>.
   271  		// If <x> is of the form <A,B,C> the choices are A, B, and C.
   272  		expand := choices[x]
   273  		if expand == nil && strings.Contains(x, ",") {
   274  			expand = strings.Split(x, ",")
   275  		}
   276  		if expand == nil {
   277  			fmt.Fprintf(os.Stderr, "%s: unknown choices for <%s>\n", text, x)
   278  			expand = []string{x}
   279  		} else if len(expand) != 1<<uint(fieldWidth[f]) {
   280  			fmt.Fprintf(os.Stderr, "%s: have %d choices for <%s> but %d bits\n", text, len(expand), x, fieldWidth[f])
   281  		}
   282  		opBits = opBits<<16 | uint64(fieldOffset[f])<<8 | uint64(fieldWidth[f])
   283  		ops = cross(ops, expand...)
   284  	}
   285  	if haveCond {
   286  		// Apply condtional suffix last.
   287  		opBits = opBits<<16 | 28<<8 | 4
   288  		ops = crossCond(ops)
   289  	}
   290  	ops = cross(ops, suffix)
   291  
   292  	// Now ops is a list of opcodes generated by this opcode pattern.
   293  	// We want to make sure that we can arrange for those opcodes to
   294  	// happen consecutively in the final opcode numbering.
   295  	// Record in p.OpRanges[op] the required consecutive sequence of
   296  	// opcode that includes op. To make searches easier, we record
   297  	// the sequence as a comma-separated list of strings with commas
   298  	// on both ends: [A, B] encodes as ",A,B,".
   299  	if p.OpRanges == nil {
   300  		p.OpRanges = make(map[string]string)
   301  	}
   302  	opstr := "," + strings.Join(ops, ",") + ","
   303  	for _, op := range ops {
   304  		if old := p.OpRanges[op]; old != "" && old != opstr {
   305  			if strings.Contains(old, opstr) {
   306  				opstr = old
   307  			} else if strings.Contains(opstr, old) {
   308  				// great, do nothing
   309  			} else {
   310  				// It would also be okay if there is some subsequence s such that
   311  				// old = x+s and opstr = s+y (or vice versa), in which case we should
   312  				// record opstr = x+s+y. However, this has not come up in practice.
   313  				// Failing that, we can't satisfy the sequencing requirements.
   314  				fmt.Fprintf(os.Stderr, "%s: %s appears in both %s and %s\n", text, op, old, opstr)
   315  			}
   316  		}
   317  	}
   318  	for _, op := range strings.Split(opstr, ",") {
   319  		if op != "" {
   320  			p.OpRanges[op] = opstr
   321  		}
   322  	}
   323  
   324  	// Process the arguments, building a list of argument descriptions.
   325  	// Each argument description has the form <argument>|field@off|field@off...
   326  	// where the |field@off suffixes give the name and location of the fields
   327  	// needed by the argument. Each such string maps to a different decoding
   328  	// type in the generated table, according to the argOps map.
   329  	var args []string
   330  	for argstr != "" {
   331  		// Find longest match among argSuffixes pieces.
   332  		best := 0
   333  		for a := range argSuffixes {
   334  			if argstr == a || strings.HasPrefix(argstr, a+",") {
   335  				if best < len(a) {
   336  					best = len(a)
   337  				}
   338  			}
   339  		}
   340  		if best == 0 {
   341  			fmt.Fprintf(os.Stderr, "%s: unknown arg %s\n", text, argstr)
   342  			break
   343  		}
   344  
   345  		var arg, desc string
   346  		arg, argstr = argstr[:best], strings.TrimSpace(strings.TrimLeft(argstr[best:], ","))
   347  		desc = arg
   348  		for _, f := range strings.Split(argSuffixes[desc], ",") {
   349  			if f == "" {
   350  				continue
   351  			}
   352  			if fieldWidth[f] == 0 {
   353  				fmt.Fprintf(os.Stderr, "%s: arg %s missing %s in encoding %s\n", text, arg, f, encoding)
   354  			}
   355  			fieldUsed[f] = true
   356  			desc += fmt.Sprintf("|%s@%d", f, fieldOffset[f])
   357  		}
   358  		args = append(args, desc)
   359  	}
   360  
   361  	// Check that all encoding fields were used by suffix or argument decoding.
   362  	for f := range fieldWidth {
   363  		switch f {
   364  		case "0", "1", "(0)", "(1)":
   365  			// ok
   366  		default:
   367  			if !fieldUsed[f] {
   368  				fmt.Fprintf(os.Stderr, "%s: encoding field %s not used in %s\n", text, f, encoding)
   369  			}
   370  		}
   371  	}
   372  
   373  	// Determine decoding priority. Instructions that say 'SEE X' in the tag
   374  	// are considered lower priority than ones that don't. In theory the
   375  	// structure described by the SEE tags might be richer than that, but
   376  	// in practice it only has those two levels.
   377  	// We leave space for two more priorities according to whether the
   378  	// fuzzy bits are set correctly. The full set of priorities then is:
   379  	//
   380  	//	4 - no SEE tag, fuzzy bits all match
   381  	//	3 - no SEE tag, some fuzzy bits don't match
   382  	//	2 - SEE tag, fuzzy bits all match
   383  	//	1 - SEE tag, some fuzzy bits don't match
   384  	//
   385  	// You could argue for swapping the middle two levels but so far
   386  	// it has not been an issue.
   387  	pri := 4
   388  	if strings.Contains(tags, "SEE") {
   389  		pri = 2
   390  	}
   391  
   392  	inst := Inst{
   393  		Text:     text,
   394  		Encoding: encoding,
   395  		Mask:     uint32(mask),
   396  		Value:    uint32(value),
   397  		Priority: pri,
   398  		OpBase:   ops[0],
   399  		OpBits:   opBits,
   400  		Args:     args,
   401  	}
   402  	p.Inst = append(p.Inst, inst)
   403  
   404  	if fuzzy != 0 {
   405  		inst.Mask &^= fuzzy
   406  		inst.Priority--
   407  		p.Inst = append(p.Inst, inst)
   408  	}
   409  }
   410  
   411  // opSuffix describes the encoding fields used to resolve a given opcode suffix.
   412  var opSuffix = map[string]string{
   413  	"<ADD,SUB>":                   "op",
   414  	"<BIF,BIT,BSL>":               "op:2",
   415  	"<MLA,MLS><c>.F<32,64>":       "op,cond:4,sz",
   416  	"<MLS,MLA><c>.F<32,64>":       "op,cond:4,sz",
   417  	"<BT,TB><c>":                  "tb,cond:4",
   418  	"<TBL,TBX>.8":                 "op",
   419  	"<c>":                         "cond:4",
   420  	"<c>.32":                      "cond:4",
   421  	"<c>.F<32,64>":                "cond:4,sz",
   422  	"<x><y><c>":                   "N,M,cond:4",
   423  	"<y><c>":                      "M,cond:4",
   424  	"{B}<c>":                      "B,cond:4",
   425  	"{E}<c>.F<32,64>":             "E,cond:4,sz",
   426  	"{R}<c>":                      "R,cond:4",
   427  	"<c>.F<32,64>.<U,S>32":        "cond:4,sz,op",
   428  	"<R,><c>.<U,S>32.F<32,64>":    "op,cond:4,signed,sz",
   429  	"{S}<c>":                      "S,cond:4",
   430  	"{W}":                         "R",
   431  	"{X}<c>":                      "M,cond:4",
   432  	"<B,T><c>.<F32.F16,F16.F32>":  "T,cond:4,op",
   433  	"<c>.<F64.F32,F32.F64>":       "cond:4,sz",
   434  	"<c>.FX<S,U><16,32>.F<32,64>": "cond:4,U,sx,sz",
   435  	"<c>.F<32,64>.FX<S,U><16,32>": "cond:4,sz,U,sx",
   436  }
   437  
   438  // choices[x] describes the choices for filling in "<"+x+">" in an opcode suffix.
   439  // Opcodes that end up containing ZZ take up a numeric sequence value but are
   440  // not exported in the package API.
   441  var choices = map[string][]string{
   442  	"c": {".EQ", ".NE", ".CS", ".CC", ".MI", ".PL", ".VS", ".VC", ".HI", ".LS", ".GE", ".LT", ".GT", ".LE", "", ".ZZ"},
   443  	"x": {"B", "T"},
   444  	"y": {"B", "T"},
   445  }
   446  
   447  // argOps maps from argument descriptions to internal decoder name.
   448  var argOps = map[string]string{
   449  	// 4-bit register encodings
   450  	"<Rm>|Rm:4@0":       "arg_R_0",
   451  	"<Rn>|Rn:4@0":       "arg_R_0",
   452  	"<Rt>|Rt:4@0":       "arg_R_0",
   453  	"<Rm>|Rm:4@8":       "arg_R_8",
   454  	"<Ra>|Ra:4@12":      "arg_R_12",
   455  	"<Rd>|Rd:4@12":      "arg_R_12",
   456  	"<RdLo>|RdLo:4@12":  "arg_R_12",
   457  	"<Rt>|Rt:4@12":      "arg_R_12",
   458  	"<Rt_nzcv>|Rt:4@12": "arg_R_12_nzcv",
   459  	"<Rd>|Rd:4@16":      "arg_R_16",
   460  	"<RdHi>|RdHi:4@16":  "arg_R_16",
   461  	"<Rn>|Rn:4@16":      "arg_R_16",
   462  
   463  	// first and second of consecutive register pair
   464  	"<Rt1>|Rt:4@0":  "arg_R1_0",
   465  	"<Rt1>|Rt:4@12": "arg_R1_12",
   466  	"<Rt2>|Rt:4@0":  "arg_R2_0",
   467  	"<Rt2>|Rt:4@12": "arg_R2_12",
   468  
   469  	// register arithmetic
   470  	"<Rm>,<type> <Rs>|Rm:4@0|Rs:4@8|type:2@5": "arg_R_shift_R",
   471  	"<Rm>{,<shift>}|Rm:4@0|imm5:5@7|type:2@5": "arg_R_shift_imm",
   472  	"<Rn>{,<shift>}|Rn:4@0|imm5:5@7|sh@6":     "arg_R_shift_imm",
   473  	"<Rm>{,LSL #<imm5>}|Rm:4@0|imm5:5@7":      "arg_R_shift_imm",
   474  	"<Rm>{,<rotation>}|Rm:4@0|rotate:2@10":    "arg_R_rotate",
   475  
   476  	// memory references
   477  	"<Rn>{!}|Rn:4@16|W@21": "arg_R_16_WB",
   478  	"[<Rn>]|Rn:4@16":       "arg_mem_R",
   479  	"[<Rn>,+/-<Rm>{, <shift>}]{!}|Rn:4@16|U@23|Rm:4@0|type:2@5|imm5:5@7|P@24|W@21": "arg_mem_R_pm_R_shift_imm_W",
   480  	"[<Rn>{,#+/-<imm8>}]{!}|Rn:4@16|P@24|U@23|W@21|imm4H:4@8|imm4L:4@0":            "arg_mem_R_pm_imm8_W",
   481  	"[<Rn>] {,#+/-<imm8>}|Rn:4@16|U@23|imm4H:4@8|imm4L:4@0":                        "arg_mem_R_pm_imm8_postindex",
   482  	"[<Rn>{,#+/-<imm12>}]{!}|Rn:4@16|P@24|U@23|W@21|imm12:12@0":                    "arg_mem_R_pm_imm12_W",
   483  	"[<Rn>],#+/-<imm12>|Rn:4@16|imm12:12@0|U@23":                                   "arg_mem_R_pm_imm12_postindex",
   484  	"[<Rn>,#+/-<imm12>]|Rn:4@16|U@23|imm12:12@0":                                   "arg_mem_R_pm_imm12_offset",
   485  	"[<Rn>] {,#+/-<imm12>}|Rn:4@16|U@23|imm12:12@0":                                "arg_mem_R_pm_imm12_postindex",
   486  	"[<Rn>], +/-<Rm>|Rn:4@16|U@23|Rm:4@0":                                          "arg_mem_R_pm_R_postindex",
   487  	"[<Rn>,+/-<Rm>]{!}|Rn:4@16|U@23|Rm:4@0|P@24|W@21":                              "arg_mem_R_pm_R_W",
   488  	"[<Rn>],+/-<Rm>{, <shift>}|Rn:4@16|Rm:4@0|imm5:5@7|type:2@5|U@23":              "arg_mem_R_pm_R_shift_imm_postindex",
   489  	"[<Rn>,+/-<Rm>{, <shift>}]|Rn:4@16|U@23|Rm:4@0|type:2@5|imm5:5@7":              "arg_mem_R_pm_R_shift_imm_offset",
   490  	"[<Rn>{,#+/-<imm8>}]|Rn:4@16|U@23|imm8:8@0":                                    "arg_mem_R_pm_imm8at0_offset",
   491  
   492  	// pc-relative constants
   493  	"<label+12>|imm12:12@0":                  "arg_label_p_12",
   494  	"<label-12>|imm12:12@0":                  "arg_label_m_12",
   495  	"<label+/-12>|imm12:12@0|U@23":           "arg_label_pm_12",
   496  	"<label+/-4+4>|imm4H:4@8|imm4L:4@0|U@23": "arg_label_pm_4_4",
   497  
   498  	// constants
   499  	"#<const>|imm12:12@0":             "arg_const",
   500  	"#<imm5>|imm5:5@7":                "arg_imm5",
   501  	"#<imm5_nz>|imm5:5@7":             "arg_imm5_nz",
   502  	"#<imm5_32>|imm5:5@7":             "arg_imm5_32",
   503  	"<label24>|imm24:24@0":            "arg_label24",
   504  	"#<lsb>|lsb:5@7":                  "arg_imm5",
   505  	"#<width>|lsb:5@7|msb:5@16":       "arg_lsb_width",
   506  	"#<imm12+4>|imm12:12@8|imm4:4@0":  "arg_imm_12at8_4at0",
   507  	"#<imm12+4>|imm12:12@0|imm4:4@16": "arg_imm_4at16_12at0",
   508  	"<label24H>|imm24:24@0|H@24":      "arg_label24H",
   509  	"#<option>|option:4@0":            "arg_option",
   510  	"#<widthm1>|widthm1:5@16":         "arg_widthm1",
   511  	"#<sat_imm4>|sat_imm:4@16":        "arg_satimm4",
   512  	"#<sat_imm5>|sat_imm:5@16":        "arg_satimm5",
   513  	"#<sat_imm4m1>|sat_imm:4@16":      "arg_satimm4m1",
   514  	"#<sat_imm5m1>|sat_imm:5@16":      "arg_satimm5m1",
   515  	"#<imm24>|imm24:24@0":             "arg_imm24",
   516  
   517  	// special
   518  	"<registers>|register_list:16@0":  "arg_registers",
   519  	"<registers2>|register_list:16@0": "arg_registers2",
   520  	"<registers1>|Rt:4@12":            "arg_registers1",
   521  	"<endian_specifier>|E@9":          "arg_endian",
   522  
   523  	"SP":    "arg_SP",
   524  	"APSR":  "arg_APSR",
   525  	"FPSCR": "arg_FPSCR",
   526  
   527  	// VFP floating point registers
   528  	"<Sd>|Vd:4@12|D@22":                    "arg_Sd",
   529  	"<Sd,Dd>|Vd:4@12|D@22|sz@8":            "arg_Sd_Dd",
   530  	"<Dd,Sd>|Vd:4@12|D@22|sz@8":            "arg_Dd_Sd",
   531  	"<Sn>|Vn:4@16|N@7":                     "arg_Sn",
   532  	"<Sn,Dn>|Vn:4@16|N@7|sz@8":             "arg_Sn_Dn",
   533  	"<Sm>|Vm:4@0|M@5":                      "arg_Sm",
   534  	"<Sm,Dm>|Vm:4@0|M@5|sz@8":              "arg_Sm_Dm",
   535  	"#0.0":                                 "arg_fp_0",
   536  	"#<imm_vfp>|imm4H:4@16|imm4L:4@0|sz@8": "arg_imm_vfp",
   537  	"#<fbits>|sx@7|imm4:4@0|i@5":           "arg_fbits",
   538  	"<Dn[x]>|N@7|Vn:4@16|opc1@21":          "arg_Dn_half",
   539  	"<Dd[x]>|D@7|Vd:4@16|opc1@21":          "arg_Dn_half",
   540  }
   541  
   542  // argSuffixes describes the encoding fields needed for a particular suffix.
   543  // The set of keys in argSuffixes also drives the identification of suffix pieces.
   544  // For example, <Rm> and <Rm>{, <type> <Rs>} are both keys in the map
   545  // and matching is done 'longest first', so "<Rm>, <Rm>{, <type> <Rs>}" is
   546  // parsed as just two arguments despite the extra ", ".
   547  // The field order in the map values must match the order expected in
   548  // the argument descriptions in argOps.
   549  var argSuffixes = map[string]string{
   550  	"#0":                           "",
   551  	"#0.0":                         "",
   552  	"#<const>":                     "imm12:12",
   553  	"#<fbits>":                     "sx,imm4:4,i",
   554  	"#<imm12+4>":                   "imm12:12,imm4:4",
   555  	"#<imm24>":                     "imm24:24",
   556  	"#<imm3>":                      "imm3:3",
   557  	"#<imm4>":                      "imm4:4",
   558  	"#<imm5>":                      "imm5:5",
   559  	"#<imm5_nz>":                   "imm5:5",
   560  	"#<imm5_32>":                   "imm5:5",
   561  	"#<imm6>":                      "imm6:6",
   562  	"#<immsize>":                   "size:2",
   563  	"#<imm_vfp>":                   "imm4H:4,imm4L:4,sz",
   564  	"#<sat_imm4>":                  "sat_imm:4",
   565  	"#<sat_imm5>":                  "sat_imm:5",
   566  	"#<sat_imm4m1>":                "sat_imm:4",
   567  	"#<sat_imm5m1>":                "sat_imm:5",
   568  	"#<lsb>":                       "lsb:5",
   569  	"#<option>":                    "option:4",
   570  	"#<width>":                     "lsb:5,msb:5",
   571  	"#<widthm1>":                   "widthm1:5",
   572  	"+/-<Rm>":                      "Rm:4,U",
   573  	"<Dd>":                         "D,Vd:4",
   574  	"<Dd[x]>":                      "D,Vd:4,opc1",
   575  	"<Dm>":                         "M,Vm:4",
   576  	"<Dm[x]>":                      "M,Vm:4,size:2",
   577  	"<Dn>":                         "N,Vn:4",
   578  	"<Dn[x]>":                      "N,Vn:4,opc1",
   579  	"<Dm[size_x]>":                 "imm4:4",
   580  	"<Qd>":                         "D,Vd:4",
   581  	"<Qm>":                         "M,Vm:4",
   582  	"<Qn>":                         "N,Vn:4",
   583  	"<Ra>":                         "Ra:4",
   584  	"<Rd>":                         "Rd:4",
   585  	"<RdHi>":                       "RdHi:4",
   586  	"<RdLo>":                       "RdLo:4",
   587  	"<Rm>":                         "Rm:4",
   588  	"<Rm>{,<rotation>}":            "Rm:4,rotate:2",
   589  	"<Rm>{,<shift>}":               "Rm:4,imm5:5,type:2",
   590  	"<Rm>{,LSL #<imm5>}":           "Rm:4,imm5:5",
   591  	"<Rn>":                         "Rn:4",
   592  	"<Rn>{!}":                      "Rn:4,W",
   593  	"<Rn>{,<shift>}":               "Rn:4,imm5:5,sh",
   594  	"<Rs>":                         "Rs:4",
   595  	"<Rt1>":                        "Rt:4",
   596  	"<Rt2>":                        "Rt:4",
   597  	"<Rt>":                         "Rt:4",
   598  	"<Rt_nzcv>":                    "Rt:4",
   599  	"<Sd>":                         "Vd:4,D",
   600  	"<Sm1>":                        "Vm:4,M",
   601  	"<Sm>":                         "Vm:4,M",
   602  	"<Sn>":                         "Vn:4,N",
   603  	"<Sd,Dd>":                      "Vd:4,D,sz",
   604  	"<Dd,Sd>":                      "Vd:4,D,sz",
   605  	"<Sn,Dn>":                      "Vn:4,N,sz",
   606  	"<Sm,Dm>":                      "Vm:4,M,sz",
   607  	"<endian_specifier>":           "E",
   608  	"<label+/-12>":                 "imm12:12,U",
   609  	"<label+12>":                   "imm12:12",
   610  	"<label-12>":                   "imm12:12",
   611  	"<label24>":                    "imm24:24",
   612  	"<label24H>":                   "imm24:24,H",
   613  	"<label+/-4+4>":                "imm4H:4,imm4L:4,U",
   614  	"<list4>":                      "D,Vd:4,type:4",
   615  	"<list3>":                      "D,Vd:4,index_align:4",
   616  	"<list3t>":                     "D,Vd:4,T",
   617  	"<list1>":                      "D,Vd:4",
   618  	"<list_len>":                   "N,Vn:4,len:2",
   619  	"<vlist32>":                    "D,Vd:4,imm8:8",
   620  	"<vlist64>":                    "D,Vd:4,imm8:8",
   621  	"<registers>":                  "register_list:16",
   622  	"<registers2>":                 "register_list:16",
   623  	"<registers1>":                 "Rt:4",
   624  	"APSR":                         "",
   625  	"<Rm>,<type> <Rs>":             "Rm:4,Rs:4,type:2",
   626  	"FPSCR":                        "",
   627  	"SP":                           "",
   628  	"[<Rn>,#+/-<imm12>]":           "Rn:4,U,imm12:12",
   629  	"[<Rn>,+/-<Rm>]{!}":            "Rn:4,U,Rm:4,P,W",
   630  	"[<Rn>,+/-<Rm>{, <shift>}]":    "Rn:4,U,Rm:4,type:2,imm5:5",
   631  	"[<Rn>,+/-<Rm>{, <shift>}]{!}": "Rn:4,U,Rm:4,type:2,imm5:5,P,W",
   632  	"[<Rn>] {,#+/-<imm12>}":        "Rn:4,U,imm12:12",
   633  	"[<Rn>] {,#+/-<imm8>}":         "Rn:4,U,imm4H:4,imm4L:4",
   634  	"[<Rn>]":                       "Rn:4",
   635  	"[<Rn>],#+/-<imm12>":           "Rn:4,imm12:12,U",
   636  	"[<Rn>],+/-<Rm>{, <shift>}":    "Rn:4,Rm:4,imm5:5,type:2,U",
   637  	"[<Rn>]{!}":                    "Rn:4,Rm:4",
   638  	"[<Rn>{@<align>}]{!}":          "XXX",
   639  	"[<Rn>{,#+/-<imm12>}]{!}":      "Rn:4,P,U,W,imm12:12",
   640  	"[<Rn>{,#+/-<imm8>}]{!}":       "Rn:4,P,U,W,imm4H:4,imm4L:4",
   641  	"[<Rn>{,#+/-<imm8>}]":          "Rn:4,U,imm8:8",
   642  	"[<Rn>], +/-<Rm>":              "Rn:4,U,Rm:4",
   643  	"#<imm_simd1>":                 "i,imm3:3,imm4:4,cmode:4",
   644  	"#<imm_simd>":                  "op,i,imm3:3,imm4:4,cmode:4",
   645  	"#<imm_vs>":                    "L,imm6:6",
   646  	"#<imm_vsn>":                   "imm6:6",
   647  }
   648  
   649  // cross returns the string concatenation cross product of xs and ys.
   650  func cross(xs []string, ys ...string) []string {
   651  	var xys []string
   652  
   653  	for _, x := range xs {
   654  		for _, y := range ys {
   655  			xys = append(xys, x+y)
   656  		}
   657  	}
   658  	return xys
   659  }
   660  
   661  // crossCond returns the cross product of xs with all the possible
   662  // conditional execution suffixes. It is assumed that each string x in xs
   663  // contains a substring _COND_ marking where the conditional suffix
   664  // should be placed.
   665  func crossCond(xs []string) []string {
   666  	ys := choices["c"]
   667  	var xys []string
   668  
   669  	for _, x := range xs {
   670  		i := strings.Index(x, "_COND_")
   671  		pre, post := x[:i], x[i+6:]
   672  		for _, y := range ys {
   673  			xys = append(xys, pre+y+post)
   674  		}
   675  	}
   676  	return xys
   677  }
   678  
   679  // printText implements the -fmt=text mode, which is not implemented (yet?).
   680  func printText(p *Prog) {
   681  	log.Fatal("-fmt=text not implemented")
   682  }
   683  
   684  // printDecoder implements the -fmt=decoder mode.
   685  // It emits the tables.go for package armasm's decoder.
   686  func printDecoder(p *Prog) {
   687  	fmt.Printf("package armasm\n\n")
   688  
   689  	// Build list of opcodes sorted by name
   690  	// but preserving the sequential ranges needed for opcode decoding.
   691  	haveRange := make(map[string]string)
   692  	for _, r := range p.OpRanges {
   693  		haveRange[r] = r
   694  	}
   695  	var ranges []string
   696  	for _, r := range haveRange {
   697  		ranges = append(ranges, r)
   698  	}
   699  	sort.Strings(ranges)
   700  
   701  	// Emit const definitions for opcodes.
   702  	fmt.Printf("const (\n")
   703  	iota := 0
   704  	fmt.Printf("\t_ Op = iota\n")
   705  	iota++
   706  	for _, r := range ranges {
   707  		for _, op := range strings.Split(r, ",") {
   708  			if op == "" {
   709  				continue
   710  			}
   711  			// Assume if opcode says .EQ it is the start of a 16-wide
   712  			// iteration through the conditional suffixes. If so, emit
   713  			// blank names until the assigned value is 16-aligned.
   714  			if strings.Contains(op, ".EQ") {
   715  				for iota&15 != 0 {
   716  					fmt.Printf("\t_\n")
   717  					iota++
   718  				}
   719  			}
   720  			fmt.Printf("\t%s\n", strings.Replace(op, ".", "_", -1))
   721  			iota++
   722  		}
   723  	}
   724  	fmt.Printf(")\n")
   725  
   726  	// Emit slice mapping opcode number to name string.
   727  	fmt.Printf("\nvar opstr = [...]string{\n")
   728  	for _, r := range ranges {
   729  		for _, op := range strings.Split(r, ",") {
   730  			if op == "" {
   731  				continue
   732  			}
   733  			fmt.Printf("\t%s: %q,\n", strings.Replace(op, ".", "_", -1), op)
   734  		}
   735  	}
   736  	fmt.Printf("}\n")
   737  
   738  	// Emit decoding table.
   739  	unknown := map[string]bool{}
   740  	fmt.Printf("\nvar instFormats = [...]instFormat{\n")
   741  	for _, inst := range p.Inst {
   742  		fmt.Printf("\t{%#08x, %#08x, %d, %s, %#x, instArgs{", inst.Mask, inst.Value, inst.Priority, strings.Replace(inst.OpBase, ".", "_", -1), inst.OpBits)
   743  		for i, a := range inst.Args {
   744  			if i > 0 {
   745  				fmt.Printf(", ")
   746  			}
   747  			str := argOps[a]
   748  			if str == "" && !unknown[a] {
   749  				fmt.Fprintf(os.Stderr, "%s: unknown arg %s\n", inst.Text, a)
   750  				unknown[a] = true
   751  			}
   752  			fmt.Printf("%s", str)
   753  		}
   754  		fmt.Printf("}}, // %s %s\n", inst.Text, inst.Encoding)
   755  	}
   756  	fmt.Printf("}\n")
   757  }
   758  

View as plain text