Livt packages

Livt.Signal

Version 0.1.1

Q1.15 sample streams, filters, windows, rate conversion, FFTs, oscillators, and mixers for Livt.

Published files (80)

tests/stream/Q15SampleFlowControlTest.lvt

namespace Livt.Signal.Stream

/**
 * Produces four consecutive framed tokens without inserting an idle cycle.
 */
component Q15ContinuousTestSource
{
	stream: IQ15SampleStream
	public accepted: int

	/**
	 * Binds the continuous test producer to a producer-side stream endpoint.
	 */
	new(stream: flip IQ15SampleStream)
	{
		this.stream = stream
	}

	/**
	 * Replaces each accepted token immediately with its successor.
	 */
	process Send()
	{
		state Prime {
			stream.sample = 0x8000
			stream.valid = true
			stream.first = true
			stream.last = false
			goto First
		}

		state First {
			if (stream.ready) {
				accepted++
				stream.sample = 0xFFFF
				stream.first = false
				goto Second
			}
		}

		state Second {
			if (stream.ready) {
				accepted++
				stream.sample = 0x0000
				goto Third
			}
		}

		state Third {
			if (stream.ready) {
				accepted++
				stream.sample = 0x7FFF
				stream.last = true
				goto Last
			}
		}

		state Last {
			if (stream.ready) {
				accepted++
				stream.valid = false
				stream.last = false
				goto Idle
			}
		}

		state Idle {
			stream.valid = false
			goto Idle
		}
	}
}

/**
 * Alternates capacity and checks every transferred token and stalled value.
 */
component Q15AlternatingTestSink
{
	stream: IQ15SampleStream
	public accepted: int
	public failed: bool
	public sawStall: bool
	allow: bool
	wasStalled: bool
	heldSample: logic[16]
	heldFirst: bool
	heldLast: bool

	/**
	 * Binds the alternating test consumer to a consumer-side stream endpoint.
	 */
	new(stream: IQ15SampleStream)
	{
		this.stream = stream
	}

	/**
	 * Alternates downstream capacity after reset.
	 */
	process Toggle()
	{
		state {
			allow = !allow
		}
	}

	/**
	 * Drives ready from the current alternating-capacity phase.
	 */
	process Drive[]()
	{
		stream.ready = this.context.rst == 0b0 && allow
	}

	/**
	 * Returns the expected payload for one of the four accepted positions.
	 */
	fn SampleAt[](index: int) logic[16]
	{
		if (index == 0) {
			return 0x8000
		}

		if (index == 1) {
			return 0xFFFF
		}

		if (index == 2) {
			return 0x0000
		}

		return 0x7FFF
	}

	/**
	 * Verifies ordering, frame markers, and complete-token stability while stalled.
	 */
	process Check()
	{
		state {
			if (stream.valid && !stream.ready) {
				sawStall = true

				if (wasStalled
					&& (stream.sample != heldSample || stream.first != heldFirst || stream.last != heldLast)) {
					failed = true
				}

				heldSample = stream.sample
				heldFirst = stream.first
				heldLast = stream.last
				wasStalled = true
			} else {
				wasStalled = false
			}

			if (stream.valid && stream.ready) {
				if (accepted >= 4 || stream.sample != SampleAt(accepted)
					|| stream.first != (accepted == 0) || stream.last != (accepted == 3)) {
					failed = true
				}

				accepted++
			}
		}
	}
}

/**
 * Connects a continuous source to an alternating sink through a two-stage delay.
 */
component Q15SampleFlowControlFixture
{
	inputStream: IQ15SampleStream
	outputStream: IQ15SampleStream
	source: Q15ContinuousTestSource
	delay: Q15SampleDelay<2>
	sink: Q15AlternatingTestSink
	public sourceAccepted: out int
	public sinkAccepted: out int
	public failed: out bool
	public sawStall: out bool

	/**
	 * Creates and connects the continuous flow-control test path.
	 */
	new()
	{
		source = new Q15ContinuousTestSource(inputStream)
		delay = new Q15SampleDelay<2>(inputStream, outputStream)
		sink = new Q15AlternatingTestSink(outputStream)
	}

	/**
	 * Publishes the source and sink protocol observations.
	 */
	process Observe[]()
	{
		sourceAccepted = source.accepted
		sinkAccepted = sink.accepted
		failed = sink.failed
		sawStall = sink.sawStall
	}
}

/**
 * Verifies continuous producer traffic under alternating downstream backpressure.
 */
@Test
component Q15SampleFlowControlTest
{
	fixture: Q15SampleFlowControlFixture

	/**
	 * Creates a fresh continuous flow-control fixture.
	 */
	new()
	{
		fixture = new Q15SampleFlowControlFixture()
	}

	/**
	 * Preserves all consecutive tokens through repeated alternating stalls.
	 */
	@Test
	fn PreservesContinuousTrafficUnderAlternatingStalls()
	{
		Simulation.Wait(100)
		assert fixture.sourceAccepted == 4
		assert fixture.sinkAccepted == 4
		assert fixture.sawStall
		assert !fixture.failed
	}
}