arm64/arm64gen: get system register readable and writeable attribute

This patch gets the readable and writeable property of system register from the
generator sysreggen.go and writes it to the sysRegEnc.go file. This attribute
would be used by assembler to check the correctness of system register's
read/write access for MRS/MSR instruction.

Change-Id: I637f86710c9f53e9e621d1dd6b7c4142f7bd4c11
Reviewed-on: https://go-review.googlesource.com/c/arch/+/194937
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/arm64/arm64gen/sysreggen.go b/arm64/arm64gen/sysreggen.go
index 1394831..5c42532 100644
--- a/arm64/arm64gen/sysreggen.go
+++ b/arm64/arm64gen/sysreggen.go
@@ -82,8 +82,9 @@
 }
 
 type SystemReg struct {
-	RegName   string
-	EncBinary uint32
+	RegName        string
+	EncBinary      uint32
+	RegAccessFlags string
 }
 
 func check(e error) {
@@ -92,6 +93,26 @@
 	}
 }
 
+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.
@@ -149,6 +170,19 @@
 			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 {
@@ -162,11 +196,11 @@
 			check(err)
 			for n := 0; n <= max; n++ {
 				name := strings.Replace(sysregName, "<n>", strconv.Itoa(n), -1)
-				systemregs = append(systemregs, SystemReg{name, 0})
+				systemregs = append(systemregs, SystemReg{name, 0, aFlags})
 				regNum++
 			}
 		} else {
-			systemregs = append(systemregs, SystemReg{sysregName, 0})
+			systemregs = append(systemregs, SystemReg{sysregName, 0, aFlags})
 			regNum++
 		}
 		for i := 0; i <= max; i++ {
@@ -237,15 +271,33 @@
 		fmt.Fprintf(w, "\tREG_%s\n", systemregs[i].RegName)
 	}
 	fmt.Fprintln(w, "\tSYSREG_END\n)")
-	fmt.Fprintln(w, "\nvar SystemReg = []struct {\n\tName string\n\tReg int16\n\tEnc uint32\n}{")
+	fmt.Fprintln(w, `
+const (
+	SR_READ = 1 << iota
+	SR_WRITE
+)
+
+var SystemReg = []struct {
+	Name string
+	Reg int16
+	Enc uint32
+	// AccessFlags is the readable and writeable property of system register.
+	AccessFlags uint8
+}{`)
 	for i := 0; i < regNum; i++ {
-		fmt.Fprintf(w, "\t{\"%s\", REG_%s, 0x%x},\n", systemregs[i].RegName, systemregs[i].RegName, systemregs[i].EncBinary)
+		fmt.Fprintf(w, "\t{\"%s\", REG_%s, 0x%x, %s},\n", systemregs[i].RegName, systemregs[i].RegName, systemregs[i].EncBinary, systemregs[i].RegAccessFlags)
 	}
 	fmt.Fprintln(w, "}")
-	fmt.Fprintln(w, "\nfunc SysRegEnc(r int16) (string, uint32) {")
-	fmt.Fprintln(w, "\t// The automatic generator guarantees that the order")
-	fmt.Fprintln(w, "\t// of Reg in SystemReg struct is consistent with the")
-	fmt.Fprintln(w, "\t// order of system register declarations")
-	fmt.Fprintln(w, "\tif r <= SYSREG_BEGIN || r >= SYSREG_END {\n\t\treturn \"\", 0\n\t}\n\tv := SystemReg[r-SYSREG_BEGIN-1]\n\treturn v.Name, v.Enc\n}")
+	fmt.Fprintln(w, `
+func SysRegEnc(r int16) (string, uint32, uint8) {
+	// The automatic generator guarantees that the order
+	// of Reg in SystemReg struct is consistent with the
+	// order of system register declarations
+	if r <= SYSREG_BEGIN || r >= SYSREG_END {
+		return "", 0, 0
+	}
+	v := SystemReg[r-SYSREG_BEGIN-1]
+	return v.Name, v.Enc, v.AccessFlags
+}`)
 	w.Flush()
 }