peter
peter

Reputation: 117

A test bench for a phase counter using uvm

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

Answers (1)

toolic
toolic

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

Related Questions