cpu_arm64.mx raw

   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  package cpu
   6  
   7  import "runtime"
   8  
   9  // cacheLineSize is used to prevent false sharing of cache lines.
  10  // We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size.
  11  // It doesn't cost much and is much more future-proof.
  12  const cacheLineSize = 128
  13  
  14  func initOptions() {
  15  	options = []option{
  16  		{Name: "fp", Feature: &ARM64.HasFP},
  17  		{Name: "asimd", Feature: &ARM64.HasASIMD},
  18  		{Name: "evstrm", Feature: &ARM64.HasEVTSTRM},
  19  		{Name: "aes", Feature: &ARM64.HasAES},
  20  		{Name: "fphp", Feature: &ARM64.HasFPHP},
  21  		{Name: "jscvt", Feature: &ARM64.HasJSCVT},
  22  		{Name: "lrcpc", Feature: &ARM64.HasLRCPC},
  23  		{Name: "pmull", Feature: &ARM64.HasPMULL},
  24  		{Name: "sha1", Feature: &ARM64.HasSHA1},
  25  		{Name: "sha2", Feature: &ARM64.HasSHA2},
  26  		{Name: "sha3", Feature: &ARM64.HasSHA3},
  27  		{Name: "sha512", Feature: &ARM64.HasSHA512},
  28  		{Name: "sm3", Feature: &ARM64.HasSM3},
  29  		{Name: "sm4", Feature: &ARM64.HasSM4},
  30  		{Name: "sve", Feature: &ARM64.HasSVE},
  31  		{Name: "sve2", Feature: &ARM64.HasSVE2},
  32  		{Name: "crc32", Feature: &ARM64.HasCRC32},
  33  		{Name: "atomics", Feature: &ARM64.HasATOMICS},
  34  		{Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
  35  		{Name: "cpuid", Feature: &ARM64.HasCPUID},
  36  		{Name: "asimrdm", Feature: &ARM64.HasASIMDRDM},
  37  		{Name: "fcma", Feature: &ARM64.HasFCMA},
  38  		{Name: "dcpop", Feature: &ARM64.HasDCPOP},
  39  		{Name: "asimddp", Feature: &ARM64.HasASIMDDP},
  40  		{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
  41  		{Name: "dit", Feature: &ARM64.HasDIT},
  42  		{Name: "i8mm", Feature: &ARM64.HasI8MM},
  43  	}
  44  }
  45  
  46  func archInit() {
  47  	switch runtime.GOOS {
  48  	case "freebsd":
  49  		readARM64Registers()
  50  	case "linux", "netbsd", "openbsd":
  51  		doinit()
  52  	default:
  53  		// Many platforms don't seem to allow reading these registers.
  54  		setMinimalFeatures()
  55  	}
  56  }
  57  
  58  // setMinimalFeatures fakes the minimal ARM64 features expected by
  59  // TestARM64minimalFeatures.
  60  func setMinimalFeatures() {
  61  	ARM64.HasASIMD = true
  62  	ARM64.HasFP = true
  63  }
  64  
  65  func readARM64Registers() {
  66  	Initialized = true
  67  
  68  	parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0())
  69  }
  70  
  71  func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
  72  	// ID_AA64ISAR0_EL1
  73  	switch extractBits(isar0, 4, 7) {
  74  	case 1:
  75  		ARM64.HasAES = true
  76  	case 2:
  77  		ARM64.HasAES = true
  78  		ARM64.HasPMULL = true
  79  	}
  80  
  81  	switch extractBits(isar0, 8, 11) {
  82  	case 1:
  83  		ARM64.HasSHA1 = true
  84  	}
  85  
  86  	switch extractBits(isar0, 12, 15) {
  87  	case 1:
  88  		ARM64.HasSHA2 = true
  89  	case 2:
  90  		ARM64.HasSHA2 = true
  91  		ARM64.HasSHA512 = true
  92  	}
  93  
  94  	switch extractBits(isar0, 16, 19) {
  95  	case 1:
  96  		ARM64.HasCRC32 = true
  97  	}
  98  
  99  	switch extractBits(isar0, 20, 23) {
 100  	case 2:
 101  		ARM64.HasATOMICS = true
 102  	}
 103  
 104  	switch extractBits(isar0, 28, 31) {
 105  	case 1:
 106  		ARM64.HasASIMDRDM = true
 107  	}
 108  
 109  	switch extractBits(isar0, 32, 35) {
 110  	case 1:
 111  		ARM64.HasSHA3 = true
 112  	}
 113  
 114  	switch extractBits(isar0, 36, 39) {
 115  	case 1:
 116  		ARM64.HasSM3 = true
 117  	}
 118  
 119  	switch extractBits(isar0, 40, 43) {
 120  	case 1:
 121  		ARM64.HasSM4 = true
 122  	}
 123  
 124  	switch extractBits(isar0, 44, 47) {
 125  	case 1:
 126  		ARM64.HasASIMDDP = true
 127  	}
 128  
 129  	// ID_AA64ISAR1_EL1
 130  	switch extractBits(isar1, 0, 3) {
 131  	case 1:
 132  		ARM64.HasDCPOP = true
 133  	}
 134  
 135  	switch extractBits(isar1, 12, 15) {
 136  	case 1:
 137  		ARM64.HasJSCVT = true
 138  	}
 139  
 140  	switch extractBits(isar1, 16, 19) {
 141  	case 1:
 142  		ARM64.HasFCMA = true
 143  	}
 144  
 145  	switch extractBits(isar1, 20, 23) {
 146  	case 1:
 147  		ARM64.HasLRCPC = true
 148  	}
 149  
 150  	switch extractBits(isar1, 52, 55) {
 151  	case 1:
 152  		ARM64.HasI8MM = true
 153  	}
 154  
 155  	// ID_AA64PFR0_EL1
 156  	switch extractBits(pfr0, 16, 19) {
 157  	case 0:
 158  		ARM64.HasFP = true
 159  	case 1:
 160  		ARM64.HasFP = true
 161  		ARM64.HasFPHP = true
 162  	}
 163  
 164  	switch extractBits(pfr0, 20, 23) {
 165  	case 0:
 166  		ARM64.HasASIMD = true
 167  	case 1:
 168  		ARM64.HasASIMD = true
 169  		ARM64.HasASIMDHP = true
 170  	}
 171  
 172  	switch extractBits(pfr0, 32, 35) {
 173  	case 1:
 174  		ARM64.HasSVE = true
 175  
 176  		parseARM64SVERegister(getzfr0())
 177  	}
 178  
 179  	switch extractBits(pfr0, 48, 51) {
 180  	case 1:
 181  		ARM64.HasDIT = true
 182  	}
 183  }
 184  
 185  func parseARM64SVERegister(zfr0 uint64) {
 186  	switch extractBits(zfr0, 0, 3) {
 187  	case 1:
 188  		ARM64.HasSVE2 = true
 189  	}
 190  }
 191  
 192  func extractBits(data uint64, start, end uint) uint {
 193  	return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
 194  }
 195