Livt packages

Livt.ML

Version 1.6.1

Fixed-size quantized inference, tensor storage, attention, and transformer building blocks for Livt.

Published files (132)

tests/linear/QLinearMatMul256x10StreamTest.lvt

namespace Livt.ML.Tests.Linear

using Livt.ML.Linear

/**
 * Verifies loading, signed weights, accumulation, scaling, and output framing.
 */
@Test
component QLinearMatMul256x10StreamTest
{
	// Shared fixture instances, signals, and observation state.
	weightRequest: logic
	weightData: logic[8]
	weightAcknowledge: logic
	scaleRequest: logic
	scaleMultiplier: int
	scaleDivisor: int
	scaleInputZeroPoint: int
	scaleWeightZeroPoint: int
	scaleOutputZeroPoint: int
	scaleAcknowledge: logic
	inputRequest: logic
	inputData: byte
	inputLast: logic
	inputAcknowledge: logic
	outputRequest: logic
	outputData: byte
	outputAccumulator: int
	outputLast: logic
	outputAcknowledge: logic
	configured: logic
	frameError: logic
	dut: QLinearMatMul256x10Stream

	/**
	 * Creates the shared fixture instances (QLinearMatMul256x10Stream). Tests initialize the
	 * state required by their scenario.
	 */
	new()
	{
		this.dut = new QLinearMatMul256x10Stream(
			this.weightRequest, this.weightData, this.weightAcknowledge,
			this.scaleRequest, this.scaleMultiplier, this.scaleDivisor,
			this.scaleInputZeroPoint, this.scaleWeightZeroPoint,
			this.scaleOutputZeroPoint, this.scaleAcknowledge,
			this.inputRequest, this.inputData, this.inputLast, this.inputAcknowledge,
			this.outputRequest, this.outputData, this.outputAccumulator,
			this.outputLast, this.outputAcknowledge, this.configured, this.frameError)
	}

	/**
	 * Submits one packed weight and waits for the matching toggle acknowledgment before
	 * returning.
	 */
	fn SendWeight(value: int)
	{
		weightData = value as logic[8]
		weightRequest = !weightRequest

		while (weightAcknowledge != weightRequest) {
			state {
			}
		}
	}

	/**
	 * Submits one quantization parameter tuple and waits for the matching toggle
	 * acknowledgment before returning.
	 */
	fn SendScale(
		multiplier: int, divisor: int,
		inputZeroPoint: int, weightZeroPoint: int, outputZeroPoint: int)
	{
		scaleMultiplier = multiplier
		scaleDivisor = divisor
		scaleInputZeroPoint = inputZeroPoint
		scaleWeightZeroPoint = weightZeroPoint
		scaleOutputZeroPoint = outputZeroPoint
		scaleRequest = !scaleRequest

		while (scaleAcknowledge != scaleRequest) {
			state {
			}
		}
	}

	/**
	 * Submits one frame element and waits for the matching toggle acknowledgment before
	 * returning.
	 */
	fn SendInput(value: byte, last: logic)
	{
		inputData = value
		inputLast = last
		inputRequest = !inputRequest

		while (inputAcknowledge != inputRequest) {
			state {
			}
		}
	}

	/**
	 * Checks that Compute s loaded projection.
	 */
	@Test
	fn ComputesLoadedProjection()
	{
		for (var column = 0; column < 10; column++) {
			for (var row = 0; row < 256; row++) {
				var weight = 0

				if (column == 0 && row == 0) {
					weight = 2
				}

				if (column == 1 && row == 0) {
					weight = -2
				}

				this.SendWeight(weight)
			}
		}

		for (var column = 0; column < 10; column++) {
			if (column == 1) {
				this.SendScale(1, 1, 1, -1, 112)
			} else {
				this.SendScale(1, 1, 1, 0, 112)
			}
		}

		while (configured != 0b1) {
			state {
			}
		}

		for (var row = 0; row < 256; row++) {
			var value = 0x01

			if (row == 0) {
				value = 0x03
			}

			var last = 0b0

			if (row == 255) {
				last = 0b1
			}

			this.SendInput(value, last)
		}

		for (var column = 0; column < 10; column++) {
			while (outputRequest == outputAcknowledge) {
				state {
				}
			}

			if (column == 0) {
				assert outputAccumulator == 4
				assert outputData == 0x74
			} else {
				if (column == 1) {
					assert outputAccumulator == -2
					assert outputData == 0x6e
				} else {
					assert outputAccumulator == 0
					assert outputData == 0x70
				}
			}

			if (column == 9) {
				assert outputLast == 0b1
			} else {
				assert outputLast == 0b0
			}

			outputAcknowledge = outputRequest
		}

		assert frameError == 0b0
	}
}