...

Source file src/golang.org/x/arch/arm64/arm64gen/sysreggen.go

Documentation: golang.org/x/arch/arm64/arm64gen

     1  // Copyright 2019 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  // This file is an automatic parser program that parses arm64
     6  // system register XML files to get the encoding information
     7  // and writes them to the sysRegEnc.go file. The sysRegEnc.go
     8  // file is used for the system register encoding.
     9  // Follow the following steps to run the automatic parser program:
    10  // 1. The system register XML files are from
    11  // https://developer.arm.com/-/media/Files/ATG/Beta10/SysReg_xml_v85A-2019-06.tar.gz
    12  // 2. Extract SysReg_xml_v85A-2019-06.tar/SysReg_xml_v85A-2019-06/SysReg_xml_v85A-2019-06/AArch64-*.xml
    13  // to a "xmlfolder" folder.
    14  // 3. Run the command: ./sysrengen -i "xmlfolder" -o "filename"
    15  // By default, the xmlfolder is "./files" and the filename is "sysRegEnc.go".
    16  // 4. Put the automaically generated file into $GOROOT/src/cmd/internal/obj/arm64 directory.
    17  
    18  package main
    19  
    20  import (
    21  	"bufio"
    22  	"encoding/xml"
    23  	"flag"
    24  	"fmt"
    25  	"io/ioutil"
    26  	"log"
    27  	"os"
    28  	"path/filepath"
    29  	"strconv"
    30  	"strings"
    31  )
    32  
    33  // Types corresponded to the data structures in the XML file.
    34  
    35  type RegisterPage struct {
    36  	XMLName   xml.Name  `xml:"register_page"`
    37  	Registers Registers `xml:"registers"`
    38  }
    39  
    40  type Registers struct {
    41  	XMLName  xml.Name `xml:"registers"`
    42  	Register Register `xml:"register"`
    43  }
    44  
    45  type Register struct {
    46  	XMLName          xml.Name         `xml:"register"`
    47  	RegShortName     string           `xml:"reg_short_name"`
    48  	RegVariables     RegVariables     `xml:"reg_variables"`
    49  	AccessMechanisms AccessMechanisms `xml:"access_mechanisms"`
    50  }
    51  
    52  type RegVariables struct {
    53  	XMLName     xml.Name    `xml:"reg_variables"`
    54  	RegVariable RegVariable `xml:"reg_variable"`
    55  }
    56  
    57  type RegVariable struct {
    58  	XMLName  xml.Name `xml:"reg_variable"`
    59  	Variable string   `xml:"variable,attr"`
    60  	Max      string   `xml:"max,attr"`
    61  }
    62  
    63  type AccessMechanisms struct {
    64  	XMLName         xml.Name          `xml:"access_mechanisms"`
    65  	AccessMechanism []AccessMechanism `xml:"access_mechanism"`
    66  }
    67  
    68  type AccessMechanism struct {
    69  	XMLName  xml.Name `xml:"access_mechanism"`
    70  	Accessor string   `xml:"accessor,attr"`
    71  	Encoding Encoding `xml:"encoding"`
    72  }
    73  
    74  type Encoding struct {
    75  	XMLName xml.Name `xml:"encoding"`
    76  	Enc     []Enc    `xml:"enc"`
    77  }
    78  
    79  type Enc struct {
    80  	XMLName xml.Name `xml:"enc"`
    81  	V       string   `xml:"v,attr"`
    82  }
    83  
    84  type SystemReg struct {
    85  	RegName        string
    86  	EncBinary      uint32
    87  	RegAccessFlags string
    88  }
    89  
    90  func check(e error) {
    91  	if e != nil {
    92  		log.Fatal(e)
    93  	}
    94  }
    95  
    96  type accessFlag uint8
    97  
    98  const (
    99  	SR_READ accessFlag = 1 << iota
   100  	SR_WRITE
   101  )
   102  
   103  func (a accessFlag) String() string {
   104  	switch a {
   105  	case SR_READ:
   106  		return "SR_READ"
   107  	case SR_WRITE:
   108  		return "SR_WRITE"
   109  	case SR_READ | SR_WRITE:
   110  		return "SR_READ | SR_WRITE"
   111  	default:
   112  		return ""
   113  	}
   114  }
   115  
   116  func main() {
   117  	// Write system register encoding to the sysRegEnc.go file.
   118  	// This file should be put into $GOROOT/src/cmd/internal/obj/arm64/ directory.
   119  	filename := flag.String("o", "sysRegEnc.go", "the name of the automatically generated file")
   120  	xmlfolder := flag.String("i", "./files", "the folder where the data XML files are")
   121  	flag.Parse()
   122  
   123  	out, err := os.Create(*filename)
   124  	check(err)
   125  	defer out.Close()
   126  
   127  	files, err := ioutil.ReadDir(*xmlfolder)
   128  	check(err)
   129  
   130  	var systemregs []SystemReg
   131  	regNum := 0
   132  
   133  	for _, file := range files {
   134  		xmlFile, err := os.Open(filepath.Join(*xmlfolder, file.Name()))
   135  		check(err)
   136  		value, err := ioutil.ReadAll(xmlFile)
   137  		check(err)
   138  
   139  		var regpage RegisterPage
   140  		err = xml.Unmarshal(value, &regpage)
   141  		if err != nil {
   142  			log.Printf("%s: The data of this file does not fit into Register_page struct\n", file.Name())
   143  			xmlFile.Close()
   144  			continue
   145  		}
   146  
   147  		sysreg := regpage.Registers.Register
   148  		sysregName := sysreg.RegShortName
   149  		if strings.Contains(sysregName, "EL2") || strings.Contains(sysregName, "EL3") {
   150  			log.Printf("%s: we do not support EL2 and EL3 system registers at the moment!\n", file.Name())
   151  			xmlFile.Close()
   152  			continue
   153  		}
   154  		if strings.Contains(sysregName, "<op1>_<Cn>_<Cm>_<op2>") {
   155  			log.Printf("%s: The register %s is reserved\n", file.Name(), sysregName)
   156  			xmlFile.Close()
   157  			continue
   158  		}
   159  		if len(sysreg.AccessMechanisms.AccessMechanism) == 0 {
   160  			log.Printf("%s: The data of this file does not fit into AccessMechanisms struct\n", file.Name())
   161  			xmlFile.Close()
   162  			continue
   163  		}
   164  
   165  		m0 := sysreg.AccessMechanisms.AccessMechanism[0]
   166  		ins := m0.Accessor
   167  		if !(strings.Contains(ins, "MRS") || strings.Contains(ins, "MSR")) {
   168  			log.Printf("%s: \"%s\" is not a system register for MSR and MRS instructions.\n", file.Name(), sysregName)
   169  			xmlFile.Close()
   170  			continue
   171  		}
   172  
   173  		m := sysreg.AccessMechanisms.AccessMechanism
   174  		accessF := accessFlag(0)
   175  		for j := range m {
   176  			accessor := m[j].Accessor
   177  			if strings.Contains(accessor, "MRS") {
   178  				accessF |= SR_READ
   179  			}
   180  			if strings.Contains(accessor, "MSR") {
   181  				accessF |= SR_WRITE
   182  			}
   183  		}
   184  		aFlags := accessF.String()
   185  
   186  		max := 0
   187  		var enc [5]uint64
   188  		if len(m0.Encoding.Enc) != 5 {
   189  			log.Printf("%s: The data of this file does not fit into S<op0>_<op1>_<Cn>_<Cm>_<op2> encoding\n", file.Name())
   190  			xmlFile.Close()
   191  			continue
   192  		}
   193  		// Special handling for system register name containing <n>.
   194  		if strings.Contains(sysregName, "<n>") {
   195  			max, err = strconv.Atoi(sysreg.RegVariables.RegVariable.Max)
   196  			check(err)
   197  			for n := 0; n <= max; n++ {
   198  				name := strings.Replace(sysregName, "<n>", strconv.Itoa(n), -1)
   199  				systemregs = append(systemregs, SystemReg{name, 0, aFlags})
   200  				regNum++
   201  			}
   202  		} else {
   203  			systemregs = append(systemregs, SystemReg{sysregName, 0, aFlags})
   204  			regNum++
   205  		}
   206  		for i := 0; i <= max; i++ {
   207  			index := regNum - 1 - max + i
   208  			for j := 0; j < len(m0.Encoding.Enc); j++ {
   209  				value := m0.Encoding.Enc[j].V
   210  				// value="0b010:n[3]"
   211  				// value="0b1:n[1:0]"
   212  				// value="ob10:n[4:3]"
   213  				if strings.Contains(value, "n") && strings.Contains(value, "b") {
   214  					v0 := strings.Split(value, "b")
   215  					v1 := strings.Split(v0[1], "n")
   216  					v2 := strings.Trim(v1[1], "[]")
   217  					bits, err := strconv.ParseUint(strings.Trim(v1[0], ":"), 2, 32)
   218  					check(err)
   219  					if strings.Contains(v1[1], ":") {
   220  						// v1[1]="[1:0]", v2="1:0"
   221  						// Get the index.
   222  						first, err := strconv.Atoi(strings.Split(v2, ":")[0])
   223  						check(err)
   224  						last, err := strconv.Atoi(strings.Split(v2, ":")[1])
   225  						check(err)
   226  						// Get the corresponding appended bits.
   227  						bitsAppend := (i >> uint(last) & (1<<uint(first-last+1) - 1))
   228  						// Join the bits to get the final bits.
   229  						finalBits := int(bits)<<uint(first-last+1) | bitsAppend
   230  						enc[j] = uint64(finalBits)
   231  					} else {
   232  						// v1[1]="[3]", v2="3"
   233  						// Get the corresponding appended bits.
   234  						first, err := strconv.Atoi(v2)
   235  						check(err)
   236  						bitsAppend := (i >> uint(first)) & 1
   237  						// Join the bits to get the final bits.
   238  						finalBits := int(bits)<<1 | bitsAppend
   239  						enc[j] = uint64(finalBits)
   240  					}
   241  				} else if strings.Contains(value, "n") && !strings.Contains(value, "b") {
   242  					// value="n[3:0]" | value="n[2:0]"
   243  					v0 := strings.Split(value, "n")
   244  					v1 := strings.Trim(v0[1], "[]")
   245  					v2 := strings.Split(v1, ":")
   246  					// Convert string format to integer.
   247  					first, err := strconv.Atoi(v2[0])
   248  					check(err)
   249  					last, err := strconv.Atoi(v2[1])
   250  					check(err)
   251  					finalBits := (i >> uint(last) & (1<<uint(first-last+1) - 1))
   252  					enc[j] = uint64(finalBits)
   253  				} else {
   254  					// value="0b110"
   255  					v := strings.Split(value, "b")
   256  					var err error = nil
   257  					enc[j], err = strconv.ParseUint(v[1], 2, 64)
   258  					check(err)
   259  				}
   260  			}
   261  			systemregs[index].EncBinary = uint32(enc[0]<<19 | enc[1]<<16 | enc[2]<<12 | enc[3]<<8 | enc[4]<<5)
   262  		}
   263  		// Close the xml file.
   264  		xmlFile.Close()
   265  	}
   266  	log.Printf("The total number of parsing registers is %d\n", regNum)
   267  	w := bufio.NewWriter(out)
   268  	fmt.Fprintf(w, "// Code generated by arm64gen -i %s -o %s. DO NOT EDIT.\n", *xmlfolder, *filename)
   269  	fmt.Fprintln(w, "\npackage arm64\n\nconst (\n\tSYSREG_BEGIN = REG_SPECIAL + iota")
   270  	for i := 0; i < regNum; i++ {
   271  		fmt.Fprintf(w, "\tREG_%s\n", systemregs[i].RegName)
   272  	}
   273  	fmt.Fprintln(w, "\tSYSREG_END\n)")
   274  	fmt.Fprintln(w, `
   275  const (
   276  	SR_READ = 1 << iota
   277  	SR_WRITE
   278  )
   279  
   280  var SystemReg = []struct {
   281  	Name string
   282  	Reg int16
   283  	Enc uint32
   284  	// AccessFlags is the readable and writeable property of system register.
   285  	AccessFlags uint8
   286  }{`)
   287  	for i := 0; i < regNum; i++ {
   288  		fmt.Fprintf(w, "\t{\"%s\", REG_%s, 0x%x, %s},\n", systemregs[i].RegName, systemregs[i].RegName, systemregs[i].EncBinary, systemregs[i].RegAccessFlags)
   289  	}
   290  	fmt.Fprintln(w, "}")
   291  	fmt.Fprintln(w, `
   292  func SysRegEnc(r int16) (string, uint32, uint8) {
   293  	// The automatic generator guarantees that the order
   294  	// of Reg in SystemReg struct is consistent with the
   295  	// order of system register declarations
   296  	if r <= SYSREG_BEGIN || r >= SYSREG_END {
   297  		return "", 0, 0
   298  	}
   299  	v := SystemReg[r-SYSREG_BEGIN-1]
   300  	return v.Name, v.Enc, v.AccessFlags
   301  }`)
   302  	w.Flush()
   303  }
   304  

View as plain text