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)

src/stream/Q15SampleDelay.lvt

namespace Livt.Signal.Stream

/**
 * Delays Q1.15 samples and their frame markers through a stallable registered pipeline.
 * With ready continuously high, latency is STAGES clocks and the initiation interval is
 * one clock. Downstream backpressure freezes every stage and propagates to the input.
 */
component Q15SampleDelay<STAGES: int = 1>
{
	static assert STAGES > 0, "Q15 sample delay must contain at least one stage"

	// Total packed payload width across every registered stage.
	const SAMPLE_BITS: int = 16 * STAGES
	const OUTPUT_OFFSET: int = 16 * (STAGES - 1)

	// Borrowed input and output stream endpoints.
	inputStream: IQ15SampleStream
	outputStream: IQ15SampleStream

	// Packed sample pipeline and matching token metadata.
	samples: logic[SAMPLE_BITS]
	validStages: logic[STAGES]
	firstStages: logic[STAGES]
	lastStages: logic[STAGES]

	// Shared pipeline advance condition.
	advance: bool

	/**
	 * Binds a consumer-side input and producer-side output in one clock/reset context.
	 */
	new(inputStream: IQ15SampleStream, outputStream: flip IQ15SampleStream)
	{
		this.inputStream = inputStream
		this.outputStream = outputStream
	}

	/**
	 * Drives the stream handshake and the oldest retained token.
	 */
	process Drive[]()
	{
		advance = validStages[STAGES - 1] == 0b0 || outputStream.ready
		inputStream.ready = this.context.rst == 0b0 && advance
		outputStream.valid = this.context.rst == 0b0 && validStages[STAGES - 1] == 0b1
		outputStream.sample = samples[OUTPUT_OFFSET: OUTPUT_OFFSET + 16]
		outputStream.first = firstStages[STAGES - 1] == 0b1
		outputStream.last = lastStages[STAGES - 1] == 0b1
	}

	/**
	 * Advances every token and sideband together, or holds the complete pipeline stable.
	 */
	process Advance()
	{
		state {
			if (advance) {
				var nextSamples = samples << 16
				var nextValid = validStages << 1
				var nextFirst = firstStages << 1
				var nextLast = lastStages << 1
				nextSamples[0: 16] = inputStream.sample
				nextValid[0] = 0b0
				nextFirst[0] = 0b0
				nextLast[0] = 0b0

				if (inputStream.valid) {
					nextValid[0] = 0b1
				}

				if (inputStream.first) {
					nextFirst[0] = 0b1
				}

				if (inputStream.last) {
					nextLast[0] = 0b1
				}

				samples = nextSamples
				validStages = nextValid
				firstStages = nextFirst
				lastStages = nextLast
			}
		}
	}
}