diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
new file mode 100644
index 0000000..47137ee
--- /dev/null
+++ b/.github/workflows/go.yml
@@ -0,0 +1,57 @@
+name: Go
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  build:
+    strategy:
+      matrix:
+        go-version: [1.15.x, 1.16.x, 1.17.x]
+        os: [ubuntu-latest, macos-latest, windows-latest]  
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Set up Go
+      uses: actions/setup-go@v2
+      with:
+        go-version: ${{ matrix.go-version }}
+
+    - name: Vet
+      run: go vet ./...
+
+    - name: Test
+      run: go test ./...
+
+    - name: Test Noasm
+      run: go test -tags=noasm ./...
+      
+  build-special:
+    env:
+      CGO_ENABLED: 0
+    runs-on: ubuntu-latest
+    steps:
+    - name: Set up Go
+      uses: actions/setup-go@v2      
+      with:
+        go-version: 1.16.x
+
+    - name: Checkout code
+      uses: actions/checkout@v2
+
+    - name: fmt
+      run: diff <(gofmt -d .) <(printf "")
+
+    - name: Test 386
+      run: GOOS=linux GOARCH=386 go test -short ./...
+
+    - name: goreleaser deprecation
+      run: curl -sfL https://git.io/goreleaser | VERSION=v0.162.0 sh -s -- check
+      
+    - name: goreleaser snapshot
+      run: curl -sL https://git.io/goreleaser | VERSION=v0.162.0 sh -s -- --snapshot --skip-publish --rm-dist
+       
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..91b70c3
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,30 @@
+name: goreleaser
+
+on:
+  push:
+    tags:
+      - 'v*'
+
+jobs:
+  goreleaser:
+    runs-on: ubuntu-latest
+    steps:
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      -
+        name: Set up Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.16
+      -
+        name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v2
+        with:
+          version: 0.162.0
+          args: release --rm-dist
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          CGO_ENABLED: 0
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index aa9bad7..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-language: go
-
-os:
-  - linux
-  - osx
-  - windows
-
-arch:
-  - amd64
-  - arm64
-
-go:
-  - 1.13.x
-  - 1.14.x
-  - 1.15.x
-  - 1.16.x
-  - master
-
-env:
-  - CGO_ENABLED=0
-
-script:
-  - go vet ./...
-  - go test -test.v -test.run ^TestCPUID$
-  - CGO_ENABLED=1 go test -race ./...
-  - go test -tags=nounsafe -test.v -test.run ^TestCPUID$
-  - go test -tags=noasm ./...
-  - go run ./cmd/cpuid/main.go
-  - go run ./cmd/cpuid/main.go -json
-
-matrix:
-  allow_failures:
-    - go: 'master'
-  fast_finish: true
-  include:
-    - stage: other
-      go: 1.16.x
-      os: linux
-      arch: amd64
-      script:
-        - diff <(gofmt -d .) <(printf "")
-        - diff <(gofmt -d ./private) <(printf "")
-        - curl -sfL https://git.io/goreleaser | VERSION=v0.157.0 sh -s -- check # check goreleaser config for deprecations
-        - curl -sL https://git.io/goreleaser | VERSION=v0.157.0 sh -s -- --snapshot --skip-publish --rm-dist
-        - go get github.com/klauspost/asmfmt&&go install github.com/klauspost/asmfmt/cmd/asmfmt
-        - diff <(asmfmt -d .) <(printf "")
-        - GOOS=linux GOARCH=386 go test .
-        - ./test-architectures.sh
-    - stage: other
-      go: 1.15.x
-      os: linux
-      arch: amd64
-      script:
-        - ./test-architectures.sh
-
-deploy:
-  - provider: script
-    skip_cleanup: true
-    script: curl -sL https://git.io/goreleaser | VERSION=v0.157.0 bash || true
-    on:
-      tags: true
-      condition: ($TRAVIS_OS_NAME = linux) && ($TRAVIS_CPU_ARCH = amd64)
-      go: 1.16.x
-branches:
-  only:
-    - master
-    - /^v\d+\.\d+(\.\d+)?(-\S*)?$/
diff --git a/README.md b/README.md
index 465f4b7..bc2f98f 100644
--- a/README.md
+++ b/README.md
@@ -39,10 +39,10 @@ func main() {
 	fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
 	fmt.Println("LogicalCores:", CPU.LogicalCores)
 	fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID)
-	fmt.Println("Features:", fmt.Sprintf(strings.Join(CPU.FeatureSet(), ",")))
+	fmt.Println("Features:", strings.Join(CPU.FeatureSet(), ","))
 	fmt.Println("Cacheline bytes:", CPU.CacheLine)
 	fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes")
