blob: 2080b7a7a81740ef8bf2cb8d18aae5b03e4f5f14 [file] [log] [blame]
//
// Template for VMM-compliant full-duplex physical-level transactor
//
// <XACT> Name of transactor
// <IF> Name of physical interface
// <master> Name of modport in physical interface
// <TR> Name of input/output transaction descriptor class
//
`ifndef XACT__SV
`define XACT__SV
`include "vmm.sv"
`include "IF.sv"
`include "TR.sv"
typedef class XACT;
class XACT_callbacks extends vmm_xactor_callbacks;
// ToDo: Add additional relevant callbacks
// ToDo: Use task if callbacks can be blocking
// Called before a transaction is executed
virtual task pre_ex_trans(XACT xactor,
TR tr,
ref bit drop);
endtask: pre_ex_trans
// Called after a transaction has been executed
virtual task post_ex_trans(XACT xactor,
TR tr);
endtask: post_ex_trans
// Called at start of observed transaction
virtual function void pre_obs_trans(XACT xactor,
TR tr);
endfunction: pre_obs_trans
// Called before acknowledging a transaction
virtual function void pre_ack(XACT xactor,
TR tr);
endfunction: pre_ack
// Called at end of observed transaction
virtual function void post_obs_trans(XACT xactor,
TR tr);
endfunction: post_obs_trans
endclass: XACT_callbacks
class XACT_cfg;
// ToDo: Add transactor configuration class properties
rand int mode;
endclass:XACT_cfg
class XACT extends vmm_xactor;
int EXECUTING;
int OBSERVING;
protected XACT_cfg cfg;
local XACT_cfg reset_cfg;
protected TR rx_factory;
local TR reset_rx_factory;
TR_channel in_chan;
TR_channel out_chan;
virtual IF.master sigs;
extern function new(string inst,
int stream_id,
virtual IF.master sigs,
XACT_cfg cfg = null,
TR_channel in_chan = null,
TR_channel out_chan = null,
TR rx_factory = null);
extern virtual function void reconfigure(XACT_cfg cfg);
extern virtual function void reset_xactor(reset_e rst_typ = SOFT_RST);
extern protected virtual task main();
extern protected virtual task tx_driver();
extern protected virtual task rx_monitor();
endclass: XACT
function XACT::new(string inst,
int stream_id,
virtual IF.master sigs,
XACT_cfg cfg,
TR_channel in_chan,
TR_channel out_chan,
TR rx_factory);
super.new("XACT Transactor", inst, stream_id);
this.EXECUTING = this.notify.configure(-1, vmm_notify::ON_OFF);
this.OBSERVING = this.notify.configure(-1, vmm_notify::ON_OFF);
this.sigs = sigs;
if (cfg == null) cfg = new;
this.cfg = cfg;
this.reset_cfg = cfg;
if (in_chan == null) in_chan = new("XACT Input Channel", inst);
this.in_chan = in_chan;
if (out_chan == null) out_chan = new("XACT Output Channel", inst);
this.out_chan = out_chan;
if (rx_factory == null) rx_factory = new;
this.rx_factory = rx_factory;
this.reset_rx_factory = rx_factory;
endfunction: new
function void XACT::reconfigure(XACT_cfg cfg);
if (!this.notify.is_on(XACTOR_IDLE)) begin
`vmm_warning(this.log, "Transactor should be reconfigured only when IDLE");
end
this.cfg = cfg;
// ToDo: Notify any running threads of the new configuration
endfunction: reconfigure
function void XACT::reset_xactor(reset_e rst_typ);
super.reset_xactor(rst_typ);
// ToDo: Reset output/inout signals
this.sigs.mck1.sync_txd <= 0;
this.sigs.mck1.sync_dat <= 'z;
this.sigs.async_en <= 0;
this.in_chan.flush();
this.out_chan.flush();
// ToDo: Reset other state information
if (rst_typ != SOFT_RST) begin
// ToDo: Reset state if FIRM or above
end
if (rst_typ == PROTOCOL_RST) begin
// ToDo: Reset state if PROTOCOL
end
if (rst_typ == HARD_RST) begin
// ToDo: Reset state if HARD or above
this.cfg = this.reset_cfg;
this.rx_factory = this.reset_rx_factory;
end
endfunction: reset_xactor
task XACT::main();
super.main();
fork
tx_driver();
rx_monitor();
join
endtask: main
task XACT::tx_driver();
forever begin
TR tr;
bit drop;
// ToDo: Set output/inout signals to their idle state
this.sigs.mck1.sync_txd <= 0;
this.sigs.async_en <= 0;
this.wait_if_stopped_or_empty(this.in_chan);
this.in_chan.activate(tr);
drop = 0;
`vmm_callback(XACT_callbacks,
pre_ex_trans(this, tr, drop));
if (drop) begin
void'(this.in_chan.remove());
continue;
end
void'(this.in_chan.start());
this.notify.indicate(this.EXECUTING, tr);
`vmm_trace(this.log, "Starting Tx transaction...");
`vmm_debug(this.log, tr.psdisplay(" "));
case (tr.kind)
TR::READ: begin
// ToDo: Implement READ transaction
end
TR::WRITE: begin
// ToDo: Implement READ transaction
end
endcase
this.notify.reset(this.EXECUTING);
void'(this.in_chan.complete());
`vmm_trace(this.log, "Completed Tx transaction...");
`vmm_debug(this.log, tr.psdisplay(" "));
`vmm_callback(XACT_callbacks,
post_ex_trans(this, tr));
void'(this.in_chan.remove());
end
endtask: tx_driver
task XACT::rx_monitor();
forever begin
TR tr;
// ToDo: Set output signals to their idle state
this.sigs.mck1.sync_dat <= 'z;
// ToDo: Wait for start of transaction
$cast(tr, this.rx_factory.copy());
`vmm_callback(XACT_callbacks,
pre_obs_trans(this, tr));
tr.notify.indicate(vmm_data::STARTED);
this.notify.indicate(this.OBSERVING, tr);
`vmm_trace(this.log, "Starting Rx transaction...");
// ToDo: Observe first half of transaction
tr.status = TR::IS_OK;
`vmm_callback(XACT_callbacks,
pre_obs_trans(this, tr));
// ToDo: React to observed transaction with ACK/NAK
`vmm_trace(this.log, "Completed Rx transaction...");
`vmm_debug(this.log, tr.psdisplay(" "));
this.notify.reset(this.OBSERVING);
tr.notify.indicate(vmm_data::ENDED);
`vmm_callback(XACT_callbacks,
post_obs_trans(this, tr));
this.out_chan.sneak(tr);
end
endtask: rx_monitor
`endif