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/Rv32PipelineCsrEngineTest.lvt
namespace Eccelerators.RiscV.Tests
using Eccelerators.RiscV.Pipeline
using Eccelerators.RiscV.Sequential
using Eccelerators.RiscV.Storage
using Eccelerators.RiscV.Presets
using Eccelerators.RiscV.Machine
/**
* Instruction-level checks observe committed writes independently of CPU storage.
* Every wait is bounded so a stalled bus or controller fails the test.
*/
@Test
component Rv32PipelineCsrEngineTest
{
// Owned platform, explicit execution composition and architectural scoreboard.
fetch: RvFetchRom<512, 9>
loadStore: RvLoadStoreRam<256, 8>
core: Rv32PipelineEngine<0>
registers: Rv32DualReadRegisterBank
baseDecoder: Rv32iZmmulDecoder
decoder: Rv32ZicsrDecoder
integer: Rv32iIntegerUnit
multiplier: Rv32DspMultiplier
csrs: Rv32MachineCsrs
observed: uint[32]
retireCount: uint
clearObservation: bool
cycles: uint
csrCommits: uint
lastCsrCycle: uint
previousWasCsr: bool
tracePc: uint[512]
traceWord: uint[512]
traceRd: uint[512]
traceValue: uint[512]
/**
* Creates distinct instruction and data providers in the test clock context.
*/
new()
{
fetch = new RvFetchRom<512, 9>()
loadStore = new RvLoadStoreRam<256, 8>()
registers = new Rv32DualReadRegisterBank()
baseDecoder = new Rv32iZmmulDecoder()
decoder = new Rv32ZicsrDecoder(baseDecoder)
integer = new Rv32iIntegerUnit()
multiplier = new Rv32DspMultiplier()
csrs = new Rv32MachineCsrs()
core = new Rv32PipelineEngine<0>(registers, fetch, loadStore, decoder, integer, multiplier, csrs)
}
/**
* Samples retirement every clock; tests never read a CPU-private register array.
*/
process Observe()
{
state {
cycles++
if (clearObservation) {
csrCommits = 0
previousWasCsr = false
} elif (csrs.retire == 0b1) {
if (csrs.commit == 0b1) {
lastCsrCycle = cycles
csrCommits++
Simulation.Report("CSR commit")
}
previousWasCsr = csrs.commit == 0b1
}
assert csrs.commit == 0b0 || (csrs.retire == 0b1 && csrs.illegal == 0b0)
if (clearObservation) {
retireCount = 0
} elif (core.retired == 0b1) {
assert retireCount < 512
tracePc[retireCount] = core.retiredPc as uint
traceWord[retireCount] = core.retiredInstruction as uint
traceRd[retireCount] = core.retiredRd as uint
traceValue[retireCount] = core.retiredValue as uint
retireCount++
if (core.retiredRd != 0) {
observed[core.retiredRd as uint] = core.retiredValue as uint
}
}
}
}
/**
* Programs one word with the CPU paused; writes are sampled once.
*/
fn Load(index: uint, word: uint)
{
state {
fetch.programWrite = 0b1
fetch.programIndex = index as logic[9]
fetch.programData = word as logic[32]
}
state {
fetch.programWrite = 0b0
}
}
/**
* Runs to a fault stop with a generous bound independent of engine cycle timing.
*/
fn RunToStop(cause: uint)
{
var start = cycles
core.run = 0b1
while (core.halted == 0b0 && cycles - start < 20000) {
state {
}
}
core.run = 0b0
assert core.halted == 0b1
assert core.faultCause as uint == cause
assert cycles - start < retireCount * 50 + 50
}
/**
* Initializes every data location that a vector can read before execution.
*/
fn Prepare()
{
core.run = 0b0
Simulation.Wait(40)
assert core.idle == 0b1
var ticket = ~core.restartAck
core.restartRequest = ticket
var elapsed: uint = 0
while (core.restartAck != ticket && elapsed < 100) {
state {
elapsed++
}
}
assert core.restartAck == ticket
clearObservation = true
Simulation.Wait(4)
clearObservation = false
for (var index: uint = 0; index < 256; index++) {
state {
loadStore.programWrite = 0b1
loadStore.programIndex = index as logic[8]
loadStore.programData = 0
}
}
state {
loadStore.programWrite = 0b0
}
assert core.idle == 0b1
}
/**
* Compares one ordered committed event with independently computed constants.
*/
fn CheckRetirement(index: uint, pc: uint, word: uint, rd: uint, value: uint)
{
assert tracePc[index] == pc
assert traceWord[index] == word
assert traceRd[index] == rd
assert traceValue[index] == value
}
/**
* Checks all CSR forms, encoded-zero suppression, aliases, WARL and counter commits.
*/
@Test
fn CsrRetirement()
{
Prepare()
for (var index: uint = 0; index < (Rv32CsrRetirement.WORDS.Length as uint); index++) {
Load(index, Rv32CsrRetirement.WORDS[index])
}
RunToStop(3)
assert retireCount == Rv32CsrRetirement.VALUES.Length as uint
for (var index: uint = 0; index < (Rv32CsrRetirement.VALUES.Length as uint); index++) {
CheckRetirement(index, index * 4, Rv32CsrRetirement.WORDS[index],
Rv32CsrRetirement.DESTINATIONS[index], Rv32CsrRetirement.VALUES[index])
}
}
/**
* Rejects UnknownCsr with no CSR access commit, retirement or destination write.
*/
@Test
fn UnknownCsr()
{
Prepare()
Load(0, 0x777020f3)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0x777020f3
}
/**
* Rejects ReadOnlyWrite with no CSR access commit, retirement or destination write.
*/
@Test
fn ReadOnlyWrite()
{
Prepare()
Load(0, 0xf11110f3)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0xf11110f3
}
/**
* Rejects ZeroRegisterValueStillWrites with no CSR access commit, retirement or destination write.
*/
@Test
fn ZeroRegisterValueStillWrites()
{
Prepare()
Load(0, 0xf11120f3)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0xf11120f3
}
/**
* Rejects UnknownWithoutRead with no CSR access commit, retirement or destination write.
*/
@Test
fn UnknownWithoutRead()
{
Prepare()
Load(0, 0x77701073)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0x77701073
}
/**
* Rejects MachineReturnUnavailable with no CSR access commit, retirement or destination write.
*/
@Test
fn MachineReturnUnavailable()
{
Prepare()
Load(0, 0x30200073)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0x30200073
}
/**
* Rejects UserCounterUnavailable with no CSR access commit, retirement or destination write.
*/
@Test
fn UserCounterUnavailable()
{
Prepare()
Load(0, 0xc00020f3)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0xc00020f3
}
/**
* Rejects SupervisorUnavailable with no CSR access commit, retirement or destination write.
*/
@Test
fn SupervisorUnavailable()
{
Prepare()
Load(0, 0x100020f3)
RunToStop(2)
assert retireCount == 0 && csrCommits == 0 && core.pc == 0
assert core.faultValue == 0x100020f3
}
/**
* Toggles one instruction step and bounds the completion acknowledgement.
*/
fn Step()
{
core.stepRequest = ~core.stepRequest
var elapsed: uint = 0
while (core.stepAck != core.stepRequest && elapsed < 200) {
state {
elapsed++
}
}
assert core.stepAck == core.stepRequest
}
/**
* A held step writes once; pause retains CSR state; restart clears it.
*/
@Test
fn CsrStepPauseRestart()
{
Prepare()
Load(0, 0x3403d0f3)
Load(1, 0x34002173)
Load(2, 0x00100073)
Step()
assert retireCount == 1 && csrCommits == 1 && traceValue[0] == 0
Simulation.Wait(40)
assert retireCount == 1 && csrCommits == 1 && core.pc == 4
Step()
assert retireCount == 2 && traceValue[1] == 7
Step()
assert core.halted == 0b1 && core.faultCause == 3
var ticket = ~core.restartAck
core.restartRequest = ticket
Simulation.Wait(50)
assert core.restartAck == ticket && core.pc == 0 && core.halted == 0b0
Load(0, 0x340021f3)
Load(1, 0xb0202273)
Step()
assert retireCount == 3 && traceValue[2] == 0
Step()
assert retireCount == 4 && traceValue[3] == 1
}
}