/
bits.go
150 lines (131 loc) · 3.73 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
// Package bits does the low (bit-)level parsing and assembly of
// new-style Raspberry Pi revision codes.
package bits
//go:generate go run golang.org/x/tools/cmd/stringer -type=Field
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) & 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
// Field constants.
const (
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, as an unsigned integer, Field cannot have negative
// values, and `f := Field(0) - 1` overflows to `f == 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() Value { 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&^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
// NumTotal.
var ErrOverflow = errors.New("more Values than NumTotal")
// bitmasks of Fields.
var bitmasks = func(s [NumTotal]uint8) (m [NumTotal]Value) {
// 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 is the number of bits in a Raspberry Pi revision code.
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]