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)
- fixtures
- DelayedWordDevice.lvt
- PipelineFetchMemory.lvt
- PipelineWordDevice.lvt
- README.md
- Rv32BusCoreTest.lvt
- Rv32BusProtocolTest.lvt
- Rv32CsrEngineTest.lvt
- Rv32CsrRetirement.lvt
- Rv32DspControlTest.lvt
- Rv32DspEngineTest.lvt
- Rv32DspMultiplierTest.lvt
- Rv32DualReadDistributedTest.lvt
- Rv32DualReadRegisterBankTest.lvt
- Rv32ExternalInterruptTest.lvt
- Rv32FetchBusTest.lvt
- Rv32iConstantsTest.lvt
- Rv32iDecodeTest.lvt
- Rv32InterruptCsrTest.lvt
- Rv32iPackageApiTest.lvt
- Rv32iSemanticsTest.lvt
- Rv32IterativeMultiplierTest.lvt
- Rv32LoadStoreBusTest.lvt
- Rv32MachineCsrsTest.lvt
- Rv32MachineDecoderTest.lvt
- Rv32MultiplyRetirement.lvt
- Rv32MultiplyVectors.lvt
- Rv32PipelineControlTest.lvt
- Rv32PipelineCsrEngineTest.lvt
- Rv32PipelineDspEngineTest.lvt
- Rv32PipelineEngineTest.lvt
- Rv32PipelineExternalInterruptTest.lvt
- Rv32PipelineTimerInterruptTest.lvt
- Rv32PipelineTrapEngineTest.lvt
- Rv32PipelineZmmulEngineTest.lvt
- Rv32RegisterBankTest.lvt
- Rv32SequentialControlTest.lvt
- Rv32SequentialEngineTest.lvt
- Rv32TimerInterruptTest.lvt
- Rv32TrapEngineTest.lvt
- Rv32TrapPolicyTest.lvt
- Rv32ZicsrAccessTest.lvt
- Rv32ZicsrDecoderTest.lvt
- Rv32ZmmulControlTest.lvt
- Rv32ZmmulDecodeTest.lvt
- Rv32ZmmulEngineTest.lvt
- RvExternalInterruptsTest.lvt
- RvMachineSystemTest.lvt
- RvMachineTimerTest.lvt
- RvPipelineSystemTest.lvt
- RvSystemTest.lvt
- RvUartDeviceTest.lvt
- RvUartSystemTest.lvt
tests/Rv32LoadStoreBusTest.lvt
namespace Eccelerators.RiscV.Tests
using Eccelerators.RiscV.Sequential
using Eccelerators.RiscV.Storage
using Eccelerators.RiscV.System
/**
* Direct unit tests for the two-slot load/store router: window routing with
* request gating, default catch-all and immediate effect-free unmapped faults.
* Every cell is first initialized by a store that must route to its own slot,
* so reading it back through the bus proves both routing and isolation.
*/
@Test
component Rv32LoadStoreBusTest
{
// Slot devices and routers under test in the test clock domain.
slotA: RvLoadStoreRam<4, 10, MemoryStyle.Block, 0>
slotB: RvLoadStoreRam<4, 10, MemoryStyle.Block, 16>
bus: Rv32LoadStoreBus<0, 16, 16, 16, false>
defA: RvLoadStoreRam<4, 10, MemoryStyle.Block, 0>
defB: RvLoadStoreRam<4, 10, MemoryStyle.Block, 16>
defBus: Rv32LoadStoreBus<0, 16, 16, 16, true>
/**
* Instantiates both routers with concrete slot devices.
*/
new()
{
slotA = new RvLoadStoreRam<4, 10, MemoryStyle.Block, 0>()
slotB = new RvLoadStoreRam<4, 10, MemoryStyle.Block, 16>()
bus = new Rv32LoadStoreBus<0, 16, 16, 16, false>(slotA, slotB)
defA = new RvLoadStoreRam<4, 10, MemoryStyle.Block, 0>()
defB = new RvLoadStoreRam<4, 10, MemoryStyle.Block, 16>()
defBus = new Rv32LoadStoreBus<0, 16, 16, 16, true>(defA, defB)
}
/**
* Stores through the plain bus initialize each slot's cell only when the
* address lands in that slot's window; both words then read back intact.
*/
@Test
fn TestWindowRouting()
{
state {
bus.request = 0b0
defBus.request = 0b0
}
Simulation.Wait(4)
var elapsed: uint = 0
// First store targets slot B's window; slot A must stay idle.
state {
bus.request = 0b1
bus.write = 0b1
bus.byteEnable = 0b1111
bus.address = 16 as logic[32]
bus.writeData = 22 as logic[32]
}
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
state {
bus.request = 0b0
bus.write = 0b0
bus.byteEnable = 0b0000
bus.address = 0 as logic[32]
bus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
// Second store targets slot A's window at word index 1.
state {
bus.request = 0b1
bus.write = 0b1
bus.byteEnable = 0b1111
bus.address = 4 as logic[32]
bus.writeData = 0x1122aa44 as logic[32]
}
elapsed = 0
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
state {
bus.request = 0b0
bus.write = 0b0
bus.byteEnable = 0b0000
bus.address = 0 as logic[32]
bus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
// Slot A kept its word untouched by the window B store.
state {
bus.request = 0b1
bus.address = 4 as logic[32]
}
elapsed = 0
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
assert bus.readData as uint == 0x1122aa44
state {
bus.request = 0b0
}
Simulation.Wait(2)
// Load of slot B's cell after the transaction above fully retired.
state {
bus.request = 0b1
bus.address = 16 as logic[32]
}
elapsed = 0
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
assert bus.readData as uint == 22
state {
bus.request = 0b0
}
}
/**
* Outside both windows the access faults immediately and effect-free: the
* faulted store lands nowhere, the read data is 0 and the error falls
* combinationally with the request.
*/
@Test
fn TestUnmappedAccessFault()
{
state {
bus.request = 0b0
defBus.request = 0b0
}
Simulation.Wait(4)
var elapsed: uint = 0
// Initialize slot A's cell so effect-freeness is observable.
state {
bus.request = 0b1
bus.write = 0b1
bus.byteEnable = 0b1111
bus.address = 4 as logic[32]
bus.writeData = 77 as logic[32]
}
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
state {
bus.request = 0b0
bus.write = 0b0
bus.byteEnable = 0b0000
bus.address = 0 as logic[32]
bus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
// An unmapped store faults combinationally with the request, effect-free.
state {
bus.request = 0b1
bus.write = 0b1
bus.byteEnable = 0b1111
bus.address = 0x10000 as logic[32]
bus.writeData = 0xdeadbeef as logic[32]
}
Simulation.Wait(2)
Simulation.Wait(2)
assert bus.ready == 0b1 && bus.error == 0b1 && bus.readData == 0
state {
bus.request = 0b0
}
Simulation.Wait(2)
state {
bus.request = 0b1
bus.write = 0b0
bus.byteEnable = 0b0000
bus.address = 0x20000 as logic[32]
bus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
assert bus.ready == 0b1 && bus.error == 0b1 && bus.readData == 0
state {
bus.request = 0b0
bus.address = 4 as logic[32]
}
Simulation.Wait(2)
assert bus.ready == 0b0 && bus.error == 0b0
// The faulted store never reached slot A.
state {
bus.request = 0b1
}
elapsed = 0
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
assert bus.readData as uint == 77
state {
bus.request = 0b0
}
}
/**
* A byte-lane store through the bus lands only on the enabled lane.
*/
@Test
fn TestByteLaneStore()
{
state {
bus.request = 0b0
defBus.request = 0b0
}
Simulation.Wait(4)
var elapsed: uint = 0
state {
bus.request = 0b1
bus.write = 0b1
bus.byteEnable = 0b1111
bus.address = 0 as logic[32]
bus.writeData = 0xaabbccdd as logic[32]
}
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
state {
bus.request = 0b0
bus.write = 0b0
bus.byteEnable = 0b0000
bus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
state {
bus.request = 0b1
bus.write = 0b1
bus.byteEnable = 0b0010
bus.address = 0 as logic[32]
bus.writeData = 0x0000ff00 as logic[32]
}
elapsed = 0
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
state {
bus.request = 0b0
bus.write = 0b0
bus.byteEnable = 0b0000
bus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
state {
bus.request = 0b1
bus.address = 0 as logic[32]
}
elapsed = 0
while (bus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert bus.ready == 0b1 && bus.error == 0b0
assert bus.readData as uint == 0xaabbffdd
state {
bus.request = 0b0
}
}
/**
* With a default slot everything outside window A stores and loads from
* slot B; a far catch-all store faults in slot B's own range check while
* both slots' contents stay untouched.
*/
@Test
fn TestDefaultCatchAll()
{
state {
bus.request = 0b0
defBus.request = 0b0
}
Simulation.Wait(4)
var elapsed: uint = 0
// Initialize slot A's cell through the default bus.
state {
defBus.request = 0b1
defBus.write = 0b1
defBus.byteEnable = 0b1111
defBus.address = 0 as logic[32]
defBus.writeData = 66 as logic[32]
}
while (defBus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert defBus.ready == 0b1 && defBus.error == 0b0
state {
defBus.request = 0b0
defBus.write = 0b0
defBus.byteEnable = 0b0000
defBus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
// Address outside window A routes to the catch-all slot B.
state {
defBus.request = 0b1
defBus.write = 0b1
defBus.byteEnable = 0b1111
defBus.address = 16 as logic[32]
defBus.writeData = 77 as logic[32]
}
elapsed = 0
while (defBus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert defBus.ready == 0b1 && defBus.error == 0b0
state {
defBus.request = 0b0
defBus.write = 0b0
defBus.byteEnable = 0b0000
defBus.address = 0 as logic[32]
defBus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
state {
defBus.request = 0b1
defBus.address = 0 as logic[32]
}
elapsed = 0
while (defBus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert defBus.ready == 0b1 && defBus.error == 0b0
assert defBus.readData as uint == 66
state {
defBus.request = 0b0
}
Simulation.Wait(2)
state {
defBus.request = 0b1
defBus.address = 16 as logic[32]
}
elapsed = 0
while (defBus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert defBus.ready == 0b1 && defBus.error == 0b0
assert defBus.readData as uint == 77
state {
defBus.request = 0b0
defBus.address = 0 as logic[32]
}
Simulation.Wait(2)
// The far catch-all address still routes to slot B, which range-checks
// and faults before applying the store.
state {
defBus.request = 0b1
defBus.write = 0b1
defBus.byteEnable = 0b1111
defBus.address = 0x40000000 as logic[32]
defBus.writeData = 88 as logic[32]
}
elapsed = 0
while (defBus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert defBus.ready == 0b1 && defBus.error == 0b1
state {
defBus.request = 0b0
defBus.write = 0b0
defBus.byteEnable = 0b0000
defBus.address = 0 as logic[32]
defBus.writeData = 0 as logic[32]
}
Simulation.Wait(2)
// The faulted catch-all store left slot A's word untouched.
state {
defBus.request = 0b1
}
elapsed = 0
while (defBus.ready == 0b0 && elapsed < 8) {
state {
elapsed++
}
}
assert defBus.ready == 0b1 && defBus.error == 0b0
assert defBus.readData as uint == 66
state {
defBus.request = 0b0
}
}
}