golang.org/x/arch@v0.17.0/arm64/arm64gen/sysreggen.go (about) 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, ®page) 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 }