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/axi4lite/testing/Axi4LiteTestMaster32.lvt

namespace Livt.Bus.Axi4Lite.Testing

using Livt.Bus
using Livt.Bus.Axi4Lite

/**
 * AXI4-Lite transaction master intended for component and register tests.
 */
component Axi4LiteTestMaster32 : IAxi4Lite32Master, IMemoryMappedBus32
{
	/**
	 * AXI response code for a successful normal access.
	 */
	public const RESPONSE_OKAY: Logic[2] = 0b00

	/**
	 * AXI response code for a successful exclusive access.
	 */
	public const RESPONSE_EXOKAY: Logic[2] = 0b01

	/**
	 * AXI response code for a target-reported slave error.
	 */
	public const RESPONSE_SLVERR: Logic[2] = 0b10

	/**
	 * AXI response code for an address decode error.
	 */
	public const RESPONSE_DECERR: Logic[2] = 0b11

	/**
	 * Byte-enable value selecting all four data lanes.
	 */
	public const ALL_BYTES: Logic[4] = 0b1111

	timeoutTicks: uint
	lastReadValue: uint
	lastResponse: Logic[2]
	lastTimedOut: bool

	new()
	{
		this.awaddr = 0x00000000
		this.awprot = 0b000
		this.awvalid = 0b0
		this.wdata = 0x00000000
		this.wstrb = 0b0000
		this.wvalid = 0b0
		this.bready = 0b0
		this.araddr = 0x00000000
		this.arprot = 0b000
		this.arvalid = 0b0
		this.rready = 0b0
		this.timeoutTicks = this.context.TicksFor(1ms)
		this.lastReadValue = 0
		this.lastResponse = RESPONSE_OKAY
		this.lastTimedOut = false
	}

	/**
	 * Sets the timeout applied independently to each AXI handshake stage.
	 * The count is exact; zero times out on the first stalled evaluation.
	 */
	override fn SetTimeoutTicks(timeoutTicks: uint)
	{
		this.timeoutTicks = timeoutTicks
	}

	/**
	 * Returns the timeout applied independently to each AXI handshake stage.
	 */
	override fn GetTimeoutTicks() uint
	{
		return timeoutTicks
	}

	/**
	 * Returns the data captured by the most recently completed read.
	 */
	override fn LastReadValue() uint
	{
		return lastReadValue
	}

	/**
	 * Returns the AXI response captured by the most recently completed transaction.
	 */
	override fn LastResponse() Logic[2]
	{
		return lastResponse
	}

	/**
	 * Returns true when the most recent transaction timed out.
	 */
	override fn LastTimedOut() bool
	{
		return lastTimedOut
	}

	/**
	 * Performs a non-asserting AXI4-Lite write using the selected byte lanes.
	 * Returns true after a response handshake; inspect LastResponse for its status.
	 * After a timeout, the call drains the outstanding transaction before returning.
	 */
	private fn ExecuteWrite32(address: uint, value: uint, byteEnable: Logic[4]) bool
	{
		var addressAccepted: bool = false
		var dataAccepted: bool = false
		var elapsed: uint = 0
		var successful: bool = false

		state Start {
			lastResponse = RESPONSE_OKAY
			lastTimedOut = false
			addressAccepted = false
			dataAccepted = false
			elapsed = 0
			successful = false
			this.awaddr = address as Logic[32]
			this.awprot = 0b000
			this.awvalid = 0b1
			this.wdata = value as Logic[32]
			this.wstrb = byteEnable
			this.wvalid = 0b1
			this.bready = 0b0
			goto Transfer
		}

		state Transfer {
			if (this.awready == 0b1) {
				addressAccepted = true
				this.awvalid = 0b0
			}

			if (this.wready == 0b1) {
				dataAccepted = true
				this.wvalid = 0b0
			}

			if (addressAccepted && dataAccepted) {
				this.bready = 0b1
				elapsed = 0
				goto Response
			} elif ((elapsed + 1) >= timeoutTicks) {
				lastTimedOut = true
				successful = false
				goto RecoverWriteTransfer
			} else {
				elapsed = elapsed + 1
				goto Transfer
			}
		}

		state Response {
			if (this.bvalid == 0b1) {
				lastResponse = this.bresp
				goto Complete
			} elif ((elapsed + 1) >= timeoutTicks) {
				lastTimedOut = true
				successful = false
				goto RecoverWriteResponse
			} else {
				elapsed = elapsed + 1
				goto Response
			}
		}

		state Complete {
			this.awvalid = 0b0
			this.wvalid = 0b0
			this.bready = 0b0
			lastTimedOut = false
			successful = true
			goto Finish
		}

		state RecoverWriteTransfer {
			if (this.awready == 0b1) {
				addressAccepted = true
				this.awvalid = 0b0
			}

			if (this.wready == 0b1) {
				dataAccepted = true
				this.wvalid = 0b0
			}

			if (addressAccepted && dataAccepted) {
				this.bready = 0b1
				goto RecoverWriteResponse
			} else {
				goto RecoverWriteTransfer
			}
		}

		state RecoverWriteResponse {
			if (this.bvalid == 0b1) {
				this.bready = 0b0
				goto Finish
			} else {
				goto RecoverWriteResponse
			}
		}

		state Finish {}

		return successful
	}

	/**
	 * Performs a non-asserting AXI4-Lite read and stores the returned data.
	 * Returns true after a data handshake; inspect LastResponse for its status.
	 * After a timeout, the call drains the outstanding transaction before returning.
	 */
	private fn ExecuteRead32(address: uint) bool
	{
		var elapsed: uint = 0
		var successful: bool = false

		state Start {
			lastReadValue = 0
			lastResponse = RESPONSE_OKAY
			lastTimedOut = false
			elapsed = 0
			successful = false
			this.araddr = address as Logic[32]
			this.arprot = 0b000
			this.arvalid = 0b1
			this.rready = 0b0
			goto Address
		}

		state Address {
			if (this.arready == 0b1) {
				this.arvalid = 0b0
				this.rready = 0b1
				elapsed = 0
				goto Data
			} elif ((elapsed + 1) >= timeoutTicks) {
				lastTimedOut = true
				successful = false
				goto RecoverReadAddress
			} else {
				elapsed = elapsed + 1
				goto Address
			}
		}

		state Data {
			if (this.rvalid == 0b1) {
				lastReadValue = this.rdata as uint
				lastResponse = this.rresp
				goto Complete
			} elif ((elapsed + 1) >= timeoutTicks) {
				lastTimedOut = true
				successful = false
				goto RecoverReadData
			} else {
				elapsed = elapsed + 1
				goto Data
			}
		}

		state Complete {
			this.arvalid = 0b0
			this.rready = 0b0
			lastTimedOut = false
			successful = true
			goto Finish
		}

		state RecoverReadAddress {
			if (this.arready == 0b1) {
				this.arvalid = 0b0
				this.rready = 0b1
				goto RecoverReadData
			} else {
				goto RecoverReadAddress
			}
		}

		state RecoverReadData {
			if (this.rvalid == 0b1) {
				this.rready = 0b0
				goto Finish
			} else {
				goto RecoverReadData
			}
		}

		state Finish {}

		return successful
	}

	/**
	 * Provides the non-asserting write operation inherited by the common API.
	 */
	override fn TryWrite32(address: uint, value: uint, byteEnable: Logic[4]) bool
	{
		var successful = this.ExecuteWrite32(address, value, byteEnable)

		state Settle {}

		return successful
	}

	/**
	 * Provides the non-asserting read operation inherited by the common API.
	 */
	override fn TryRead32(address: uint) bool
	{
		var successful = this.ExecuteRead32(address)

		state Settle {}

		return successful
	}

	/**
	 * Writes one byte and asserts completion with an AXI OKAY response.
	 */
	override fn Write8(address: uint, value: byte)
	{
		var lane = (address & (3 as uint)) as int
		var shift = lane * 8
		var alignedAddress = address & (0xFFFFFFFC as uint)
		var shiftedValue = (value as uint) << shift
		var byteEnable: Logic[4] = 0b0001

		if (lane == 1) {
			byteEnable = 0b0010
		} elif (lane == 2) {
			byteEnable = 0b0100
		} elif (lane == 3) {
			byteEnable = 0b1000
		}

		var completed = this.ExecuteWrite32(alignedAddress, shiftedValue, byteEnable)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
	}

	/**
	 * Writes one aligned halfword and asserts completion with an AXI OKAY response.
	 */
	override fn Write16(address: uint, value: Logic[16])
	{
		assert (address & (1 as uint)) == (0 as uint)
		var lane = (address & (2 as uint)) as int
		var shift = lane * 8
		var alignedAddress = address & (0xFFFFFFFC as uint)
		var shiftedValue = (value as uint) << shift
		var byteEnable: Logic[4] = 0b0011

		if (lane == 2) {
			byteEnable = 0b1100
		}

		var completed = this.ExecuteWrite32(alignedAddress, shiftedValue, byteEnable)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
	}

	/**
	 * Writes one word and asserts completion with an AXI OKAY response.
	 */
	override fn Write32(address: uint, value: uint)
	{
		assert (address & (3 as uint)) == (0 as uint)
		var completed = this.ExecuteWrite32(address, value, ALL_BYTES)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
	}

	/**
	 * Writes selected byte lanes and asserts completion with an AXI OKAY response.
	 */
	override fn WriteMasked32(address: uint, value: uint, byteEnable: Logic[4])
	{
		assert (address & (3 as uint)) == (0 as uint)
		var completed = this.ExecuteWrite32(address, value, byteEnable)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
	}

	/**
	 * Reads one byte and asserts completion with an AXI OKAY response.
	 */
	override fn Read8(address: uint) byte
	{
		var lane = (address & (3 as uint)) as int
		var shift = lane * 8
		var alignedAddress = address & (0xFFFFFFFC as uint)
		var completed = this.ExecuteRead32(alignedAddress)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		return (lastReadValue >> shift) as byte
	}

	/**
	 * Reads one aligned halfword and asserts completion with an AXI OKAY response.
	 */
	override fn Read16(address: uint) Logic[16]
	{
		assert (address & (1 as uint)) == (0 as uint)
		var lane = (address & (2 as uint)) as int
		var shift = lane * 8
		var alignedAddress = address & (0xFFFFFFFC as uint)
		var completed = this.ExecuteRead32(alignedAddress)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		return (lastReadValue >> shift) as Logic[16]
	}

	/**
	 * Reads one word and asserts completion with an AXI OKAY response.
	 */
	override fn Read32(address: uint) uint
	{
		assert (address & (3 as uint)) == (0 as uint)
		var completed = this.ExecuteRead32(address)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		return lastReadValue
	}

	/**
	 * Reads one byte and asserts that it equals the expected value.
	 */
	override fn Verify8(address: uint, expected: byte)
	{
		var lane = (address & (3 as uint)) as int
		var shift = lane * 8
		var alignedAddress = address & (0xFFFFFFFC as uint)
		var completed = this.ExecuteRead32(alignedAddress)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		assert ((lastReadValue >> shift) as byte) == expected
	}

	/**
	 * Reads one halfword and asserts that it equals the expected value.
	 */
	override fn Verify16(address: uint, expected: Logic[16])
	{
		assert (address & (1 as uint)) == (0 as uint)
		var lane = (address & (2 as uint)) as int
		var shift = lane * 8
		var alignedAddress = address & (0xFFFFFFFC as uint)
		var completed = this.ExecuteRead32(alignedAddress)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		assert ((lastReadValue >> shift) as Logic[16]) == expected
	}

	/**
	 * Reads one word and asserts that it equals the expected value.
	 */
	override fn Verify32(address: uint, expected: uint)
	{
		assert (address & (3 as uint)) == (0 as uint)
		var completed = this.ExecuteRead32(address)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		assert lastReadValue == expected
	}

	/**
	 * Reads one word and compares only bits selected by the mask.
	 */
	override fn VerifyMasked32(address: uint, expected: uint, mask: uint)
	{
		assert (address & (3 as uint)) == (0 as uint)
		var completed = this.ExecuteRead32(address)
		assert completed == true
		assert lastResponse == RESPONSE_OKAY
		assert (lastReadValue & mask) == (expected & mask)
	}
}