Files
tinygo/src/machine/usb/util.go
T

318 lines
9.0 KiB
Go

package usb
//go:linkname ticks runtime.ticks
func ticks() int64
// leU64 returns a slice containing 8 bytes from the given uint64 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 7 is the most-
// significant byte.
//go:inline
func leU64(u uint64) []uint8 {
var b [8]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[0] = uint8(u)
b[1] = uint8(u >> 8)
b[2] = uint8(u >> 16)
b[3] = uint8(u >> 24)
b[4] = uint8(u >> 32)
b[5] = uint8(u >> 40)
b[6] = uint8(u >> 48)
b[7] = uint8(u >> 56)
return b[:]
}
// leU32 returns a slice containing 4 bytes from the given uint32 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 3 is the most-
// significant byte.
//go:inline
func leU32(u uint32) []uint8 {
var b [4]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[0] = uint8(u)
b[1] = uint8(u >> 8)
b[2] = uint8(u >> 16)
b[3] = uint8(u >> 24)
return b[:]
}
// leU16 returns a slice containing 2 bytes from the given uint16 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 1 is the most-
// significant byte.
//go:inline
func leU16(u uint16) []uint8 {
var b [2]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[0] = uint8(u)
b[1] = uint8(u >> 8)
return b[:]
}
// beU64 returns a slice containing 8 bytes from the given uint64 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 7 is the least-
// significant byte.
//go:inline
func beU64(u uint64) []uint8 {
var b [8]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[7] = uint8(u)
b[6] = uint8(u >> 8)
b[5] = uint8(u >> 16)
b[4] = uint8(u >> 24)
b[3] = uint8(u >> 32)
b[2] = uint8(u >> 40)
b[1] = uint8(u >> 48)
b[0] = uint8(u >> 56)
return b[:]
}
// beU32 returns a slice containing 4 bytes from the given uint32 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 3 is the least-
// significant byte.
//go:inline
func beU32(u uint32) []uint8 {
var b [4]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[3] = uint8(u)
b[2] = uint8(u >> 8)
b[1] = uint8(u >> 16)
b[0] = uint8(u >> 24)
return b[:]
}
// beU16 returns a slice containing 2 bytes from the given uint16 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 1 is the least-
// significant byte.
//go:inline
func beU16(u uint16) []uint8 {
var b [2]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[1] = uint8(u)
b[0] = uint8(u >> 8)
return b[:]
}
// revU64 returns the given uint64 u with bytes in the reverse order.
//go:inline
func revU64(u uint64) uint64 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x00000000000000FF) << 56) |
((u & 0x000000000000FF00) << 40) |
((u & 0x0000000000FF0000) << 24) |
((u & 0x00000000FF000000) << 8) |
((u & 0x000000FF00000000) >> 8) |
((u & 0x0000FF0000000000) >> 24) |
((u & 0x00FF000000000000) >> 40) |
((u & 0xFF00000000000000) >> 56)
}
// revU32 returns the given uint32 u with bytes in the reverse order.
//go:inline
func revU32(u uint32) uint32 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x000000FF) << 24) | ((u & 0x0000FF00) << 8) |
((u & 0x00FF0000) >> 8) | ((u & 0xFF000000) >> 24)
}
// revU16 returns the given uint16 u with bytes in the reverse order.
//go:inline
func revU16(u uint16) uint16 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x00FF) << 8) | ((u & 0xFF00) >> 8)
}
// packU64 returns a uint64 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 7, if given. If fewer
// than 8 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU64(b []uint8) (u uint64) {
for i := 0; i < 8 && i < len(b); i++ {
u |= uint64(b[i]) << (i * 8)
}
return
}
// packU32 returns a uint32 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 3, if given. If fewer
// than 4 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU32(b []uint8) (u uint32) {
for i := 0; i < 4 && i < len(b); i++ {
u |= uint32(b[i]) << (i * 8)
}
return
}
// packU16 returns a uint16 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 1, if given. If fewer
// than 2 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU16(b []uint8) (u uint16) {
for i := 0; i < 2 && i < len(b); i++ {
u |= uint16(b[i]) << (i * 8)
}
return
}
// msU8 returns the most-significant byte of u.
//go:inline
func msU8(u uint16) uint8 { return uint8(u >> 8) }
// lsU8 returns the least-significant byte of u.
//go:inline
func lsU8(u uint16) uint8 { return uint8(u) }
// cycles converts the given number of microseconds to CPU cycles for a CPU with
// given frequency.
//go:inline
func cycles(microsec, cpuFreqHz uint32) uint32 {
return uint32((uint64(microsec) * uint64(cpuFreqHz)) / 1000000)
}
//go:inline
func unpackEndpoint(address uint8) (number, direction uint8) {
return (address & descEndptAddrNumberMsk) >> descEndptAddrNumberPos,
(address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos
}
//go:inline
func rxEndpoint(number uint8) uint8 {
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionOut
}
//go:inline
func txEndpoint(number uint8) uint8 {
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionIn
}
//go:inline
func endpointIndex(address uint8) uint8 {
return ((address & descEndptAddrNumberMsk) << 1) |
((address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos)
}
//go:inline
func indexEndpoint(index uint8) uint8 {
return ((index >> 1) & descEndptAddrNumberMsk) |
((index & 0x1) << descEndptAddrDirectionPos)
}
// wrap computes the index into a circular buffer of length mod by walking
// forward n elements if n is positive, or reverse n elements if n is negative.
// For example, both wrap(42, 10) and wrap(-308, 10) return 2.
//go:inline
func wrap(n, mod int) int {
if mod <= 0 || n == mod {
return 0
}
if n < 0 {
if -n < mod {
return mod + n
}
return mod - (-n % mod)
}
if n < mod {
return n
}
return n % mod
}
// The following buffLo and buffHi are helper methods for slice definitions from
// potentially zero-length arrays (depending on compile-time constants).
//
// For example, if we have an array containing a 5-element buffer for three
// instances of some device class (15 total elements), partitioned as follows,
// then we compute the indices for instance 2 as usual:
//
// Index: 01234 56789 ABCDE
// Array: [ 1 | 2 | 3 ]
//
// Lo: (n-1) * size => (2-1) * 5 => 5
// Hi: (n) * size => (2) * 5 => 10 (0xA)
//
// However, if we have specified (via const definition) that 0 instances of some
// device class be allocated, then the associated device class buffer arrays
// will all be zero-length arrays, and the arithmetic to compute the slice
// indices used above will result in out-of-bounds indices:
//
// Index:
// Array: []
//
// Lo: (n-1) * size => (2-1) * 5 => 5 [Error!]
// Hi: (n) * size => (2) * 5 => 10 (0xA) [Error!]
//
//
// I couldn't figure out a straight-forward way to resolve these slice indices
// using only arithmetic, so I've resorted to simple conditionals. If the number
// of instances for some given class is zero (count=0), defined via compile-time
// constant, then just use the empty slice range [0:0].
// buffLo returns the starting array slice index for the n'th region of size
// elements from an array containing count regions of size elements.
// Regions are specified using a 1-based index (n > 0). Returns 0 if any given
// argument equals 0.
func buffLo(n, count, size uint16) uint16 {
if 0 == n || 0 == count || 0 == size {
return 0
}
return (n - 1) * size
}
// buffHi returns the ending array slice index for the n'th region of size
// elements from an array containing count regions of size elements.
// Regions are specified using a 1-based index (n > 0). Returns 0 if any given
// argument equals 0.
func buffHi(n, count, size uint16) uint16 {
if 0 == n || 0 == count || 0 == size {
return 0
}
return n * size
}