Reputation: 117
I am trying to create a uvm type test bench for a phase accumulator which is to be used in a DDS chain. Having this may be an overkill for a simple phase accumulator, but I am new to uvm/SystemVerilog so want to learn how to use the concepts. I have several questions.
My DUT:
module phase_acc #(
parameter PHASE_ACC_WIDTH = 16,
parameter TUNNING_WORD_WIDTH = 8
) (
input wire clk,
input wire reset,
input wire load,
input wire [TUNNING_WORD_WIDTH-1 : 0] tuning_word,
output reg [PHASE_ACC_WIDTH-1 : 0] phase,
output wire cycle_end,
output wire [1:0] phase_quadrant
);
assign phase_quadrant = phase[PHASE_ACC_WIDTH-1:PHASE_ACC_WIDTH-2];
assign cycle_end = (phase + tuning_word) > {PHASE_ACC_WIDTH{1'b1}};
always @(clk) begin
if (reset == 1) begin
phase <= 0;
end else begin
phase <= phase + tuning_word;
end
end
endmodule
Please note that this is not complete and planning to fill it after writing tests.
basic functionality is that the phase_acc counts up by tuning_word at a time. Just before it wraps around, it needs to assert cycle_end. Forget about phase_quadrant for now.
A new tuning_word can be loaded by asserting load.
I have created two classes to monitor signals. One for input stimulus (tuning_word and load) which gets triggered when ever load is one during a clock transition. The other is for phase_acc outputs which contain phase, cycle_end. Since these change at each clock transition, a new object of this type need to be created at each clock edge. Monitor uses two analysis ports to send stimulus packets and output packets to scoreboard.
My first question is, does this design make sense? Most uvm examples I saw have a behavior where after a stimulus is created, the DUT gives a single output which is then verified. (Say a RAM for example). In my case however, the DUT is free running.
If above design is correct, I have my second question.
My code for the monitor is:
class monitor extends uvm_monitor;
`uvm_component_utils(monitor)
function new(string name = "monitor", uvm_component parent = null);
super.new(name, parent);
endfunction
uvm_analysis_port #(acc_stimulus) mon_stimulus_analysis_port;
uvm_analysis_port #(acc_output) mon_output_analysis_port;
virtual reg_if vif;
semaphore sema4;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual acc_if)::get(this, "", "acc_if", vif))
`uvm_fatal("MON", "Could not get vif")
sema4 = new(1);
mon_stimulus_analysis_port = new("mon_stimulus_analysis_port", this);
mon_output_analysis_port = new("mon_output_analysis_port", this);
endfunction
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
fork
begin
@(vif.clk);
// output
acc_output out = new;
out.phase = vif.phase;
out.cycle_end = vif.cycle_end;
out.phase_quadrant = cif.phase_quadrant;
`uvm_info(get_type_name(), $sformatf("Monitor found ouout %s", out.convert2str()),
UVM_LOW)
mon_output_analysis_port.write(out);
end
begin
@(vif.clk);
// stimulus
if (vif.ld) begin
acc_stimulus stimulus = new;
stimulus.tunning_word = vif.tuning_word;
stimulus.load = vif.ld;
`uvm_info(get_type_name(), $sformatf("Monitor found stimulus %s",
stimulus.convert2str()), UVM_LOW)
mon_stimulus_analysis_port.write(stimulus);
end
end
join
end
endtask
endclass
But when trying to compile this, I get an error for the line which says:
acc_output out = new;
I am not sure what I am doing wrong there. If I were to do this inside an if
condition, for example:
begin
@(vif.clk);
if(vif.clk) begin
// output
acc_output out = new;
Then the error disappears.
I cannot understand what's wrong with the code.
Upvotes: 1
Views: 369
Reputation: 62163
You get the error because you declared the out
variable in the middle of a begin/end
block, after a statement:
begin
@(vif.clk); // This is a statement
// output
acc_output out = new; // This is a variable declaration
Inside a begin/end
block, you must declare all variables before statements.
The error went away when you declared the variable in the if
clause because it was the first line of code after the begin
keyword. The fact that this was inside an if
condition is irrelevant. The key was that you created a new block of code with the begin
keyword.
This should also work:
begin
// output
acc_output out = new;
@(vif.clk);
Upvotes: 1