Livt packages
Livt.Bus
Version 2.0.1
Configurable Avalon, AXI4-Lite, and Wishbone memory-mapped masters, interfaces, bridges, and test components.
Published files (67)
src/wishbone/testing/WishboneTestSlave.lvt
namespace Livt.Bus.Wishbone.Testing
using Livt.Bus.Wishbone
/**
* Configurable Wishbone Classic mirrored 16-word register model for master tests.
*/
component WishboneTestSlave<AddressWidth: int = 32, DataWidth: int = 32>
{
const BYTE_COUNT: int = DataWidth / 8
static assert DataWidth == 32 || DataWidth == 64 || DataWidth == 128, "Invalid DataWidth"
public observedAddress: out Logic[AddressWidth]
public acceptedWrites: out uint
bus: IWishboneMaster<Logic[AddressWidth], Logic[DataWidth], Logic[BYTE_COUNT]>
registers: Logic[16, DataWidth]
ackDelay: uint
new(bus: flip IWishboneMaster<Logic[AddressWidth], Logic[DataWidth], Logic[BYTE_COUNT]>)
{
this.bus = bus
this.bus.datout = 0x00000000
this.bus.ack = 0b0
this.ackDelay = 0
}
/**
* Sets the number of clock ticks to wait before asserting ack.
*/
public fn ConfigureAckDelay(ackDelay: uint)
{
state Apply {
this.ackDelay = ackDelay
}
}
/**
* Clears all sixteen native-width words in the target model.
*/
public fn Clear()
{
var index: int = 0
while (index < 16) {
registers[index] = 0
index = index + 1
}
}
process Run()
{
var elapsed: uint = 0
var registerIndex: int = 0
var nextValue: Logic[DataWidth] = 0
state Idle {
this.bus.ack = 0b0
elapsed = 0
if (this.bus.cyc == 0b1 && this.bus.stb == 0b1) {
goto WaitForAck
} else {
goto Idle
}
}
state WaitForAck {
if (this.bus.cyc == 0b0 || this.bus.stb == 0b0) {
this.bus.ack = 0b0
goto Idle
} elif (elapsed >= ackDelay) {
this.observedAddress = this.bus.adr
registerIndex = (((this.bus.adr & ((16 * BYTE_COUNT - 1) as Logic[AddressWidth])) as uint) / (BYTE_COUNT as uint)) as int
if (this.bus.we == 0b1 && registerIndex >= 0 && registerIndex < 16) {
nextValue = registers[registerIndex]
nextValue = this.MergeBytes(nextValue, this.bus.datin, this.bus.sel)
this.acceptedWrites = this.acceptedWrites + 1
registers[registerIndex] = nextValue
}
if (this.bus.we == 0b0) {
if (registerIndex >= 0 && registerIndex < 16) {
this.bus.datout = registers[registerIndex] as Logic[DataWidth]
} else {
this.bus.datout = 0x00000000
}
}
this.bus.ack = 0b1
goto Acknowledge
} else {
elapsed = elapsed + 1
goto WaitForAck
}
}
state Acknowledge {
// Classic cycles complete once; do not accept the held request again.
if (this.bus.cyc == 0b0 || this.bus.stb == 0b0) {
this.bus.ack = 0b0
goto Idle
} else {
goto Acknowledge
}
}
}
private inline fn MergeBytes[](previous: Logic[DataWidth], data: Logic[DataWidth], enables: Logic[BYTE_COUNT]) Logic[DataWidth]
{
var result = previous
for (var lane = 0; lane < 16; lane++) {
if (lane < BYTE_COUNT) {
if (enables[lane] == 0b1) {
var mask = (0xFF as Logic[DataWidth]) << (lane * 8)
result = (result & ~mask) | (data & mask)
}
}
}
return result
}
}