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/transform/SequentialFftQ15.lvt

namespace Livt.Signal.Transform

/**
 * Computes one in-place radix-2 FFT or IFFT using a shared Q1.15 butterfly.
 * The component accepts exactly one complete frame, computes it, and emits the
 * retained result before accepting another frame. Stage scaling is selected by
 * the low STAGES bits of STAGE_SHIFT_MASK; -1 shifts every stage. Reset cancels
 * a partial input frame, active transform, or unread output.
 */
component SequentialFftQ15<SAMPLES: int,
	DIRECTION: FftDirection = FftDirection.Forward,
	STAGE_SHIFT_MASK: int = -1,
	INPUT_ORDER: FftOrder = FftOrder.Natural,
	OUTPUT_ORDER: FftOrder = FftOrder.Natural>
{
	static assert SAMPLES == 8 || SAMPLES == 16 || SAMPLES == 32
		|| SAMPLES == 64 || SAMPLES == 128 || SAMPLES == 256
		|| SAMPLES == 512 || SAMPLES == 1024 || SAMPLES == 2048
		|| SAMPLES == 4096,
		"sequential FFT length must be a supported power of two in 8..4096"
	static assert STAGE_SHIFT_MASK >= -1 && STAGE_SHIFT_MASK <= 4095,
		"FFT stage shift mask must be -1 or a nonnegative 12-bit mask"

	// Published sizing, throughput, storage, resource, and configuration contract.
	public const SAMPLE_COUNT: int = SAMPLES
	public const STAGES: int = Bits.RequiredFor(SAMPLES - 1)
	public const INPUT_LANES: int = 1
	public const OUTPUT_LANES: int = 1
	public const BUTTERFLY_COUNT: int = SAMPLES / 2 * STAGES
	public const BUTTERFLY_CYCLES: int = 2
	public const COMPUTE_CYCLES: int = BUTTERFLY_COUNT * BUTTERFLY_CYCLES
	public const NOMINAL_FRAME_LATENCY: int = SAMPLES + COMPUTE_CYCLES
	public const OUTPUT_INITIATION_INTERVAL: int = 2
	public const FRAME_INITIATION_INTERVAL: int = 3 * SAMPLES
		+ COMPUTE_CYCLES
	public const SAMPLE_STORAGE_WORDS: int = SAMPLES
	public const TWIDDLE_STORAGE_WORDS: int = SAMPLES / 2
	public const MULTIPLIER_COUNT: int = 4
	public const CONFIGURED_STAGE_SHIFT_MASK: int = STAGE_SHIFT_MASK
	public const CONFIGURED_DIRECTION: FftDirection = DIRECTION
	public const CONFIGURED_INPUT_ORDER: FftOrder = INPUT_ORDER
	public const CONFIGURED_OUTPUT_ORDER: FftOrder = OUTPUT_ORDER

	// Borrowed streams, elaboration shapes, and the owned sequential datapath.
	inputStream: IComplexSampleStream<logic[16]>
	outputStream: IComplexSampleStream<logic[16]>
	sampleShape: logic[SAMPLES]
	stageShape: logic[STAGES]
	primitive: SequentialFftQ15Primitive

	// Pulses when an accepted frame does not contain exactly SAMPLES tokens.
	public frameLengthError: out bool

	/**
	 * Binds borrowed scalar complex streams to the fixed transform configuration.
	 */
	new(inputStream: IComplexSampleStream<logic[16]>,
		outputStream: flip IComplexSampleStream<logic[16]>)
	{
		this.inputStream = inputStream
		this.outputStream = outputStream
		primitive = new SequentialFftQ15Primitive(sampleShape, stageShape,
			STAGE_SHIFT_MASK, DIRECTION == FftDirection.Inverse,
			INPUT_ORDER == FftOrder.BitReversed,
			OUTPUT_ORDER == FftOrder.BitReversed)
	}

	/**
	 * Connects the borrowed stream handshakes and aligned complex payloads.
	 */
	process Drive[]()
	{
		primitive.inputValid = inputStream.valid
		primitive.inputReal = inputStream.real
		primitive.inputImag = inputStream.imag
		primitive.inputFirst = inputStream.first
		primitive.inputLast = inputStream.last
		primitive.outputReady = outputStream.ready
		inputStream.ready = primitive.inputReady
		outputStream.valid = primitive.outputValid
		outputStream.real = primitive.outputReal
		outputStream.imag = primitive.outputImag
		outputStream.first = primitive.outputFirst
		outputStream.last = primitive.outputLast
		frameLengthError = primitive.frameLengthError
	}
}