Livt packages

Livt.Collections

Version 1.4.2

Fixed-capacity FIFOs, queues, stacks, circular buffers, lists, and bit sets for Livt hardware.

Published files (62)

src/fifo/AsyncFifoReadSide.lvt

namespace Livt.Collections

/**
 * Internal read-clock owner constructed by AsyncFifo.
 * Uses its supplied context and coordinated local clear; not an application API.
 */
component AsyncFifoReadSide<T, CAPACITY: int>
{
	// Address and wrap-bit widths for power-of-two storage.
	const ADDRESS_BITS: int = Bits.RequiredFor(CAPACITY - 1)
	const POINTER_BITS: int = ADDRESS_BITS + 1

	// Constructor-bound requests and remote pointer/storage signals.
	flush: bool
	pop: bool
	remote: logic[POINTER_BITS]
	inputData: T

	// Signal-level pointer: scheduled accessors would add an address cycle.
	public binary: out logic[POINTER_BITS]
	public gray: out logic[POINTER_BITS]
	public address: out logic[ADDRESS_BITS]

	// Destination-clock samples of the remote Gray pointer.
	stage1: logic[POINTER_BITS]
	stage2: logic[POINTER_BITS]

	// Registered read response, exposed combinationally to avoid accessor latency.
	response: T
	responseValid: bool
	public data: out T
	public valid: out bool

	// Local clear state and transfer status.
	clearSeen: bool
	public cleared: out bool
	public accepted: out bool
	public empty: out bool

	/**
	 * Binds the supplied clock/reset context and live input signals.
	 * The caller must coordinate reset/clear in both domains before traffic.
	 */
	new(domain: IContext, flush: bool, pop: bool, remote: logic[POINTER_BITS], inputData: T)
	{
		this.context = domain
		this.flush = flush
		this.pop = pop
		this.remote = remote
		this.inputData = inputData
	}

	/**
	 * Computes local status without adding clocked accessor latency.
	 */
	process Status[]()
	{
		this.cleared = clearSeen
		this.data = response
		this.valid = responseValid && !flush && context.rst == 0b0
		this.empty = gray == stage2
		this.address = (binary as uint) as logic[ADDRESS_BITS]
		this.accepted = !flush && context.rst == 0b0 && pop && !empty
	}

	/**
	 * Advances local state once per clock edge; preserves two synchronizer stages.
	 */
	process Update()
	{
		state Tick {
			if (flush) {
				this.clearSeen = true
				this.binary = 0
				this.gray = 0
				this.stage1 = 0
				this.stage2 = 0
				this.responseValid = false
			} else {
				this.clearSeen = false
				// Preserve the prior sample: sequential Livt assignments forward values.
				var previous = stage1
				this.stage1 = remote
				this.stage2 = previous
				this.responseValid = accepted

				if (accepted) {
					this.response = inputData
					var next = ((binary as uint) + 1) & (((2 * CAPACITY) - 1) as uint)
					this.binary = next as logic[POINTER_BITS]
					this.gray = (next ^ (next >> 1)) as logic[POINTER_BITS]
				}
			}

			goto Tick
		}
	}
}