Busperf plugins¶
You can extend Busperf’s functionality through Python plugins.
A custom analyzer can be specified in the YAML file under the custom_analyzer and custom_handshake keys.
To prevent name collisions between native and Python analyzers, the names of the Python analyzers should start with “Python”.
Some examples are available in plugins/python.
Analyzer requirements¶
A plugin should define a create() function that returns an analyzer object.
There are 2 types of Python plugins, custom_handshake and custom_analyzer, with different uses.
Custom handshake¶
Custom handshakes are used to calculate statistics for single channel buses. The analyzer object should define the following methods:
get_signals(self) -> list[str]Return value - an array of string names of signals that are required by the analyzer.
interpret_cycle(self, signals) -> CycleTypesignals - array of signal values (casted to string) during clock cycle
Return value - interpreted state of the bus during that clock cycle. See CycleType
Custom analyzer¶
Custom analyzers are used to calculate statistics for multi channel buses. Their analyzer object must define the following methods:
get_yaml_signals(self) -> list[tuple[SignalType, list[str]]]Return value - returns types and paths to each signal defined in yaml that is required by the analyzer. See SignalType
analyze(self, clk, rst, ...) -> list[Transaction]Parameters - the method takes as arguments signals requested in
get_yaml_signals, clk and rst signals are always included and passed as first 2 arguments, all remaining are passed in the same order as inget_yaml_signals. Each signal is an array of tuples(time: int, value: str).Return value - the method should return a list of transactions that were present on a bus. See Transaction
Interface types¶
All types that are used on the rust-python interface are made available in a busperf module that is created at
runtime and made accessible for the plugins. It defines the following types based on Rust structs:
CycleType¶
This enum represents the state of a single channel.
class CycleType:
Busy = <CycleType.Busy> # performing transaction
Free = <CycleType.Free> # bus is not used
NoTransaction = <CycleType.NoTransaction> # transaction is not performed
Backpressure = <CycleType.Backpressure> # backpressure
NoData = <CycleType.NoData> # receiver ready but no data is available to transfer
Reset = <CycleType.Reset> # reset signal active, bus in reset
Unknown = <CycleType.Unknown> # invalid/unknown state
SignalType¶
This enum represents what data about signal(s) the analyzer expects.
class SignalType:
Signal = <SignalType.Signal> # passes every signal change's time and value to the analyzer
RisingSignal = <SignalType.RisingSignal> # passes times of every rising edge of the signal (useful for e.g. clk)
ReadyValid = <SignalType.ReadyValid> # passes all time a transaction is performed on a ready/valid channel
Transaction¶
This type represents one transaction of the analyzed multichannel bus.
class Transaction:
def __init__(
self,
start: int,
first_data: int,
last_data: int,
resp_time: int,
resp: str,
next_start: int
):
self.start = start # time of command issue
self.first_data = first_data # time of first data being transferred
self.last_data = last_data # time of last data transfer
self.resp_time = resp_time # time of response
self.resp = resp # value of the response
self.next_start = next_start # start time of next transaction