-	fmt.Println("L1 Instruction Cache:", CPU.Cache.L1D, "bytes")
+	fmt.Println("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
 	fmt.Println("L2 Cache:", CPU.Cache.L2, "bytes")
 	fmt.Println("L3 Cache:", CPU.Cache.L3, "bytes")
 	fmt.Println("Frequency", CPU.Hz, "hz")
diff --git a/cmd/cpuid/main.go b/cmd/cpuid/main.go
index 14cc805..5869a4b 100644
--- a/cmd/cpuid/main.go
+++ b/cmd/cpuid/main.go
@@ -14,6 +14,7 @@ import (
 	"encoding/json"
 	"flag"
 	"fmt"
+	"log"
 	"os"
 	"strings"
 
@@ -21,11 +22,33 @@ import (
 )
 
 var js = flag.Bool("json", false, "Output as JSON")
+var level = flag.Int("check-level", 0, "Check microarchitecture level. Exit code will be 0 if supported")
 
 func main() {
 	flag.Parse()
+	if level != nil && *level > 0 {
+		if *level < 1 || *level > 4 {
+			log.Fatalln("Supply CPU level 1-4 to test as argument")
+		}
+		log.Println(cpuid.CPU.BrandName)
+		if cpuid.CPU.X64Level() < *level {
+			// Does os.Exit(1)
+			log.Fatalf("Microarchitecture level %d not supported. Max level is %d.", *level, cpuid.CPU.X64Level())
+		}
+		log.Printf("Microarchitecture level %d is supported. Max level is %d.", *level, cpuid.CPU.X64Level())
+		os.Exit(0)
+	}
 	if *js {
-		b, err := json.MarshalIndent(cpuid.CPU, "", "  ")
+		info := struct {
+			cpuid.CPUInfo
+			Features []string
+			X64Level int
+		}{
+			CPUInfo:  cpuid.CPU,
+			Features: cpuid.CPU.FeatureSet(),
+			X64Level: cpuid.CPU.X64Level(),
+		}
+		b, err := json.MarshalIndent(info, "", "  ")
 		if err != nil {
 			panic(err)
 		}
@@ -40,7 +63,8 @@ func main() {
 	fmt.Println("Threads Per Core:", cpuid.CPU.ThreadsPerCore)
 	fmt.Println("Logical Cores:", cpuid.CPU.LogicalCores)
 	fmt.Println("CPU Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model)
-	fmt.Println("Features:", fmt.Sprintf(strings.Join(cpuid.CPU.FeatureSet(), ",")))
+	fmt.Println("Features:", strings.Join(cpuid.CPU.FeatureSet(), ","))
+	fmt.Println("Microarchitecture level:", cpuid.CPU.X64Level())
 	fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine)
 	fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1I, "bytes")
 	fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes")
@@ -49,6 +73,9 @@ func main() {
 	if cpuid.CPU.Hz > 0 {
 		fmt.Println("Frequency:", cpuid.CPU.Hz, "Hz")
 	}
+	if cpuid.CPU.BoostFreq > 0 {
+		fmt.Println("Boost Frequency:", cpuid.CPU.BoostFreq, "Hz")
+	}
 	if cpuid.CPU.SGX.Available {
 		fmt.Printf("SGX: %+v\n", cpuid.CPU.SGX)
 	}
diff --git a/cpuid.go b/cpuid.go
index 43e9cc1..3d543ce 100644
--- a/cpuid.go
+++ b/cpuid.go
@@ -83,6 +83,7 @@ const (
 	AVX512DQ                            // AVX-512 Doubleword and Quadword Instructions
 	AVX512ER                            // AVX-512 Exponential and Reciprocal Instructions
 	AVX512F                             // AVX-512 Foundation
+	AVX512FP16                          // AVX-512 FP16 Instructions
 	AVX512IFMA                          // AVX-512 Integer Fused Multiply-Add Instructions
 	AVX512PF                            // AVX-512 Prefetch Instructions
 	AVX512VBMI                          // AVX-512 Vector Bit Manipulation Instructions
@@ -94,18 +95,26 @@ const (
 	AVXSLOW                             // Indicates the CPU performs 2 128 bit operations instead of one.
 	BMI1                                // Bit Manipulation Instruction Set 1
 	BMI2                                // Bit Manipulation Instruction Set 2
+	CETIBT                              // Intel CET Indirect Branch Tracking
+	CETSS                               // Intel CET Shadow Stack
 	CLDEMOTE                            // Cache Line Demote
 	CLMUL                               // Carry-less Multiplication
+	CLZERO                              // CLZERO instruction supported
 	CMOV                                // i686 CMOV
+	CMPXCHG8                            // CMPXCHG8 instruction
+	CPBOOST                             // Core Performance Boost
 	CX16                                // CMPXCHG16B Instruction
 	ENQCMD                              // Enqueue Command
 	ERMS                                // Enhanced REP MOVSB/STOSB
 	F16C                                // Half-precision floating-point conversion
 	FMA3                                // Intel FMA 3. Does not imply AVX.
 	FMA4                                // Bulldozer FMA4 functions
+	FXSR                                // FXSAVE, FXRESTOR instructions, CR4 bit 9
+	FXSROPT                             // FXSAVE/FXRSTOR optimizations
 	GFNI                                // Galois Field New Instructions
 	HLE                                 // Hardware Lock Elision
 	HTT                                 // Hyperthreading (enabled)
+	HWA                                 // Hardware assert supported. Indicates support for MSRC001_10
 	HYPERVISOR                          // This bit has been reserved by Intel & AMD for use by hypervisors
 	IBPB                                // Indirect Branch Restricted Speculation (IBRS) and Indirect Branch Predictor Barrier (IBPB)
 	IBS                                 // Instruction Based Sampling (AMD)
@@ -117,18 +126,29 @@ const (
 	IBSOPSAM                            // Instruction Based Sampling Feature (AMD)
 	IBSRDWROPCNT                        // Instruction Based Sampling Feature (AMD)
 	IBSRIPINVALIDCHK                    // Instruction Based Sampling Feature (AMD)
+	INT_WBINVD                          // WBINVD/WBNOINVD are interruptible.
+	INVLPGB                             // NVLPGB and TLBSYNC instruction supported
+	LAHF                                // LAHF/SAHF in long mode
 	LZCNT                               // LZCNT instruction
+	MCAOVERFLOW                         // MCA overflow recovery support.
+	MCOMMIT                             // MCOMMIT instruction supported
 	MMX                                 // standard MMX
 	MMXEXT                              // SSE integer functions or AMD MMX ext
+	MOVBE                               // MOVBE instruction (big-endian)
 	MOVDIR64B                           // Move 64 Bytes as Direct Store
 	MOVDIRI                             // Move Doubleword as Direct Store
 	MPX                                 // Intel MPX (Memory Protection Extensions)
+	MSRIRC                              // Instruction Retired Counter MSR available
 	NX                                  // NX (No-Execute) bit
+	OSXSAVE                             // XSAVE enabled by OS
 	POPCNT                              // POPCNT instruction
+	RDPRU                               // RDPRU instruction supported
 	RDRAND                              // RDRAND instruction is available
 	RDSEED                              // RDSEED instruction is available
 	RDTSCP                              // RDTSCP Instruction
 	RTM                                 // Restricted Transactional Memory
+	RTM_ALWAYS_ABORT                    // Indicates that the loaded microcode is forcing RTM abort.
+	SCE                                 // SYSENTER and SYSEXIT instructions
 	SERIALIZE                           // Serialize Instruction Execution
 	SGX                                 // Software Guard Extensions
 	SGXLC                               // Software Guard Extensions Launch Control
@@ -141,6 +161,7 @@ const (
 	SSE4A                               // AMD Barcelona microarchitecture SSE4a instructions
 	SSSE3                               // Conroe SSSE3 functions
 	STIBP                               // Single Thread Indirect Branch Predictors
+	SUCCOR                              // Software uncorrectable error containment and recovery capability.
 	TBM                                 // AMD Trailing Bit Manipulation
 	TSXLDTRK                            // Intel TSX Suspend Load Address Tracking
 	VAES                                // Vector AES
@@ -148,7 +169,9 @@ const (
 	VPCLMULQDQ                          // Carry-Less Multiplication Quadword
 	WAITPKG                             // TPAUSE, UMONITOR, UMWAIT
 	WBNOINVD                            // Write Back and Do Not Invalidate Cache
+	X87                                 // FPU
 	XOP                                 // Bulldozer XOP functions
+	XSAVE                               // XSAVE, XRESTOR, XSETBV, XGETBV
 
 	// ARM features:
 	AESARM   // AES instructions
@@ -194,7 +217,8 @@ type CPUInfo struct {
 	Family         int     // CPU family number
 	Model          int     // CPU model number
 	CacheLine      int     // Cache line size in bytes. Will be 0 if undetectable.
-	Hz             int64   // Clock speed, if known, 0 otherwise
+	Hz             int64   // Clock speed, if known, 0 otherwise. Will attempt to contain base clock speed.
+	BoostFreq      int64   // Max clock speed, if known, 0 otherwise
 	Cache          struct {
 		L1I int // L1 Instruction Cache (per core or shared). Will be -1 if undetected
 		L1D int // L1 Data Cache (per core or shared). Will be -1 if undetected
@@ -298,6 +322,31 @@ func (c CPUInfo) Has(id FeatureID) bool {
 	return c.featureSet.inSet(id)
 }
 
+// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
+var level1Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2)
+var level2Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3)
+var level3Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE)
+var level4Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE, AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL)
+
+// X64Level returns the microarchitecture level detected on the CPU.
+// If features are lacking or non x64 mode, 0 is returned.
+// See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
+func (c CPUInfo) X64Level() int {
+	if c.featureSet.hasSet(level4Features) {
+		return 4
+	}
+	if c.featureSet.hasSet(level3Features) {
+		return 3
+	}
+	if c.featureSet.hasSet(level2Features) {
+		return 2
+	}
+	if c.featureSet.hasSet(level1Features) {
+		return 1
+	}
+	return 0
+}
+
 // Disable will disable one or several features.
 func (c *CPUInfo) Disable(ids ...FeatureID) bool {
 	for _, id := range ids {
@@ -322,9 +371,7 @@ func (c CPUInfo) IsVendor(v Vendor) bool {
 
 func (c CPUInfo) FeatureSet() []string {
 	s := make([]string, 0)
-	for _, f := range c.featureSet.Strings() {
-		s = append(s, f)
-	}
+	s = append(s, c.featureSet.Strings()...)
 	return s
 }
 
@@ -363,25 +410,42 @@ func (c CPUInfo) LogicalCPU() int {
 	return int(ebx >> 24)
 }
 
-// hertz tries to compute the clock speed of the CPU. If leaf 15 is
+// frequencies tries to compute the clock speed of the CPU. If leaf 15 is
 // supported, use it, otherwise parse the brand string. Yes, really.
-func hertz(model string) int64 {
+func (c *CPUInfo) frequencies() {
+	c.Hz, c.BoostFreq = 0, 0
 	mfi := maxFunctionID()
 	if mfi >= 0x15 {
 		eax, ebx, ecx, _ := cpuid(0x15)
 		if eax != 0 && ebx != 0 && ecx != 0 {
-			return int64((int64(ecx) * int64(ebx)) / int64(eax))
+			c.Hz = (int64(ecx) * int64(ebx)) / int64(eax)
+		}
+	}
+	if mfi >= 0x16 {
+		a, b, _, _ := cpuid(0x16)
+		// Base...
+		if a&0xffff > 0 {
+			c.Hz = int64(a&0xffff) * 1_000_000
+		}
+		// Boost...
+		if b&0xffff > 0 {
+			c.BoostFreq = int64(b&0xffff) * 1_000_000
 		}
 	}
+	if c.Hz > 0 {
+		return
+	}
+
 	// computeHz determines the official rated speed of a CPU from its brand
 	// string. This insanity is *actually the official documented way to do
 	// this according to Intel*, prior to leaf 0x15 existing. The official
 	// documentation only shows this working for exactly `x.xx` or `xxxx`
 	// cases, e.g., `2.50GHz` or `1300MHz`; this parser will accept other
 	// sizes.
+	model := c.BrandName
 	hz := strings.LastIndex(model, "Hz")
 	if hz < 3 {
-		return 0
+		return
 	}
 	var multiplier int64
 	switch model[hz-1] {
@@ -393,7 +457,7 @@ func hertz(model string) int64 {
 		multiplier = 1000 * 1000 * 1000 * 1000
 	}
 	if multiplier == 0 {
-		return 0
+		return
 	}
 	freq := int64(0)
 	divisor := int64(0)
@@ -405,21 +469,22 @@ func hertz(model string) int64 {
 			decimalShift *= 10
 		} else if model[i] == '.' {
 			if divisor != 0 {
-				return 0
+				return
 			}
 			divisor = decimalShift
 		} else {
-			return 0
+			return
 		}
 	}
 	// we didn't find a space
 	if i < 0 {
-		return 0
+		return
 	}
 	if divisor != 0 {
-		return (freq * multiplier) / divisor
+		c.Hz = (freq * multiplier) / divisor
+		return
 	}
-	return freq * multiplier
+	c.Hz = freq * multiplier
 }
 
 // VM Will return true if the cpu id indicates we are in
@@ -468,6 +533,24 @@ func (s *flagSet) or(other flagSet) {
 	}
 }
 
+// hasSet returns whether all features are present.
+func (s flagSet) hasSet(other flagSet) bool {
+	for i, v := range other[:] {
+		if s[i]&v != v {
+			return false
+		}
+	}
+	return true
+}
+
+func flagSetWith(feat ...FeatureID) flagSet {
+	var res flagSet
+	for _, f := range feat {
+		res.set(f)
+	}
+	return res
+}
+
 // ParseFeature will parse the string and return the ID of the matching feature.
 // Will return UNKNOWN if not found.
 func ParseFeature(s string) FeatureID {
@@ -677,6 +760,7 @@ func (c *CPUInfo) cacheSize() {
 		if maxFunctionID() < 4 {
 			return
 		}
+		c.Cache.L1I, c.Cache.L1D, c.Cache.L2, c.Cache.L3 = 0, 0, 0, 0
 		for i := uint32(0); ; i++ {
 			eax, ebx, ecx, _ := cpuidex(4, i)
 			cacheType := eax & 15
@@ -769,8 +853,6 @@ func (c *CPUInfo) cacheSize() {
 			}
 		}
 	}
-
-	return
 }
 
 type SGXEPCSection struct {
@@ -834,9 +916,14 @@ func support() flagSet {
 	family, model := familyModel()
 
 	_, _, c, d := cpuid(1)
+	fs.setIf((d&(1<<0)) != 0, X87)
+	fs.setIf((d&(1<<8)) != 0, CMPXCHG8)
+	fs.setIf((d&(1<<11)) != 0, SCE)
 	fs.setIf((d&(1<<15)) != 0, CMOV)
+	fs.setIf((d&(1<<22)) != 0, MMXEXT)
 	fs.setIf((d&(1<<23)) != 0, MMX)
-	fs.setIf((d&(1<<25)) != 0, MMXEXT)
+	fs.setIf((d&(1<<24)) != 0, FXSR)
+	fs.setIf((d&(1<<25)) != 0, FXSROPT)
 	fs.setIf((d&(1<<25)) != 0, SSE)
 	fs.setIf((d&(1<<26)) != 0, SSE2)
 	fs.setIf((c&1) != 0, SSE3)
@@ -846,6 +933,7 @@ func support() flagSet {
 	fs.setIf((c&0x00100000) != 0, SSE42)
 	fs.setIf((c&(1<<25)) != 0, AESNI)
 	fs.setIf((c&(1<<1)) != 0, CLMUL)
+	fs.setIf(c&(1<<22) != 0, MOVBE)
 	fs.setIf(c&(1<<23) != 0, POPCNT)
 	fs.setIf(c&(1<<30) != 0, RDRAND)
 
@@ -861,6 +949,8 @@ func support() flagSet {
 	if vend == AMD && (d&(1<<28)) != 0 && mfi >= 4 {
 		fs.setIf(threadsPerCore() > 1, HTT)
 	}
+	fs.setIf(c&1<<26 != 0, XSAVE)
+	fs.setIf(c&1<<27 != 0, OSXSAVE)
 	// Check XGETBV/XSAVE (26), OXSAVE (27) and AVX (28) bits
 	const avxCheck = 1<<26 | 1<<27 | 1<<28
 	if c&avxCheck == avxCheck {
@@ -905,14 +995,17 @@ func support() flagSet {
 		fs.setIf(ebx&(1<<29) != 0, SHA)
 		// CPUID.(EAX=7, ECX=0).ECX
 		fs.setIf(ecx&(1<<5) != 0, WAITPKG)
+		fs.setIf(ecx&(1<<7) != 0, CETSS)
 		fs.setIf(ecx&(1<<25) != 0, CLDEMOTE)
 		fs.setIf(ecx&(1<<27) != 0, MOVDIRI)
 		fs.setIf(ecx&(1<<28) != 0, MOVDIR64B)
 		fs.setIf(ecx&(1<<29) != 0, ENQCMD)
 		fs.setIf(ecx&(1<<30) != 0, SGXLC)
 		// CPUID.(EAX=7, ECX=0).EDX
+		fs.setIf(edx&(1<<11) != 0, RTM_ALWAYS_ABORT)
 		fs.setIf(edx&(1<<14) != 0, SERIALIZE)
 		fs.setIf(edx&(1<<16) != 0, TSXLDTRK)
+		fs.setIf(edx&(1<<20) != 0, CETIBT)
 		fs.setIf(edx&(1<<26) != 0, IBPB)
 		fs.setIf(edx&(1<<27) != 0, STIBP)
 
@@ -949,6 +1042,7 @@ func support() flagSet {
 				// edx
 				fs.setIf(edx&(1<<8) != 0, AVX512VP2INTERSECT)
 				fs.setIf(edx&(1<<22) != 0, AMXBF16)
+				fs.setIf(edx&(1<<23) != 0, AVX512FP16)
 				fs.setIf(edx&(1<<24) != 0, AMXTILE)
 				fs.setIf(edx&(1<<25) != 0, AMXINT8)
 				// eax1 = CPUID.(EAX=7, ECX=1).EAX
@@ -963,6 +1057,7 @@ func support() flagSet {
 			fs.set(LZCNT)
 			fs.set(POPCNT)
 		}
+		fs.setIf((c&(1<<0)) != 0, LAHF)
 		fs.setIf((c&(1<<10)) != 0, IBS)
 		fs.setIf((d&(1<<31)) != 0, AMD3DNOW)
 		fs.setIf((d&(1<<30)) != 0, AMD3DNOWEXT)
@@ -980,9 +1075,23 @@ func support() flagSet {
 		}
 
 	}
+	if maxExtendedFunction() >= 0x80000007 {
+		_, b, _, d := cpuid(0x80000007)
+		fs.setIf((b&(1<<0)) != 0, MCAOVERFLOW)
+		fs.setIf((b&(1<<1)) != 0, SUCCOR)
+		fs.setIf((b&(1<<2)) != 0, HWA)
+		fs.setIf((d&(1<<9)) != 0, CPBOOST)
+	}
+
 	if maxExtendedFunction() >= 0x80000008 {
 		_, b, _, _ := cpuid(0x80000008)
 		fs.setIf((b&(1<<9)) != 0, WBNOINVD)
+		fs.setIf((b&(1<<8)) != 0, MCOMMIT)
+		fs.setIf((b&(1<<13)) != 0, INT_WBINVD)
+		fs.setIf((b&(1<<4)) != 0, RDPRU)
+		fs.setIf((b&(1<<3)) != 0, INVLPGB)
+		fs.setIf((b&(1<<1)) != 0, MSRIRC)
+		fs.setIf((b&(1<<0)) != 0, CLZERO)
 	}
 
 	if maxExtendedFunction() >= 0x8000001b && fs.inSet(IBS) {
diff --git a/cpuid_test.go b/cpuid_test.go
index 2d31be9..5b810b6 100644
--- a/cpuid_test.go
+++ b/cpuid_test.go
@@ -35,13 +35,15 @@ func TestCPUID(t *testing.T) {
 	t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
 	t.Log("LogicalCores:", CPU.LogicalCores)
 	t.Log("Family", CPU.Family, "Model:", CPU.Model)
-	t.Log("Features:", fmt.Sprintf(strings.Join(CPU.FeatureSet(), ",")))
+	t.Log("Features:", strings.Join(CPU.FeatureSet(), ","))
 	t.Log("Cacheline bytes:", CPU.CacheLine)
 	t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
 	t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
 	t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
 	t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
 	t.Log("Hz:", CPU.Hz, "Hz")
+	t.Log("VM:", CPU.VM())
+	t.Log("BoostFreq:", CPU.BoostFreq, "Hz")
 }
 
 func TestExample(t *testing.T) {
@@ -52,7 +54,7 @@ func TestExample(t *testing.T) {
 	fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
 	fmt.Println("LogicalCores:", CPU.LogicalCores)
 	fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID)
-	fmt.Println("Features:", fmt.Sprintf(strings.Join(CPU.FeatureSet(), ",")))
+	fmt.Println("Features:", strings.Join(CPU.FeatureSet(), ","))
 	fmt.Println("Cacheline bytes:", CPU.CacheLine)
 	fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes")
 	fmt.Println("L1 Instruction Cache:", CPU.Cache.L1D, "bytes")
diff --git a/debian/changelog b/debian/changelog
index 29fdd22..39d1395 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-klauspost-cpuid (2.0.12-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 20 Mar 2022 13:12:25 -0000
+
 golang-github-klauspost-cpuid (2.0.6-2) unstable; urgency=medium
 
   [ Peymaneh Nejad ]
diff --git a/detect_arm64.go b/detect_arm64.go
index 9bf9f77..9a53504 100644
--- a/detect_arm64.go
+++ b/detect_arm64.go
@@ -1,6 +1,7 @@
 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 
-//+build arm64,!gccgo,!noasm,!appengine
+//go:build arm64 && !gccgo && !noasm && !appengine
+// +build arm64,!gccgo,!noasm,!appengine
 
 package cpuid
 
diff --git a/detect_ref.go b/detect_ref.go
index e9c8606..9636c2b 100644
--- a/detect_ref.go
+++ b/detect_ref.go
@@ -1,6 +1,7 @@
 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 
-//+build !amd64,!386,!arm64 gccgo noasm appengine
+//go:build (!amd64 && !386 && !arm64) || gccgo || noasm || appengine
+// +build !amd64,!386,!arm64 gccgo noasm appengine
 
 package cpuid
 
diff --git a/detect_x86.go b/detect_x86.go
index 93bc20f..35678d8 100644
--- a/detect_x86.go
+++ b/detect_x86.go
@@ -1,6 +1,7 @@
 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 
-//+build 386,!gccgo,!noasm,!appengine amd64,!gccgo,!noasm,!appengine
+//go:build (386 && !gccgo && !noasm && !appengine) || (amd64 && !gccgo && !noasm && !appengine)
+// +build 386,!gccgo,!noasm,!appengine amd64,!gccgo,!noasm,!appengine
 
 package cpuid
 
@@ -30,6 +31,6 @@ func addInfo(c *CPUInfo, safe bool) {
 	c.LogicalCores = logicalCores()
 	c.PhysicalCores = physicalCores()
 	c.VendorID, c.VendorString = vendorID()
-	c.Hz = hertz(c.BrandName)
 	c.cacheSize()
+	c.frequencies()
 }
diff --git a/featureid_string.go b/featureid_string.go
index 0e764f9..02fe232 100644
--- a/featureid_string.go
+++ b/featureid_string.go
@@ -24,103 +24,126 @@ func _() {
 	_ = x[AVX512DQ-14]
 	_ = x[AVX512ER-15]
 	_ = x[AVX512F-16]
-	_ = x[AVX512IFMA-17]
-	_ = x[AVX512PF-18]
-	_ = x[AVX512VBMI-19]
-	_ = x[AVX512VBMI2-20]
-	_ = x[AVX512VL-21]
-	_ = x[AVX512VNNI-22]
-	_ = x[AVX512VP2INTERSECT-23]
-	_ = x[AVX512VPOPCNTDQ-24]
-	_ = x[AVXSLOW-25]
-	_ = x[BMI1-26]
-	_ = x[BMI2-27]
-	_ = x[CLDEMOTE-28]
-	_ = x[CLMUL-29]
-	_ = x[CMOV-30]
-	_ = x[CX16-31]
-	_ = x[ENQCMD-32]
-	_ = x[ERMS-33]
-	_ = x[F16C-34]
-	_ = x[FMA3-35]
-	_ = x[FMA4-36]
-	_ = x[GFNI-37]
-	_ = x[HLE-38]
-	_ = x[HTT-39]
-	_ = x[HYPERVISOR-40]
-	_ = x[IBPB-41]
-	_ = x[IBS-42]
-	_ = x[IBSBRNTRGT-43]
-	_ = x[IBSFETCHSAM-44]
-	_ = x[IBSFFV-45]
-	_ = x[IBSOPCNT-46]
-	_ = x[IBSOPCNTEXT-47]
-	_ = x[IBSOPSAM-48]
-	_ = x[IBSRDWROPCNT-49]
-	_ = x[IBSRIPINVALIDCHK-50]
-	_ = x[LZCNT-51]
-	_ = x[MMX-52]
-	_ = x[MMXEXT-53]
-	_ = x[MOVDIR64B-54]
-	_ = x[MOVDIRI-55]
-	_ = x[MPX-56]
-	_ = x[NX-57]
-	_ = x[POPCNT-58]
-	_ = x[RDRAND-59]
-	_ = x[RDSEED-60]
-	_ = x[RDTSCP-61]
-	_ = x[RTM-62]
-	_ = x[SERIALIZE-63]
-	_ = x[SGX-64]
-	_ = x[SGXLC-65]
-	_ = x[SHA-66]
-	_ = x[SSE-67]
-	_ = x[SSE2-68]
-	_ = x[SSE3-69]
-	_ = x[SSE4-70]
-	_ = x[SSE42-71]
-	_ = x[SSE4A-72]
-	_ = x[SSSE3-73]
-	_ = x[STIBP-74]
-	_ = x[TBM-75]
-	_ = x[TSXLDTRK-76]
-	_ = x[VAES-77]
-	_ = x[VMX-78]
-	_ = x[VPCLMULQDQ-79]
-	_ = x[WAITPKG-80]
-	_ = x[WBNOINVD-81]
-	_ = x[XOP-82]
-	_ = x[AESARM-83]
-	_ = x[ARMCPUID-84]
-	_ = x[ASIMD-85]
-	_ = x[ASIMDDP-86]
-	_ = x[ASIMDHP-87]
-	_ = x[ASIMDRDM-88]
-	_ = x[ATOMICS-89]
-	_ = x[CRC32-90]
-	_ = x[DCPOP-91]
-	_ = x[EVTSTRM-92]
-	_ = x[FCMA-93]
-	_ = x[FP-94]
-	_ = x[FPHP-95]
-	_ = x[GPA-96]
-	_ = x[JSCVT-97]
-	_ = x[LRCPC-98]
-	_ = x[PMULL-99]
-	_ = x[SHA1-100]
-	_ = x[SHA2-101]
-	_ = x[SHA3-102]
-	_ = x[SHA512-103]
-	_ = x[SM3-104]
-	_ = x[SM4-105]
-	_ = x[SVE-106]
-	_ = x[lastID-107]
+	_ = x[AVX512FP16-17]
+	_ = x[AVX512IFMA-18]
+	_ = x[AVX512PF-19]
+	_ = x[AVX512VBMI-20]
+	_ = x[AVX512VBMI2-21]
+	_ = x[AVX512VL-22]
+	_ = x[AVX512VNNI-23]
+	_ = x[AVX512VP2INTERSECT-24]
+	_ = x[AVX512VPOPCNTDQ-25]
+	_ = x[AVXSLOW-26]
+	_ = x[BMI1-27]
+	_ = x[BMI2-28]
+	_ = x[CETIBT-29]
+	_ = x[CETSS-30]
+	_ = x[CLDEMOTE-31]
+	_ = x[CLMUL-32]
+	_ = x[CLZERO-33]
+	_ = x[CMOV-34]
+	_ = x[CMPXCHG8-35]
+	_ = x[CPBOOST-36]
+	_ = x[CX16-37]
+	_ = x[ENQCMD-38]
+	_ = x[ERMS-39]
+	_ = x[F16C-40]
+	_ = x[FMA3-41]
+	_ = x[FMA4-42]
+	_ = x[FXSR-43]
+	_ = x[FXSROPT-44]
+	_ = x[GFNI-45]
+	_ = x[HLE-46]
+	_ = x[HTT-47]
+	_ = x[HWA-48]
+	_ = x[HYPERVISOR-49]
+	_ = x[IBPB-50]
+	_ = x[IBS-51]
+	_ = x[IBSBRNTRGT-52]
+	_ = x[IBSFETCHSAM-53]
+	_ = x[IBSFFV-54]
+	_ = x[IBSOPCNT-55]
+	_ = x[IBSOPCNTEXT-56]
+	_ = x[IBSOPSAM-57]
+	_ = x[IBSRDWROPCNT-58]
+	_ = x[IBSRIPINVALIDCHK-59]
+	_ = x[INT_WBINVD-60]
+	_ = x[INVLPGB-61]
+	_ = x[LAHF-62]
+	_ = x[LZCNT-63]
+	_ = x[MCAOVERFLOW-64]
+	_ = x[MCOMMIT-65]
+	_ = x[MMX-66]
+	_ = x[MMXEXT-67]
+	_ = x[MOVBE-68]
+	_ = x[MOVDIR64B-69]
+	_ = x[MOVDIRI-70]
+	_ = x[MPX-71]
+	_ = x[MSRIRC-72]
+	_ = x[NX-73]
+	_ = x[OSXSAVE-74]
+	_ = x[POPCNT-75]
+	_ = x[RDPRU-76]
+	_ = x[RDRAND-77]
+	_ = x[RDSEED-78]
+	_ = x[RDTSCP-79]
+	_ = x[RTM-80]
+	_ = x[RTM_ALWAYS_ABORT-81]
+	_ = x[SCE-82]
+	_ = x[SERIALIZE-83]
+	_ = x[SGX-84]
+	_ = x[SGXLC-85]
+	_ = x[SHA-86]
+	_ = x[SSE-87]
+	_ = x[SSE2-88]
+	_ = x[SSE3-89]
+	_ = x[SSE4-90]
+	_ = x[SSE42-91]
+	_ = x[SSE4A-92]
+	_ = x[SSSE3-93]
+	_ = x[STIBP-94]
+	_ = x[SUCCOR-95]
+	_ = x[TBM-96]
+	_ = x[TSXLDTRK-97]
+	_ = x[VAES-98]
+	_ = x[VMX-99]
+	_ = x[VPCLMULQDQ-100]
+	_ = x[WAITPKG-101]
+	_ = x[WBNOINVD-102]
+	_ = x[X87-103]
+	_ = x[XOP-104]
+	_ = x[XSAVE-105]
+	_ = x[AESARM-106]
+	_ = x[ARMCPUID-107]
+	_ = x[ASIMD-108]
+	_ = x[ASIMDDP-109]
+	_ = x[ASIMDHP-110]
+	_ = x[ASIMDRDM-111]
+	_ = x[ATOMICS-112]
+	_ = x[CRC32-113]
+	_ = x[DCPOP-114]
+	_ = x[EVTSTRM-115]
+	_ = x[FCMA-116]
+	_ = x[FP-117]
+	_ = x[FPHP-118]
+	_ = x[GPA-119]
+	_ = x[JSCVT-120]
+	_ = x[LRCPC-121]
+	_ = x[PMULL-122]
+	_ = x[SHA1-123]
+	_ = x[SHA2-124]
+	_ = x[SHA3-125]
+	_ = x[SHA512-126]
+	_ = x[SM3-127]
+	_ = x[SM4-128]
+	_ = x[SVE-129]
+	_ = x[lastID-130]
 	_ = x[firstID-0]
 }
 
-const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXINT8AMXTILEAVXAVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXSLOWBMI1BMI2CLDEMOTECLMULCMOVCX16ENQCMDERMSF16CFMA3FMA4GFNIHLEHTTHYPERVISORIBPBIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKLZCNTMMXMMXEXTMOVDIR64BMOVDIRIMPXNXPOPCNTRDRANDRDSEEDRDTSCPRTMSERIALIZESGXSGXLCSHASSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPTBMTSXLDTRKVAESVMXVPCLMULQDQWAITPKGWBNOINVDXOPAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFPFPHPGPAJSCVTLRCPCPMULLSHA1SHA2SHA3SHA512SM3SM4SVElastID"
+const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXINT8AMXTILEAVXAVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512FP16AVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXSLOWBMI1BMI2CETIBTCETSSCLDEMOTECLMULCLZEROCMOVCMPXCHG8CPBOOSTCX16ENQCMDERMSF16CFMA3FMA4FXSRFXSROPTGFNIHLEHTTHWAHYPERVISORIBPBIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKINT_WBINVDINVLPGBLAHFLZCNTMCAOVERFLOWMCOMMITMMXMMXEXTMOVBEMOVDIR64BMOVDIRIMPXMSRIRCNXOSXSAVEPOPCNTRDPRURDRANDRDSEEDRDTSCPRTMRTM_ALWAYS_ABORTSCESERIALIZESGXSGXLCSHASSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPSUCCORTBMTSXLDTRKVAESVMXVPCLMULQDQWAITPKGWBNOINVDX87XOPXSAVEAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFPFPHPGPAJSCVTLRCPCPMULLSHA1SHA2SHA3SHA512SM3SM4SVElastID"
 
-var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 58, 62, 72, 84, 92, 100, 108, 116, 123, 133, 141, 151, 162, 170, 180, 198, 213, 220, 224, 228, 236, 241, 245, 249, 255, 259, 263, 267, 271, 275, 278, 281, 291, 295, 298, 308, 319, 325, 333, 344, 352, 364, 380, 385, 388, 394, 403, 410, 413, 415, 421, 427, 433, 439, 442, 451, 454, 459, 462, 465, 469, 473, 477, 482, 487, 492, 497, 500, 508, 512, 515, 525, 532, 540, 543, 549, 557, 562, 569, 576, 584, 591, 596, 601, 608, 612, 614, 618, 621, 626, 631, 636, 640, 644, 648, 654, 657, 660, 663, 669}
+var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 58, 62, 72, 84, 92, 100, 108, 116, 123, 133, 143, 151, 161, 172, 180, 190, 208, 223, 230, 234, 238, 244, 249, 257, 262, 268, 272, 280, 287, 291, 297, 301, 305, 309, 313, 317, 324, 328, 331, 334, 337, 347, 351, 354, 364, 375, 381, 389, 400, 408, 420, 436, 446, 453, 457, 462, 473, 480, 483, 489, 494, 503, 510, 513, 519, 521, 528, 534, 539, 545, 551, 557, 560, 576, 579, 588, 591, 596, 599, 602, 606, 610, 614, 619, 624, 629, 634, 640, 643, 651, 655, 658, 668, 675, 683, 686, 689, 694, 700, 708, 713, 720, 727, 735, 742, 747, 752, 759, 763, 765, 769, 772, 777, 782, 787, 791, 795, 799, 805, 808, 811, 814, 820}
 
 func (i FeatureID) String() string {
 	if i < 0 || i >= FeatureID(len(_FeatureID_index)-1) {
diff --git a/go.mod b/go.mod
index 2afac8e..3ad3f84 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
 module github.com/klauspost/cpuid/v2
 
-go 1.13
+go 1.15
diff --git a/mockcpu_test.go b/mockcpu_test.go
index 29f85d1..c44b7fc 100644
--- a/mockcpu_test.go
+++ b/mockcpu_test.go
@@ -45,9 +45,9 @@ func mockCPU(def []byte) func() {
 				break
 			}
 		}
-		if !strings.Contains(line, "-") {
-			//continue
-		}
+		//if !strings.Contains(line, "-") {
+		//	continue
+		//}
 		items := strings.Split(line, ":")
 		if len(items) < 2 {
 			if len(line) == 51 || len(line) == 50 {
@@ -186,13 +186,15 @@ func TestMocks(t *testing.T) {
 		t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
 		t.Log("LogicalCores:", CPU.LogicalCores)
 		t.Log("Family", CPU.Family, "Model:", CPU.Model)
-		t.Log("Features:", fmt.Sprintf(strings.Join(CPU.FeatureSet(), ",")))
+		t.Log("Features:", strings.Join(CPU.FeatureSet(), ","))
+		t.Log("Microarchitecture level:", CPU.X64Level())
 		t.Log("Cacheline bytes:", CPU.CacheLine)
 		t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
 		t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
 		t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
 		t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
 		t.Log("Hz:", CPU.Hz, "Hz")
+		t.Log("Boost:", CPU.BoostFreq, "Hz")
 		if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 {
 			if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore {
 				t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)",
diff --git a/os_other_arm64.go b/os_other_arm64.go
index 1a951e6..8733ba3 100644
--- a/os_other_arm64.go
+++ b/os_other_arm64.go
@@ -1,8 +1,7 @@
 // Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
 
-// +build arm64
-// +build !linux
-// +build !darwin
+//go:build arm64 && !linux && !darwin
+// +build arm64,!linux,!darwin
 
 package cpuid
 
diff --git a/os_safe_linux_arm64.go b/os_safe_linux_arm64.go
index 4d0b8b4..f8f201b 100644
--- a/os_safe_linux_arm64.go
+++ b/os_safe_linux_arm64.go
@@ -1,6 +1,7 @@
 // Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file.
 
-//+build nounsafe
+//go:build nounsafe
+// +build nounsafe
 
 package cpuid
 
diff --git a/os_unsafe_linux_arm64.go b/os_unsafe_linux_arm64.go
index 3298002..92af622 100644
--- a/os_unsafe_linux_arm64.go
+++ b/os_unsafe_linux_arm64.go
@@ -1,6 +1,7 @@
 // Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file.
 
-//+build !nounsafe
+//go:build !nounsafe
+// +build !nounsafe
 
 package cpuid
 
diff --git a/testdata/getall.go b/testdata/getall.go
index f4d78a6..116456b 100644
--- a/testdata/getall.go
+++ b/testdata/getall.go
@@ -1,14 +1,17 @@
+//go:build ignore
+
 package main
 
 import (
 	"archive/zip"
 	_ "bytes"
 	"fmt"
-	"golang.org/x/net/html"
 	"io"
 	"net/http"
 	"os"
 	"strings"
+
+	"golang.org/x/net/html"
 )
 
 // Download all CPUID dumps from http://users.atw.hu/instlatx64/