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
}
}
}