• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC Design
  3. VerilogA for staircase voltage generator issue

Stats

  • Locked Locked
  • Replies 4
  • Subscribers 127
  • Views 9078
  • Members are here 0
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

VerilogA for staircase voltage generator issue

NewScreenName
NewScreenName over 2 years ago

Hi all,

I am trying to generate a staircase signal for a testbench. One way would be using vpwl but if I have, say 100 or more steps, becomes unpractical.

Or I could use a vpwlf loading an external file, but in this case, after briefly searching around, it seems to me it does not support parametrized times and values (feature which I need here). In case parameters are allowed there instead, could you please point out to a reference explaining the correct syntay to be used?

Therefore the last option I envision would be writing a verilogA model to generate this, but it is not working, I think it is most probably a syntax issue? Below is the code, and the issue is that vout only gets updated for i=0, i.e. the first step, afterwards it is as if the cross( $abstime - t_start+i*stair_step_time, +1) statement did not get triggered anymore.

Which would be the right syntax?

Thank you and best regards

CODE:

`include "constants.vams"
`include "disciplines.vams"

module staircase_voltage_generator(A, B);

inout A, B;
electrical A, B;

parameter real t_start = 100n;
parameter real stair_step_time = 10u;
parameter real stair_step_amplitude = 6m;
parameter real vo_begin = -60m;
parameter integer steps_number = 100;

parameter real td = 10p from [0:inf);
parameter real tr = 10p from (0:inf);
parameter real tf = 10p from (0:inf);

real vout;
genvar i;

analog begin

  @ ( initial_step ) begin
   vout=vo_begin;
  end

  for (i=0; i<steps_number; i=i+1) begin
   @ cross( $abstime - t_start+i*stair_step_time, +1) begin
      vout=vout+stair_step_amplitude;
   end
  end

  V(A,B)<+transition(vout, td, tr, tf);

end

endmodule

  • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago

    This post shows a way to do this with a clocked source to trigger the transitions:  staircase function 

    You could do it with @timer instead of a clocked source - it certainly would not be done with a for loop the way you've done it - using @cross to detect time crossings is not a good idea and you are creating a lot of cross events for every iteration of the loop (I know it's a genvar). It would make more sense to do something like (I only did very limited testing):

    //
    `include "constants.vams"
    `include "disciplines.vams"
    
    module staircase_voltage_generator(A, B);
    
    inout A, B;
    electrical A, B;
    
    parameter real t_start = 100n;
    parameter real stair_step_time = 10u;
    parameter real stair_step_amplitude = 6m;
    parameter real vo_begin = -60m;
    parameter integer steps_number = 100;
    
    parameter real td = 10p from [0:inf);
    parameter real tr = 10p from (0:inf);
    parameter real tf = 10p from (0:inf);
    
    real vout;
    integer i;
    
    analog begin
    
      @ ( initial_step ) begin
       vout=vo_begin;
       i=0;
      end
    
      @(timer(t_start,stair_step_time)) begin
        if(i<steps_number) begin
          i++;
          vout=vout+stair_step_amplitude;
        end
      end
    
      V(A,B)<+transition(vout, td, tr, tf);
    
    end
    
    endmodule
    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
  • NewScreenName
    NewScreenName over 2 years ago in reply to Andrew Beckett

    Thank you for your reply, the code seems to be working fine.

    Just for sake of understanding, what is wrong with the for loop?

    There are n_steps loop iterations, each containing one cross function getting triggered once, timer function will get triggered n_steps times as well, is this correct? Where does the overhead lie?

    And moreover, a part from the efficiency point of view, why is the for loop just not working? (or actually working only for the first step) Is it not correct to assume that @ cross( $abstime - t_start+i*stair_step_time, +1) would get triggered as tran sim time passes? If not, why? cross function should be able to evaluate any expression, is $abstime not an expression maybe?

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • ShawnLogan
    ShawnLogan over 2 years ago in reply to NewScreenName

    Dear NewScreenName.

    NewScreenName said:
    Just for sake of understanding, what is wrong with the for loop?

    I am not a veriloga expert, but when I looked at your source code, it seems that your for loop will run a single time after your begin statement. There is nothing limiting the advancement of your for loop counting integer i at a given time. Hence, it will simply complete the for loop after the begin statement and not trigger at each staircase transition time as you desire.

    In Andrew's code, the timer serves to trigger a stairstep event at each desired time.

    Shawn

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to ShawnLogan

    The issue is not the loop (which is a genvar loop, so is expanded at "compilation time", so is equivalent to unrolling the loop and having lots of @ cross statements, one for each expanded time. The issue is that the argument is not an "analog signal" - and so that means (I believe) that the timestep control in the simulator can't iterate to resolve the crossing point accurately because it's not a function for which the derivative can be taken. The Verilog-AMS Language Reference Manual (LRM) is a little vague on this, but it does say:

    The cross() function is used for generating a monitored analog event to detect threshold crossings in analog signals when the expression crosses zero (0) in the specified direction. In addition, cross() controls the timestep to accurately resolve the crossing.

    Possibly the compiler should object to this expression in some way, but in practice it just doesn't work and it would be an inefficient way of scheduling an event at a time - normally the @ cross event is trying to place a timepoint at the crossing point and so has to take time points near the crossing point too to improve the accuracy of the crossing, which would be unnecessary for something that is just a timed event - which is why the @ timer is a more appropriate way of doing this.

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information