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/Rv32FetchBus.lvt

namespace Eccelerators.RiscV.System

using Eccelerators.RiscV.Sequential

/**
 * Combinational two-slot instruction fetch 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 fetch 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 request (only
 * possible without HAS_DEFAULT) faults immediately and effect-free, on the
 * combinational response to the request. Provisioning of the slot devices stays direct
 * on the devices; the router does not forward it.
 */
component Rv32FetchBus<A_BASE: uint = 0, A_SIZE: uint = 16, B_BASE: uint = 0,
	B_SIZE: uint = 16, HAS_DEFAULT: bool = true> : IRv32FetchPort
{
	static assert (A_BASE & 3) == 0, "Fetch window A base must be word aligned"
	static assert (B_BASE & 3) == 0, "Fetch window B base must be word aligned"
	static assert A_SIZE > 0 && B_SIZE > 0, "Fetch 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: IRv32FetchPort
	slotB: IRv32FetchPort

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

	/**
	 * Borrows exactly the two routed fetch providers.
	 */
	new(a: flip IRv32FetchPort, b: flip IRv32FetchPort)
	{
		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

		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
			instruction = slotA.instruction
		} elif (hitB) {
			ready = slotB.ready
			error = slotB.error
			instruction = slotB.instruction
		} else {
			ready = request
			error = request
			instruction = 0
		}
	}
}