Livt packages
Livt.ML
Version 1.6.1
Fixed-size quantized inference, tensor storage, attention, and transformer building blocks for Livt.
Published files (132)
- DotProduct.lvt
- FixedPointAccumulator.lvt
- Int8BroadcastMac64x8.lvt
- Int8BroadcastMac64x8Primitive.lvt
- Int8BroadcastMac64x8Primitive.vhd
- Int8Dot64x8.lvt
- Int8Dot64x8Primitive.lvt
- Int8Dot64x8Primitive.vhd
- Int8Linear4x8.lvt
- Int8Linear8x3.lvt
- Int8LinearAccumulator.lvt
- Int8Mac8.lvt
- Int8MatrixAccumulator32.lvt
- Int8MatrixAccumulator32Primitive.lvt
- Int8MatrixAccumulator32Primitive.vhd
- Int8MatrixAccumulator32Stream.lvt
- Linear8x8.lvt
- MatrixVectorMultiplication.lvt
- QLinearMatMul256x10.lvt
- QLinearMatMul256x10Ram.lvt
- QLinearMatMul256x10Stream.lvt
- QuantizedMatrix.lvt
- VecAdd.lvt
src/linear/QLinearMatMul256x10Stream.lvt
namespace Livt.ML.Linear
using Livt.ML.Numeric
/**
* Streams a loaded ONNX per-column QLinearMatMul from 256 uint8 inputs to ten outputs.
*
* Weights are loaded output-column-major as 2,560 signed two's-complement
* `logic[8]` values. Ten scale and zero-point records follow the same
* output-column order. Each record repeats the scalar activation zero point;
* weight and output zero points may vary by column.
* Both loaders and the activation/output paths use toggle handshakes. The
* compact weight representation and process implementation avoid tensor-sized
* public-function shadow signals.
*
* The datapath consumes one activation and updates ten accumulators in
* parallel. `frameError` is set when `inputLast` does not identify activation
* 255 and is cleared at the start of the next frame.
*/
component QLinearMatMul256x10Stream
{
// Owned scheduled requantizer; processing holds input acceptance until completion.
requantize: ScheduledRequantizeUInt8
// Weight-loading payload and toggle acknowledgment.
weightRequest: logic
weightData: logic[8]
weightAcknowledge: logic
// Parameter-loading payload and toggle acknowledgment.
scaleRequest: logic
scaleMultiplier: int
scaleDivisor: int
scaleInputZeroPoint: int
scaleWeightZeroPoint: int
scaleOutputZeroPoint: int
scaleAcknowledge: logic
// Input payload and toggle acknowledgment from the producer.
inputRequest: logic
inputData: byte
inputLast: logic
inputAcknowledge: logic
// Output payload and toggle acknowledgment; payload stays stable while pending.
outputRequest: logic
outputData: byte
outputAccumulator: int
outputLast: logic
outputAcknowledge: logic
// Configuration readiness and frame-boundary error status.
configured: logic
frameError: logic
// Transfer progress and retained request/acknowledgment state.
weightSeen: logic
scaleSeen: logic
inputSeen: logic
pending: bool
emitting: bool
weightsLoaded: bool
scalesLoaded: bool
// Current position and bounds within the configured frame.
weightColumn: int
weightRow: int
scaleColumn: int
inputIndex: int
outputColumn: int
// Configured coefficients and numeric scaling parameters.
weights: logic[10, 256, 8]
multipliers: int[10]
divisors: int[10]
inputZeroPoint: int
weightZeroPoints: int[10]
outputZeroPoints: int[10]
// Wide output accumulators before final output conversion.
accumulators: int[10]
/**
* Binds configuration, input, and output toggle-handshake ports. Callers hold each payload
* until its acknowledgment matches the request; configure the worker before sending
* frames.
*/
new(weightRequest: in logic, weightData: in logic[8], weightAcknowledge: out logic,
scaleRequest: in logic, scaleMultiplier: in int, scaleDivisor: in int,
scaleInputZeroPoint: in int, scaleWeightZeroPoint: in int,
scaleOutputZeroPoint: in int, scaleAcknowledge: out logic,
inputRequest: in logic, inputData: in byte, inputLast: in logic,
inputAcknowledge: out logic, outputRequest: out logic, outputData: out byte,
outputAccumulator: out int, outputLast: out logic, outputAcknowledge: in logic,
configured: out logic, frameError: out logic)
{
requantize = new ScheduledRequantizeUInt8()
this.weightRequest = weightRequest
this.weightData = weightData
weightAcknowledge = this.weightAcknowledge
this.scaleRequest = scaleRequest
this.scaleMultiplier = scaleMultiplier
this.scaleDivisor = scaleDivisor
this.scaleInputZeroPoint = scaleInputZeroPoint
this.scaleWeightZeroPoint = scaleWeightZeroPoint
this.scaleOutputZeroPoint = scaleOutputZeroPoint
scaleAcknowledge = this.scaleAcknowledge
this.inputRequest = inputRequest
this.inputData = inputData
this.inputLast = inputLast
inputAcknowledge = this.inputAcknowledge
outputRequest = this.outputRequest
outputData = this.outputData
outputAccumulator = this.outputAccumulator
outputLast = this.outputLast
this.outputAcknowledge = outputAcknowledge
configured = this.configured
frameError = this.frameError
}
/**
* Accepts configuration and frame values through the toggle handshakes, evaluates the
* configured operator, and holds each output until acknowledged. All connected endpoints
* must share compatible clock/reset sequencing.
*/
process Main()
{
weightAcknowledge = weightSeen
scaleAcknowledge = scaleSeen
inputAcknowledge = inputSeen
configured = 0b0
if (weightsLoaded && scalesLoaded) {
configured = 0b1
}
if (!emitting && !pending && weightRequest != weightSeen) {
weights[weightColumn, weightRow] = weightData
weightSeen = weightRequest
if (weightRow == 255) {
weightRow = 0
if (weightColumn == 9) {
weightColumn = 0
weightsLoaded = true
} else {
weightColumn++
}
} else {
weightRow++
}
}
if (!emitting && !pending && scaleRequest != scaleSeen) {
multipliers[scaleColumn] = scaleMultiplier
divisors[scaleColumn] = scaleDivisor
inputZeroPoint = scaleInputZeroPoint
weightZeroPoints[scaleColumn] = scaleWeightZeroPoint
outputZeroPoints[scaleColumn] = scaleOutputZeroPoint
scaleSeen = scaleRequest
if (scaleColumn == 9) {
scaleColumn = 0
scalesLoaded = true
} else {
scaleColumn++
}
}
if (pending) {
if (outputAcknowledge == outputRequest) {
pending = false
}
} else {
if (emitting) {
outputAccumulator = accumulators[outputColumn]
outputData = requantize.ApplyRational(
accumulators[outputColumn], multipliers[outputColumn],
divisors[outputColumn], outputZeroPoints[outputColumn]) as byte
outputLast = 0b0
if (outputColumn == 9) {
outputLast = 0b1
}
outputRequest = !outputRequest
pending = true
if (outputColumn == 9) {
outputColumn = 0
emitting = false
} else {
outputColumn++
}
} else {
if (weightsLoaded && scalesLoaded && inputRequest != inputSeen) {
if (inputIndex == 0) {
frameError = 0b0
}
if (inputLast == 0b1 && inputIndex != 255) {
frameError = 0b1
}
if (inputIndex == 255 && inputLast != 0b1) {
frameError = 0b1
}
for (var column = 0; column < 10; column++) {
var centeredInput = (inputData as int) - inputZeroPoint
var centeredWeight = (weights[column, inputIndex] as int) - weightZeroPoints[column]
var product = centeredInput * centeredWeight
if (inputIndex == 0) {
accumulators[column] = product
} else {
accumulators[column] = accumulators[column] + product
}
}
inputSeen = inputRequest
if (inputIndex == 255) {
inputIndex = 0
emitting = true
} else {
inputIndex++
}
}
}
}
}
}