// Copyright 2019 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. // This file is an automatic parser program that parses arm64 // system register XML files to get the encoding information // and writes them to the sysRegEnc.go file. The sysRegEnc.go // file is used for the system register encoding. // Follow the following steps to run the automatic parser program: // 1. The system register XML files are from // https://developer.arm.com/-/media/Files/ATG/Beta10/SysReg_xml_v85A-2019-06.tar.gz // 2. Extract SysReg_xml_v85A-2019-06.tar/SysReg_xml_v85A-2019-06/SysReg_xml_v85A-2019-06/AArch64-*.xml // to a "xmlfolder" folder. // 3. Run the command: ./sysrengen -i "xmlfolder" -o "filename" // By default, the xmlfolder is "./files" and the filename is "sysRegEnc.go". // 4. Put the automaically generated file into $GOROOT/src/cmd/internal/obj/arm64 directory. package main import ( "bufio" "encoding/xml" "flag" "fmt" "io/ioutil" "log" "os" "path/filepath" "strconv" "strings" ) // Types corresponded to the data structures in the XML file. type RegisterPage struct { XMLName xml.Name `xml:"register_page"` Registers Registers `xml:"registers"` } type Registers struct { XMLName xml.Name `xml:"registers"` Register Register `xml:"register"` } type Register struct { XMLName xml.Name `xml:"register"` RegShortName string `xml:"reg_short_name"` RegVariables RegVariables `xml:"reg_variables"` AccessMechanisms AccessMechanisms `xml:"access_mechanisms"` } type RegVariables struct { XMLName xml.Name `xml:"reg_variables"` RegVariable RegVariable `xml:"reg_variable"` } type RegVariable struct { XMLName xml.Name `xml:"reg_variable"` Variable string `xml:"variable,attr"` Max string `xml:"max,attr"` } type AccessMechanisms struct { XMLName xml.Name `xml:"access_mechanisms"` AccessMechanism []AccessMechanism `xml:"access_mechanism"` } type AccessMechanism struct { XMLName xml.Name `xml:"access_mechanism"` Accessor string `xml:"accessor,attr"` Encoding Encoding `xml:"encoding"` } type Encoding struct { XMLName xml.Name `xml:"encoding"` Enc []Enc `xml:"enc"` } type Enc struct { XMLName xml.Name `xml:"enc"` V string `xml:"v,attr"` } type SystemReg struct { RegName string EncBinary uint32 RegAccessFlags string } func check(e error) { if e != nil { log.Fatal(e) } } type accessFlag uint8 const ( SR_READ accessFlag = 1 << iota SR_WRITE ) func (a accessFlag) String() string { switch a { case SR_READ: return "SR_READ" case SR_WRITE: return "SR_WRITE" case SR_READ | SR_WRITE: return "SR_READ | SR_WRITE" default: return "" } } func main() { // Write system register encoding to the sysRegEnc.go file. // This file should be put into $GOROOT/src/cmd/internal/obj/arm64/ directory. filename := flag.String("o", "sysRegEnc.go", "the name of the automatically generated file") xmlfolder := flag.String("i", "./files", "the folder where the data XML files are") flag.Parse() out, err := os.Create(*filename) check(err) defer out.Close() files, err := ioutil.ReadDir(*xmlfolder) check(err) var systemregs []SystemReg regNum := 0 for _, file := range files { xmlFile, err := os.Open(filepath.Join(*xmlfolder, file.Name())) check(err) value, err := ioutil.ReadAll(xmlFile) check(err) var regpage RegisterPage err = xml.Unmarshal(value, ®page) if err != nil { log.Printf("%s: The data of this file does not fit into Register_page struct\n", file.Name()) xmlFile.Close() continue } sysreg := regpage.Registers.Register sysregName := sysreg.RegShortName if strings.Contains(sysregName, "EL2") || strings.Contains(sysregName, "EL3") { log.Printf("%s: we do not support EL2 and EL3 system registers at the moment!\n", file.Name()) xmlFile.Close() continue } if strings.Contains(sysregName, "___") { log.Printf("%s: The register %s is reserved\n", file.Name(), sysregName) xmlFile.Close() continue } if len(sysreg.AccessMechanisms.AccessMechanism) == 0 { log.Printf("%s: The data of this file does not fit into AccessMechanisms struct\n", file.Name()) xmlFile.Close() continue } m0 := sysreg.AccessMechanisms.AccessMechanism[0] ins := m0.Accessor if !(strings.Contains(ins, "MRS") || strings.Contains(ins, "MSR")) { log.Printf("%s: \"%s\" is not a system register for MSR and MRS instructions.\n", file.Name(), sysregName) xmlFile.Close() continue } m := sysreg.AccessMechanisms.AccessMechanism accessF := accessFlag(0) for j := range m { accessor := m[j].Accessor if strings.Contains(accessor, "MRS") { accessF |= SR_READ } if strings.Contains(accessor, "MSR") { accessF |= SR_WRITE } } aFlags := accessF.String() max := 0 var enc [5]uint64 if len(m0.Encoding.Enc) != 5 { log.Printf("%s: The data of this file does not fit into S____ encoding\n", file.Name()) xmlFile.Close() continue } // Special handling for system register name containing . if strings.Contains(sysregName, "") { max, err = strconv.Atoi(sysreg.RegVariables.RegVariable.Max) check(err) for n := 0; n <= max; n++ { name := strings.Replace(sysregName, "", strconv.Itoa(n), -1) systemregs = append(systemregs, SystemReg{name, 0, aFlags}) regNum++ } } else { systemregs = append(systemregs, SystemReg{sysregName, 0, aFlags}) regNum++ } for i := 0; i <= max; i++ { index := regNum - 1 - max + i for j := 0; j < len(m0.Encoding.Enc); j++ { value := m0.Encoding.Enc[j].V // value="0b010:n[3]" // value="0b1:n[1:0]" // value="ob10:n[4:3]" if strings.Contains(value, "n") && strings.Contains(value, "b") { v0 := strings.Split(value, "b") v1 := strings.Split(v0[1], "n") v2 := strings.Trim(v1[1], "[]") bits, err := strconv.ParseUint(strings.Trim(v1[0], ":"), 2, 32) check(err) if strings.Contains(v1[1], ":") { // v1[1]="[1:0]", v2="1:0" // Get the index. first, err := strconv.Atoi(strings.Split(v2, ":")[0]) check(err) last, err := strconv.Atoi(strings.Split(v2, ":")[1]) check(err) // Get the corresponding appended bits. bitsAppend := (i >> uint(last) & (1<> uint(first)) & 1 // Join the bits to get the final bits. finalBits := int(bits)<<1 | bitsAppend enc[j] = uint64(finalBits) } } else if strings.Contains(value, "n") && !strings.Contains(value, "b") { // value="n[3:0]" | value="n[2:0]" v0 := strings.Split(value, "n") v1 := strings.Trim(v0[1], "[]") v2 := strings.Split(v1, ":") // Convert string format to integer. first, err := strconv.Atoi(v2[0]) check(err) last, err := strconv.Atoi(v2[1]) check(err) finalBits := (i >> uint(last) & (1<= SYSREG_END { return "", 0, 0 } v := SystemReg[r-SYSREG_BEGIN-1] return v.Name, v.Enc, v.AccessFlags }`) w.Flush() }