init
This commit is contained in:
115
code/vezba10/verif/Agent/calc_driver.sv
Normal file
115
code/vezba10/verif/Agent/calc_driver.sv
Normal file
@@ -0,0 +1,115 @@
|
||||
`ifndef CALC_DRIVER_SV
|
||||
`define CALC_DRIVER_SV
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Calc1 driver.
|
||||
//
|
||||
// Protocol (Vezba 5):
|
||||
// * command + operand1 are driven in the same cycle,
|
||||
// * operand2 is driven in the next cycle (command line back to 0),
|
||||
// * a response appears on out_respX a few (>=3) cycles later.
|
||||
//
|
||||
// Only one request may be outstanding per port, so after issuing a request the
|
||||
// driver waits for that port's response before completing the item. This keeps
|
||||
// the very simple "bidirectional, non-pipelined" use model from Vezba 6.
|
||||
//-----------------------------------------------------------------------------
|
||||
class calc_driver extends uvm_driver#(calc_seq_item);
|
||||
|
||||
`uvm_component_utils(calc_driver)
|
||||
|
||||
virtual interface calc_if vif;
|
||||
|
||||
function new(string name = "calc_driver", uvm_component parent = null);
|
||||
super.new(name,parent);
|
||||
endfunction
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
if (!uvm_config_db#(virtual calc_if)::get(this, "", "calc_if", vif))
|
||||
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
|
||||
endfunction : connect_phase
|
||||
|
||||
task main_phase(uvm_phase phase);
|
||||
// start from a known idle state and wait until reset is released
|
||||
reset_inputs();
|
||||
wait_reset_done();
|
||||
|
||||
forever begin
|
||||
seq_item_port.get_next_item(req);
|
||||
`uvm_info(get_type_name(),
|
||||
$sformatf("Driving: %s", req.convert2string()), UVM_HIGH)
|
||||
drive_item(req);
|
||||
seq_item_port.item_done();
|
||||
end
|
||||
endtask : main_phase
|
||||
|
||||
// Drive a single transaction following the two-cycle request protocol and
|
||||
// wait for the corresponding response on the same port.
|
||||
task drive_item(calc_seq_item it);
|
||||
int unsigned wait_cnt;
|
||||
|
||||
// optional idle gap before the request
|
||||
repeat (it.delay) @(posedge vif.clk);
|
||||
|
||||
// cycle 1: command + operand1
|
||||
drive_req(it.port, it.cmd, it.op1);
|
||||
@(posedge vif.clk);
|
||||
|
||||
// cycle 2: operand2, command de-asserted
|
||||
drive_req(it.port, CMD_NOP, it.op2);
|
||||
@(posedge vif.clk);
|
||||
|
||||
// idle the port again while the pipeline produces the result
|
||||
drive_req(it.port, CMD_NOP, '0);
|
||||
|
||||
// wait for this port's response (resp != 0), bounded so a non-responding
|
||||
// DUT cannot deadlock the test
|
||||
wait_cnt = 0;
|
||||
do begin
|
||||
@(posedge vif.clk);
|
||||
wait_cnt++;
|
||||
end while (get_resp(it.port) === RESP_NONE && wait_cnt < RSP_TIMEOUT);
|
||||
|
||||
if (get_resp(it.port) === RESP_NONE)
|
||||
`uvm_warning(get_type_name(),
|
||||
$sformatf("No response on port %0d within %0d cycles (cmd=%s) - the scoreboard will flag this",
|
||||
it.port+1, RSP_TIMEOUT, it.cmd2string()))
|
||||
endtask : drive_item
|
||||
|
||||
// Drive command/data onto the selected port, leaving the others untouched.
|
||||
task drive_req(bit [1:0] port, bit [CMD_WIDTH-1:0] cmd, bit [DATA_WIDTH-1:0] data);
|
||||
case (port)
|
||||
2'd0 : begin vif.req1_cmd_in <= cmd; vif.req1_data_in <= data; end
|
||||
2'd1 : begin vif.req2_cmd_in <= cmd; vif.req2_data_in <= data; end
|
||||
2'd2 : begin vif.req3_cmd_in <= cmd; vif.req3_data_in <= data; end
|
||||
2'd3 : begin vif.req4_cmd_in <= cmd; vif.req4_data_in <= data; end
|
||||
endcase
|
||||
endtask : drive_req
|
||||
|
||||
// Combinational read of a port's response line.
|
||||
function bit [RESP_WIDTH-1:0] get_resp(bit [1:0] port);
|
||||
case (port)
|
||||
2'd0 : return vif.out_resp1;
|
||||
2'd1 : return vif.out_resp2;
|
||||
2'd2 : return vif.out_resp3;
|
||||
2'd3 : return vif.out_resp4;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// Drive all request lines to their idle (zero) state.
|
||||
task reset_inputs();
|
||||
vif.req1_cmd_in <= '0; vif.req1_data_in <= '0;
|
||||
vif.req2_cmd_in <= '0; vif.req2_data_in <= '0;
|
||||
vif.req3_cmd_in <= '0; vif.req3_data_in <= '0;
|
||||
vif.req4_cmd_in <= '0; vif.req4_data_in <= '0;
|
||||
endtask : reset_inputs
|
||||
|
||||
task wait_reset_done();
|
||||
// reset is active-high (all ones); wait until it is fully released
|
||||
while (vif.rst !== '0) @(posedge vif.clk);
|
||||
`uvm_info(get_type_name(), "Reset released - starting to drive", UVM_LOW)
|
||||
endtask : wait_reset_done
|
||||
|
||||
endclass : calc_driver
|
||||
|
||||
`endif
|
||||
Reference in New Issue
Block a user