hello everyone!
i’ve faced a very strange behaviour of my cb, here goes:
interface:
interface adc_if #(
parameter DATA_WIDTH = 14, //ширина слова данных
parameter CHANNEL_AMOUNT = 4 //количество каналов АЦП
)
(
input wire rst
);
// ------------------------------------------------------------------------
// port Declaration:
// ------------------------------------------------------------------------
logic [DATA_WIDTH-1:0] data [CHANNEL_AMOUNT];
logic ovfl_spo [CHANNEL_AMOUNT];
logic cs [CHANNEL_AMOUNT];
logic oen_sclk;
logic spi_calr;
logic clk;
// synthesis translate_off
// Use this clocking block for TB code that stimulates the bus
clocking drv_cb @(posedge clk);
output negedge data;
endclocking
clocking drv_pos_cb @(posedge clk);
output #4 data;
endclocking
clocking drv_neg_cb @(negedge clk);
output #4 data;
endclocking
// Use this clocking block for passive monitoring TB code
clocking mtr_cb @(posedge clk);
input #1step data;
endclocking
clocking mtr_pos_cb @(posedge clk);
input #1step data;
endclocking
clocking mtr_neg_cb @(negedge clk);
input #1step data;
endclocking
// One modport for each testbench role
modport drv_pos_neg_mp(
clocking drv_pos_cb,
clocking drv_neg_cb,
input rst
);
modport drv_mp(
clocking drv_cb,
clocking drv_pos_cb,
clocking drv_neg_cb,
input rst
);
modport mtr_mp(
clocking mtr_cb,
clocking mtr_pos_cb,
clocking mtr_neg_cb,
input rst
);
// synthesis translate_on
endinterface : adc_if
transaction:
class adc_transaction #(
parameter DATA_WIDTH = 14,
parameter CHANNEL_AMOUNT = 4
) extends uvm_sequence_item;
rand bit [DATA_WIDTH-1:0] data [CHANNEL_AMOUNT-1:0];
.....
driver:
class adc_pos_neg_driver #(
parameter DATA_WIDTH = 14,//ширина слова данных
parameter CHANNEL_AMOUNT = 4//количество каналов АЦП
) extends adc_driver #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT)
);
`uvm_component_param_utils( adc_pos_neg_driver #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT)
)
)
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
endfunction: build_phase
extern virtual task main_phase( uvm_phase phase );
endclass: adc_pos_neg_driver
// +HDR ------------------------------------------------------------------------
// NAME : main_phase
// TYPE : task
// -----------------------------------------------------------------------------
// PURPOSE : main task
// -----------------------------------------------------------------------------
// Other :
// -HDR ------------------------------------------------------------------------
task adc_pos_neg_driver::main_phase( uvm_phase phase );
adc_transaction #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT)
) adc_tx;
static bit positive_edge_transfer;
forever
begin
if (adc_bus.rst)//ресет
begin
//по ресету все сигналы уходят в 0
foreach (adc_bus.drv_pos_cb.data[i])
begin
adc_bus.drv_pos_cb.data[i] <= '0;
end
//ждем падения ресета
wait_for_end_of_reset();
end
else
begin
seq_item_port.get_next_item( adc_tx );
if (positive_edge_transfer)//передаем по фронту тактовой частоты
begin
@ (adc_bus.drv_pos_cb);
foreach (adc_bus.drv_pos_cb.data[i])
begin
adc_bus.drv_pos_cb.data[i] <= adc_tx.data[i];
end
end
else
begin
@ (adc_bus.drv_neg_cb);
foreach (adc_bus.drv_neg_cb.data[i])
begin
//adc_bus.drv_neg_cb.data[0] <= '1;
adc_bus.drv_neg_cb.data[i] <= adc_tx.data[i];
end
end
positive_edge_transfer = ~positive_edge_transfer;
seq_item_port.item_done();
end
end
endtask: main_phase
and sequence:
class adc_rand_sequence #(
parameter DATA_WIDTH = 14,//ширина слова данных
parameter CHANNEL_AMOUNT = 4,//количество каналов АЦП
parameter Y_SIZE = 1024//размер по вертикали
) extends uvm_sequence #( adc_transaction #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT)
)
);
rand bit [DATA_WIDTH-1:0] max_signal;//максимальное значение сигнала
rand bit [DATA_WIDTH-1:0] min_signal;//минимальное значение сигнала
rand int x_coord;
//ограничение на пределы изменения сигнала (нижняя граница небольше верхней)
constraint range_con {
max_signal >= min_signal;
};
function new( string name = "" );
super.new( name );
endfunction: new
extern virtual task body();
`uvm_object_param_utils( adc_rand_sequence #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT),
.Y_SIZE(Y_SIZE)
)
)
endclass: adc_rand_sequence
// +HDR ------------------------------------------------------------------------
// NAME : body
// TYPE : task
// -----------------------------------------------------------------------------
// PURPOSE : creates transactions and sends them to sequencer
// -----------------------------------------------------------------------------
// Other :
// -HDR ------------------------------------------------------------------------
task adc_rand_sequence::body();
adc_transaction #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT)
) adc_tx;
bit [DATA_WIDTH-1:0] data_saved[1:0] [CHANNEL_AMOUNT-1:0];
bit [DATA_WIDTH-1:0] data_without_noise [CHANNEL_AMOUNT-1:0];
for (int y = 0; y < Y_SIZE*4*2; y++)
begin
//передаем сигнал
adc_tx = adc_transaction #(
.DATA_WIDTH(DATA_WIDTH),
.CHANNEL_AMOUNT(CHANNEL_AMOUNT)
)::type_id::create( .name( "adc_tx" ));
start_item( adc_tx );
foreach (data_without_noise[i])
begin
data_without_noise[i] = (DATA_WIDTH)'(data_saved[y%2][i] + 1);
end
assert( adc_tx.randomize() with {
foreach (data[i])
if ((y%8)/2 == 0) data[i] inside {[min_signal:max_signal]};
else data[i] == data_without_noise[i];
}
);
if ((y%8)/2 == 0)
begin
foreach ( adc_tx.data[i])
begin
data_saved[y%2][i] = adc_tx.data[i];
end
end
finish_item( adc_tx );
end
endtask
as you can see, i want driver to transmit data on both clock edges, and i want first two out of eight data transfers to be random, and next six to be equal first (or second, depends on clock edge) plus one. i use two clocking blocks, one “posedge clk”, and one “negedge clk”.
Problem is, that my diver doesn’t update data, if it is random data plus one. E.g., my first random value is 8 (transmitted on negedge), second is 5(trasmitted on posedge). I expect next six to be 9, 6, 9, 6, 9, 6. but i get 9, 6, 6, 6, 6, 6. When i make data on every clock edge completely random,this bug disappears. What’s the problem with my code? I’ve looked through transactions my driver gets, and they are all right (8, 5, 9, 6, 9, 6, 9, 6).
P.S. compiles gives a warning for driver “usage of clocking block is forbidden for this or another assignment”, as i can undersdand it’ s because my signal is an unpacked array, but still my test runs. maybe my problem is connected with this?
P.P.S. Thank you for your reply!