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/Storage/Rv32DualReadRegisterBank.lvt
namespace Eccelerators.RiscV.Storage
using Livt.IO
/**
* Two synchronous read copies with one broadcast write, BRAM requested by default.
* Each copy has one read and one write port; no multi-pumped clock is required.
* Explicit forwarding makes read/write collisions independent of inferred RAM
* collision mode. Owns storage exclusively in the inherited clock/reset context.
* STYLE is an implementation hint; physical mapping must be measured per target.
*/
component Rv32DualReadRegisterBank<STYLE: MemoryStyle = MemoryStyle.Block> : IRv32DualReadRegisterPort
{
// Capabilities consumed by the bounded pipeline construction contract.
public const READ_PORTS: int = 2
public const READ_LATENCY: int = 1
public const INDEPENDENT_WRITE: bool = true
public const WRITE_FORWARDING: bool = true
// Replicated payload has no reset; the engine initializes both copies by writing.
@Memory(Style = STYLE)
@UninitializedStorage
leftStorage: logic[32, 32]
@Memory(Style = STYLE)
@UninitializedStorage
rightStorage: logic[32, 32]
// Raw RAM responses and sampled correction data share the accepting read edge.
leftResponse: logic[32]
rightResponse: logic[32]
leftZero: bool
rightZero: bool
leftCollision: bool
rightCollision: bool
forwarded: logic[32]
/**
* Owns storage; no constructor-time payload initialization is promised.
*/
new()
{
}
/**
* Owns the left RAM copy with independent synchronous read and write commands.
*/
process Left()
{
state {
if (readEnable == 0b1) {
leftResponse = leftStorage[leftIndex as uint]
}
if (writeEnable == 0b1 && writeIndex != 0) {
leftStorage[writeIndex as uint] = writeData
}
}
}
/**
* Owns the right RAM copy; writes are identical to those of the left copy.
*/
process Right()
{
state {
if (readEnable == 0b1) {
rightResponse = rightStorage[rightIndex as uint]
}
if (writeEnable == 0b1 && writeIndex != 0) {
rightStorage[writeIndex as uint] = writeData
}
}
}
/**
* Captures bypass and zero selections only when accepting a new operand pair.
*/
process Sample()
{
state {
if (readEnable == 0b1) {
leftZero = leftIndex == 0
rightZero = rightIndex == 0
leftCollision = writeEnable == 0b1 && writeIndex == leftIndex
rightCollision = writeEnable == 0b1 && writeIndex == rightIndex
forwarded = writeData
}
}
}
/**
* Corrects collisions without relying on vendor-specific read-during-write data.
*/
process Drive[]()
{
leftData = leftResponse
rightData = rightResponse
if (leftCollision) {
leftData = forwarded
}
if (rightCollision) {
rightData = forwarded
}
if (leftZero) {
leftData = 0
}
if (rightZero) {
rightData = 0
}
}
}