1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
118
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
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
211
212
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
221
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
227 bitsAppend := (i >> uint(last) & (1<<uint(first-last+1) - 1))
228
229 finalBits := int(bits)<<uint(first-last+1) | bitsAppend
230 enc[j] = uint64(finalBits)
231 } else {
232
233
234 first, err := strconv.Atoi(v2)
235 check(err)
236 bitsAppend := (i >> uint(first)) & 1
237
238 finalBits := int(bits)<<1 | bitsAppend
239 enc[j] = uint64(finalBits)
240 }
241 } else if strings.Contains(value, "n") && !strings.Contains(value, "b") {
242
243 v0 := strings.Split(value, "n")
244 v1 := strings.Trim(v0[1], "[]")
245 v2 := strings.Split(v1, ":")
246
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
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
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