-
Notifications
You must be signed in to change notification settings - Fork 0
/
bits.go
150 lines (130 loc) · 3.7 KB
/
bits.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//go:generate stringer -type=Field
// Package bits does the low (bit-)level revision code
// parsing and assembly.
package bits
import (
"errors"
"fmt"
"math/bits"
)
// Parse a Raspberry Pi revision Code into a slice of Values.
func Parse(r Code) Values {
s := make(Values, NumTotal)
// HACK Seems crazy, but that's how integer overflow works.
for f := Last; f <= Last; f-- {
s[f] = Value(r & Code(f.Bitmask()))
r >>= f.Bitsize()
}
return s
}
// Code is a Raspberry Pi revision code.
type Code uint32
// Values is an alias for a Value slice.
type Values = []Value
// The Value of a Field in a revision Code.
type Value uint8
const (
// _ Field = iota - 1 // To improve readability of the following
NoOvervoltage Field = iota // Overvoltage disallowed
NoOTPPrograming // OTP programming disallowed
NoOTPReading // OTP reading disallowed
Unused1 //
WarrantyVoid // Warranty has been voided by overclocking
Unused2 //
NewStyleRev // New-style revision code
Memory // Memory size in multiples of 256
Manufacturer
Processor
Model
Revision
// NumTotal of known Fields.
NumTotal // Taking advantage of iota continuing its effect here.
// Last known field.
Last = NumTotal - 1 // This automatically tracks the last field.
// First of known Fields, short for "Field(0)" to iterate from.
First Field = 0
)
// A Field of revision code.
//
// Keep in mind that this cannot have negative values, and f := Field(0)
// overflows to f - 1 == Field(MaxUint). This means that you have to
// compare f <= Last if/when iterating down from Last.
type Field uint
// Bitmask is an all-ones mask derived from the bitsize of the Field.
func (f Field) Bitmask() uint8 { return bitmasks[f] }
// Bitsize is the length of Field value in number of bits.
func (f Field) Bitsize() uint8 { return bitsizes[f] }
// Validate returns error if v is not a valid Value for the Field.
func (f Field) Validate(v Value) (err error) {
if v&^Value(f.Bitmask()) != 0 {
err = fmt.Errorf(
"field %s takes %d bit value, %#x is %d bits",
f, f.Bitsize(), v, bits.Len8(uint8(v)),
)
}
return
}
// Naming ideas: assemble/compile/construct/synthesize
// Assemble a slice of Values into a revision Code.
func Assemble(s Values) (r Code, err error) {
n := Field(len(s))
if n > NumTotal {
err = ErrOverflow
return
}
for f := First; f < n; f++ {
v := s[f]
if err = f.Validate(v); err != nil {
return
}
r = r<<f.Bitsize() | Code(v)
}
for f := n; f <= Last; f++ {
r <<= f.Bitsize()
}
return
}
// ErrOverflow is returned when a function gets passed more Values than
// TotalNumFields.
var ErrOverflow = errors.New("more Values than NumTotal")
// bitmasks of Fields.
var bitmasks = func(s [NumTotal]uint8) (m [NumTotal]uint8) {
// TODO Verify that the array argument is not copied here.
for i, l := range s {
m[i] = 1<<l - 1
}
return
}(bitsizes)
// bitsizes of fields.
var bitsizes = [NumTotal]uint8{
NoOvervoltage: 1,
NoOTPPrograming: 1,
NoOTPReading: 1,
Unused1: 3,
WarrantyVoid: 1,
Unused2: 1,
NewStyleRev: 1,
Memory: 3,
Manufacturer: 4,
Processor: 4,
Model: 8,
Revision: 4,
}
// CodeBitsize of a Raspberry Pi revision code as a number of bits.
const CodeBitsize = 32
// "index out of range" means bitsizes not adding up to CodeBitsize.
var _ = [1]struct{}{}[0+
CodeBitsize-
bitsizes[NoOvervoltage]-
bitsizes[NoOTPPrograming]-
bitsizes[NoOTPReading]-
bitsizes[Unused1]-
bitsizes[WarrantyVoid]-
bitsizes[Unused2]-
bitsizes[NewStyleRev]-
bitsizes[Memory]-
bitsizes[Manufacturer]-
bitsizes[Processor]-
bitsizes[Model]-
bitsizes[Revision]-
0]