Livt packages

Eccelerators.RiscV

Version 0.3.0

Composable RV32I and Zmmul processors, machine-mode support, and reusable FPGA system components written in Livt.

Published files (120)

src/System/Rv32LoadStoreBus.lvt

namespace Eccelerators.RiscV.System

using Eccelerators.RiscV.Sequential

/**
 * Combinational two-slot load/store router. Windows are half-open byte ranges
 * [BASE, BASE + SIZE) and must not wrap past the address space maximum; with
 * HAS_DEFAULT the second slot is the catch-all instead of a checked window.
 * The router is pure wiring: it never checks alignment (the engine faults on
 * unaligned addresses before the load/store port is requested) and it never
 * stores, delays or reorders requests. A slot sees request=1 only while its
 * window is hit, so the unselected device stays idle and its host
 * provisioning signals keep working while the other slot serves traffic. An
 * unmapped access (only possible without HAS_DEFAULT) faults immediately and
 * effect-free, with a combinational response. Provisioning of the slot
 * devices stays direct on the devices; the router does not forward it.
 */
component Rv32LoadStoreBus<A_BASE: uint = 0, A_SIZE: uint = 16, B_BASE: uint = 0,
	B_SIZE: uint = 16, HAS_DEFAULT: bool = true> : IRv32LoadStorePort
{
	static assert (A_BASE & 3) == 0, "Load/store window A base must be word aligned"
	static assert (B_BASE & 3) == 0, "Load/store window B base must be word aligned"
	static assert A_SIZE > 0 && B_SIZE > 0, "Load/store window sizes must be positive"
	static if (!HAS_DEFAULT) {
		static if (A_BASE <= B_BASE) {
			static assert A_SIZE <= B_BASE - A_BASE, "Windows must not overlap"
		} else {
			static assert B_SIZE <= A_BASE - B_BASE, "Windows must not overlap"
		}
	}

	static assert A_BASE <= 0xffffffff - (A_SIZE - 1), "Window A must not wrap"
	static assert HAS_DEFAULT || B_BASE <= 0xffffffff - (B_SIZE - 1), "Window B must not wrap"

	// Borrowed slot devices; the owner wires the device-side provisioning.
	slotA: IRv32LoadStorePort
	slotB: IRv32LoadStorePort

	// Combinational window decode.
	hitA: bool
	hitB: bool

	/**
	 * Borrows exactly the two routed load/store providers.
	 */
	new(a: flip IRv32LoadStorePort, b: flip IRv32LoadStorePort)
	{
		slotA = a
		slotB = b
	}

	/**
	 * Pure combinational routing; the selected slot completes the transaction.
	 */
	process Drive[]()
	{
		hitA = (address as uint) >= A_BASE && ((address as uint) - A_BASE) < A_SIZE

		if (HAS_DEFAULT) {
			hitB = !hitA
		} else {
			hitB = (address as uint) >= B_BASE && ((address as uint) - B_BASE) < B_SIZE
		}

		slotA.address = address
		slotB.address = address
		slotA.write = write
		slotB.write = write
		slotA.byteEnable = byteEnable
		slotB.byteEnable = byteEnable
		slotA.writeData = writeData
		slotB.writeData = writeData

		if (hitA) {
			slotA.request = request
		} else {
			slotA.request = 0b0
		}

		if (hitB) {
			slotB.request = request
		} else {
			slotB.request = 0b0
		}

		if (hitA) {
			ready = slotA.ready
			error = slotA.error
			readData = slotA.readData
		} elif (hitB) {
			ready = slotB.ready
			error = slotB.error
			readData = slotB.readData
		} else {
			ready = request
			error = request
			readData = 0
		}
	}
}