...

Source file src/golang.org/x/arch/arm/armspec/specmap.go

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

     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  //go:build ignore
     6  
     7  package main
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"log"
    14  	"os"
    15  	"regexp"
    16  	"strconv"
    17  	"strings"
    18  )
    19  
    20  var _ = os.Stdout
    21  var _ = fmt.Sprintf
    22  
    23  type Inst struct {
    24  	Name   string
    25  	ID     string
    26  	Bits   string
    27  	Arch   string
    28  	Syntax []string
    29  	Code   string
    30  	Base   uint32
    31  	Mask   uint32
    32  	Prog   []*Stmt
    33  }
    34  
    35  func main() {
    36  	data, err := ioutil.ReadFile("spec.json")
    37  	if err != nil {
    38  		log.Fatal(err)
    39  	}
    40  	var insts []Inst
    41  	if err := json.Unmarshal(data, &insts); err != nil {
    42  		log.Fatal(err)
    43  	}
    44  
    45  	var out []Inst
    46  	for _, inst := range insts {
    47  		inst.Prog = parse(inst.Name+" "+inst.ID, inst.Code)
    48  		if inst.ID[0] == 'A' && !strings.HasPrefix(inst.Syntax[0], "MSR<c>") && !strings.Contains(inst.Syntax[0], "<coproc>") && !strings.Contains(inst.Syntax[0], "VLDM") && !strings.Contains(inst.Syntax[0], "VSTM") {
    49  			out = append(out, inst)
    50  		}
    51  	}
    52  	insts = out
    53  
    54  	for i := range insts {
    55  		dosize(&insts[i])
    56  	}
    57  
    58  	var cond, special []Inst
    59  	for _, inst := range insts {
    60  		if inst.Base>>28 == 0xF {
    61  			special = append(special, inst)
    62  		} else {
    63  			cond = append(cond, inst)
    64  		}
    65  	}
    66  
    67  	fmt.Printf("special:\n")
    68  	split(special, 0xF0000000, 1)
    69  	fmt.Printf("cond:\n")
    70  	split(cond, 0xF0000000, 1)
    71  }
    72  
    73  func dosize(inst *Inst) {
    74  	var base, mask uint32
    75  	off := 0
    76  	for _, f := range strings.Split(inst.Bits, "|") {
    77  		if i := strings.Index(f, ":"); i >= 0 {
    78  			n, _ := strconv.Atoi(f[i+1:])
    79  			off += n
    80  			continue
    81  		}
    82  		for _, bit := range strings.Fields(f) {
    83  			switch bit {
    84  			case "0", "(0)":
    85  				mask |= 1 << uint(31-off)
    86  			case "1", "(1)":
    87  				base |= 1 << uint(31-off)
    88  			}
    89  			off++
    90  		}
    91  	}
    92  	if off != 16 && off != 32 {
    93  		log.Printf("incorrect bit count for %s %s: have %d", inst.Name, inst.Bits, off)
    94  	}
    95  	if off == 16 {
    96  		mask >>= 16
    97  		base >>= 16
    98  	}
    99  	mask |= base
   100  	inst.Mask = mask
   101  	inst.Base = base
   102  }
   103  
   104  func split(insts []Inst, used uint32, depth int) {
   105  Again:
   106  	if len(insts) <= 1 {
   107  		for _, inst := range insts {
   108  			fmt.Printf("%*s%#08x %#08x %s %s %v\n", depth*2+2, "", inst.Mask, inst.Base, inst.Syntax[0], inst.Bits, seeRE.FindAllString(inst.Code, -1))
   109  		}
   110  		return
   111  	}
   112  
   113  	m := ^used
   114  	for _, inst := range insts {
   115  		m &= inst.Mask
   116  	}
   117  	if m == 0 {
   118  		fmt.Printf("«%*s%#08x masked out (%d)\n", depth*2, "", used, len(insts))
   119  		for _, inst := range insts {
   120  			fmt.Printf("%*s%#08x %#08x %s %s %v\n", depth*2+2, "", inst.Mask, inst.Base, inst.Syntax[0], inst.Bits, seeRE.FindAllString(inst.Code, -1))
   121  		}
   122  		updated := false
   123  		for i := range insts {
   124  			if updateMask(&insts[i]) {
   125  				updated = true
   126  			}
   127  		}
   128  		fmt.Printf("»\n")
   129  		if updated {
   130  			goto Again
   131  		}
   132  		fmt.Printf("%*s%#08x masked out (%d)\n", depth*2, "", used, len(insts))
   133  		for _, inst := range insts {
   134  			fmt.Printf("%*s%#08x %#08x %s %s %v\n", depth*2+2, "", inst.Mask, inst.Base, inst.Syntax[0], inst.Bits, seeRE.FindAllString(inst.Code, -1))
   135  		}
   136  		//checkOverlap(used, insts)
   137  		return
   138  	}
   139  	for i := 31; i >= 0; i-- {
   140  		if m&(1<<uint(i)) != 0 {
   141  			m = 1 << uint(i)
   142  			break
   143  		}
   144  	}
   145  	var bit [2][]Inst
   146  	for _, inst := range insts {
   147  		b := (inst.Base / m) & 1
   148  		bit[b] = append(bit[b], inst)
   149  	}
   150  
   151  	for b, list := range bit {
   152  		if len(list) > 0 {
   153  			suffix := ""
   154  			if len(bit[1-b]) == 0 {
   155  				suffix = " (only)"
   156  			}
   157  			fmt.Printf("%*sbit %#08x = %d%s\n", depth*2, "", m, b, suffix)
   158  			split(list, used|m, depth+1)
   159  		}
   160  	}
   161  }
   162  
   163  var seeRE = regexp.MustCompile(`SEE ([^;\n]+)`)
   164  
   165  func updateMask(inst *Inst) bool {
   166  	defer func() {
   167  		if err := recover(); err != nil {
   168  			fmt.Println("PANIC:", err)
   169  			return
   170  		}
   171  	}()
   172  
   173  	print(".")
   174  	println(inst.Name, inst.ID, inst.Bits)
   175  	println(inst.Code)
   176  	wiggle := ^inst.Mask &^ 0xF0000000
   177  	n := countbits(wiggle)
   178  	m1 := ^uint32(0)
   179  	m2 := ^uint32(0)
   180  	for i := uint32(0); i < 1<<uint(n); i++ {
   181  		w := inst.Base | expand(i, wiggle)
   182  		if !isValid(inst, w) {
   183  			continue
   184  		}
   185  		m1 &= w
   186  		m2 &= ^w
   187  	}
   188  	m := m1 | m2
   189  	m &^= 0xF0000000
   190  	m |= 0xF0000000 & inst.Mask
   191  	if m&^inst.Mask != 0 {
   192  		fmt.Printf("%s %s: mask=%#x but decided %#x\n", inst.Name, inst.ID, inst.Mask, m)
   193  		inst.Mask = m
   194  		inst.Base = m1
   195  		return true
   196  	}
   197  	if inst.Mask&^m != 0 {
   198  		fmt.Printf("%s %s: mask=%#x but got %#x\n", inst.Name, inst.ID, inst.Mask, m)
   199  		panic("bad updateMask")
   200  	}
   201  	return false
   202  }
   203  
   204  func countbits(x uint32) int {
   205  	n := 0
   206  	for ; x != 0; x >>= 1 {
   207  		n += int(x & 1)
   208  	}
   209  	return n
   210  }
   211  
   212  func expand(x, m uint32) uint32 {
   213  	var out uint32
   214  	for i := uint(0); i < 32; i++ {
   215  		out >>= 1
   216  		if m&1 != 0 {
   217  			out |= (x & 1) << 31
   218  			x >>= 1
   219  		}
   220  		m >>= 1
   221  	}
   222  	return out
   223  }
   224  

View as plain text