Livt packages

Livt.Bus

Version 2.0.1

Configurable Avalon, AXI4-Lite, and Wishbone memory-mapped masters, interfaces, bridges, and test components.

Published files (67)

src/bridges/Axi4LiteToAvalonBridge32.lvt

namespace Livt.Bus.Bridges

using Livt.Bus.Avalon
using Livt.Bus.Axi4Lite

/**
 * Converts AXI4-Lite transactions into non-pipelined Avalon-MM transactions.
 * The bridge accepts AXI write address and data independently and supports one
 * downstream transaction at a time.
 */
component Axi4LiteToAvalonBridge32 : IAvalon32Master
{
	// Response returned to AXI after normal Avalon request acceptance.
	public const RESPONSE_OKAY: Logic[2] = 0b00

	// Response returned to AXI when Avalon request acceptance times out.
	public const RESPONSE_SLVERR: Logic[2] = 0b10

	// AXI4-Lite source connected to the upstream side of this bridge.
	upstream: IAxi4Lite32Master

	// Maximum ticks to wait while downstream Avalon holds waitrequest high.
	timeoutTicks: uint

	// True only when the most recent downstream request timed out.
	lastTimedOut: bool

	// True while a timed-out Avalon request remains asserted for acceptance.
	recovering: bool

	/**
	 * Connects an AXI4-Lite source and initializes the Avalon-MM master outputs.
	 * The default Avalon acceptance timeout is 1 ms.
	 */
	new(upstream: flip IAxi4Lite32Master)
	{
		this.upstream = upstream
		this.upstream.awready = 0b0
		this.upstream.wready = 0b0
		this.upstream.bresp = RESPONSE_OKAY
		this.upstream.bvalid = 0b0
		this.upstream.arready = 0b0
		this.upstream.rdata = 0x00000000
		this.upstream.rresp = RESPONSE_OKAY
		this.upstream.rvalid = 0b0
		this.address = 0x00000000
		this.byteenable = 0b0000
		this.write = 0b0
		this.writedata = 0x00000000
		this.read = 0b0
		this.timeoutTicks = this.context.TicksFor(1ms)
		this.lastTimedOut = false
		this.recovering = false
	}

	/**
	 * Sets the maximum ticks to wait for downstream Avalon request acceptance.
	 * The count is exact; zero times out on the first stalled evaluation.
	 * A timeout returns RESPONSE_SLVERR on the matching AXI response channel.
	 */
	public fn SetTimeoutTicks(timeoutTicks: uint)
	{
		this.timeoutTicks = timeoutTicks
	}

	/**
	 * Returns the maximum ticks allowed for Avalon request acceptance.
	 */
	public fn GetTimeoutTicks() uint
	{
		return timeoutTicks
	}

	/**
	 * Returns true when the most recent downstream Avalon request timed out.
	 */
	public fn LastTimedOut() bool
	{
		return lastTimedOut
	}

	/**
	 * Returns true while the bridge completes a timed-out Avalon request.
	 * New AXI requests remain stalled until recovery completes.
	 */
	public fn IsRecovering() bool
	{
		return recovering
	}

	/**
	 * Captures AXI channels and sequences one corresponding Avalon request.
	 */
	process Run()
	{
		var writeAddress: Logic[32] = 0x00000000
		var writeValue: Logic[32] = 0x00000000
		var writeEnable: Logic[4] = 0b0000
		var addressAccepted: bool = false
		var dataAccepted: bool = false
		var downstreamAccepted: bool = false
		var responseAccepted: bool = false
		var elapsed: uint = 0

		state Idle {
			this.upstream.awready = 0b0
			this.upstream.wready = 0b0
			this.upstream.arready = 0b0
			this.upstream.bvalid = 0b0
			this.upstream.rvalid = 0b0
			this.write = 0b0
			this.read = 0b0
			this.byteenable = 0b0000
			addressAccepted = false
			dataAccepted = false

			if (this.upstream.awvalid == 0b1 || this.upstream.wvalid == 0b1) {
				lastTimedOut = false
				recovering = false
				this.upstream.awready = 0b1
				this.upstream.wready = 0b1
				goto CaptureWrite
			} elif (this.upstream.arvalid == 0b1) {
				lastTimedOut = false
				recovering = false
				this.upstream.arready = 0b1
				goto CaptureRead
			} else {
				goto Idle
			}
		}

		state CaptureWrite {
			if (addressAccepted == false && this.upstream.awvalid == 0b1) {
				writeAddress = this.upstream.awaddr
				addressAccepted = true
				this.upstream.awready = 0b0
			}

			if (dataAccepted == false && this.upstream.wvalid == 0b1) {
				writeValue = this.upstream.wdata
				writeEnable = this.upstream.wstrb
				dataAccepted = true
				this.upstream.wready = 0b0
			}

			if (addressAccepted && dataAccepted) {
				this.address = writeAddress
				this.writedata = writeValue
				this.byteenable = writeEnable
				this.write = 0b1
				elapsed = 0
				goto AvalonWrite
			} else {
				goto CaptureWrite
			}
		}

		state AvalonWrite {
			if (this.waitrequest == 0b0) {
				this.write = 0b0
				this.byteenable = 0b0000
				this.upstream.bresp = this.response
				this.upstream.bvalid = 0b1
				goto WriteResponse
			} elif ((elapsed + 1) >= timeoutTicks) {
				lastTimedOut = true
				recovering = true
				downstreamAccepted = false
				responseAccepted = false
				this.upstream.bresp = RESPONSE_SLVERR
				this.upstream.bvalid = 0b1
				goto RecoverAvalonWrite
			} else {
				elapsed = elapsed + 1
				goto AvalonWrite
			}
		}

		state WriteResponse {
			if (this.upstream.bready == 0b1) {
				this.upstream.bvalid = 0b0
				goto Idle
			} else {
				goto WriteResponse
			}
		}

		state CaptureRead {
			if (this.upstream.arvalid == 0b1) {
				this.address = this.upstream.araddr
				this.byteenable = 0b1111
				this.read = 0b1
				this.upstream.arready = 0b0
				elapsed = 0
				goto AvalonRead
			} else {
				goto CaptureRead
			}
		}

		state AvalonRead {
			if (this.waitrequest == 0b0) {
				this.read = 0b0
				this.byteenable = 0b0000
				this.upstream.rdata = this.readdata
				this.upstream.rresp = this.response
				this.upstream.rvalid = 0b1
				goto ReadResponse
			} elif ((elapsed + 1) >= timeoutTicks) {
				lastTimedOut = true
				recovering = true
				downstreamAccepted = false
				responseAccepted = false
				this.upstream.rdata = 0x00000000
				this.upstream.rresp = RESPONSE_SLVERR
				this.upstream.rvalid = 0b1
				goto RecoverAvalonRead
			} else {
				elapsed = elapsed + 1
				goto AvalonRead
			}
		}

		state ReadResponse {
			if (this.upstream.rready == 0b1) {
				this.upstream.rvalid = 0b0
				goto Idle
			} else {
				goto ReadResponse
			}
		}

		state RecoverAvalonWrite {
			if (downstreamAccepted == false && this.waitrequest == 0b0) {
				this.write = 0b0
				this.byteenable = 0b0000
				downstreamAccepted = true
			}

			if (responseAccepted == false && this.upstream.bready == 0b1) {
				this.upstream.bvalid = 0b0
				responseAccepted = true
			}

			if (downstreamAccepted && responseAccepted) {
				recovering = false
				goto Idle
			} else {
				goto RecoverAvalonWrite
			}
		}

		state RecoverAvalonRead {
			if (downstreamAccepted == false && this.waitrequest == 0b0) {
				this.read = 0b0
				this.byteenable = 0b0000
				downstreamAccepted = true
			}

			if (responseAccepted == false && this.upstream.rready == 0b1) {
				this.upstream.rvalid = 0b0
				responseAccepted = true
			}

			if (downstreamAccepted && responseAccepted) {
				recovering = false
				goto Idle
			} else {
				goto RecoverAvalonRead
			}
		}
	}
}