The Designer's Guide Community Forum
https://designers-guide.org/forum/YaBB.pl
Design >> Mixed-Signal Design >> Verilog AMS sine generator
https://designers-guide.org/forum/YaBB.pl?num=1642147821

Message started by Praseetha Pn on Jan 14th, 2022, 12:10am

Title: Verilog AMS sine generator
Post by Praseetha Pn on Jan 14th, 2022, 12:10am

module rxbb_lp_wrapper


 (
   VDD1V8BB ,
   VSS1V8A ,
   VSS1V8BB ,
   VSS_SUB ,
   bbmux_lp_n_ai_amplitude ,
   bbmux_lp_n_ai_frequency ,
   bbmux_lp_n_ai_phase ,
   bbmux_lp_p_ai_amplitude ,
   bbmux_lp_p_ai_frequency ,
   bbmux_lp_p_ai_phase ,
   lp_n_ai_amplitude ,
   lp_n_ai_frequency ,
   lp_n_ai_phase ,
   lp_p_ai_amplitude ,
   lp_p_ai_frequency ,
   lp_p_ai_phase ,
   ibg_lp_untrim_50u_p_ai ,
   iptat_lp_untrim_50u_p_ai ,
   lp_en_i ,
   lp_noise_filter_en_i ,
   lp_test_sel_i ,
   trim_lp_fb_fc_i ,
   trim_lp_pass_fc_i ,
   vcm1_750m_ai ,
   vcm3_600m_ai ,
   lp1_n_amux_ao,
   lp1_p_amux_ao,
   lp2_n_amux_ao,
   lp2_p_amux_ao,
   lp_n_ao,
   lp_p_ao
   );
       
 input   VDD1V8BB;
 input   VSS1V8A;
 input   VSS1V8BB;
 input   VSS_SUB;
 input   bbmux_lp_n_ai_amplitude ;
 input   bbmux_lp_n_ai_frequency ;
 input   bbmux_lp_n_ai_phase ;
 input   bbmux_lp_p_ai_amplitude ;
 input   bbmux_lp_p_ai_frequency ;
 input   bbmux_lp_p_ai_phase ;
 input   lp_n_ai_amplitude ;
 input   lp_n_ai_frequency ;
 input   lp_n_ai_phase ;
 input   lp_p_ai_amplitude ;
 input   lp_p_ai_frequency ;
 input   lp_p_ai_phase ;
 input   [1:0] ibg_lp_untrim_50u_p_ai;
 input   [1:0] iptat_lp_untrim_50u_p_ai;
 input   lp_en_i;
 input   lp_noise_filter_en_i;
 input   lp_test_sel_i;
 input   [2:0] trim_lp_fb_fc_i;
 input   [3:0] trim_lp_pass_fc_i;
 input   vcm1_750m_ai;
 input   vcm3_600m_ai;
 output  lp1_n_amux_ao;
 output  lp1_p_amux_ao;
 output  lp2_n_amux_ao;
 output  lp2_p_amux_ao;
 output  lp_n_ao;
 output  lp_p_ao;
 
 wreal    VDD1V8BB;
 wreal    VSS1V8A;
 wreal    VSS1V8BB;
 wreal    VSS_SUB;
 wreal    bbmux_lp_n_ai_amplitude ;
 wreal    bbmux_lp_n_ai_frequency ;
 wreal    bbmux_lp_n_ai_phase ;
 wreal    bbmux_lp_p_ai_amplitude ;
 wreal    bbmux_lp_p_ai_frequency ;
 wreal    bbmux_lp_p_ai_phase ;
 wreal    lp_n_ai_amplitude ;
 wreal    lp_n_ai_frequency ;
 wreal    lp_n_ai_phase ;
 wreal    lp_p_ai_amplitude ;
 wreal    lp_p_ai_frequency ;
 wreal    lp_p_ai_phase ;
 wreal    ibg_lp_untrim_50u_p_ai[1:0];
 wreal    iptat_lp_untrim_50u_p_ai[1:0];
 wreal    lp_en_i;
 wreal    lp_noise_filter_en_i;
 wreal    lp_test_sel_i;
 wreal    trim_lp_fb_fc_i[2:0];
 wreal    trim_lp_pass_fc_i[3:0];
 wreal    vcm1_750m_ai;
 wreal    vcm3_600m_ai;
 wreal    lp1_n_amux_ao;
 wreal    lp1_p_amux_ao;
 wreal    lp2_n_amux_ao;
 wreal    lp2_p_amux_ao;
 wreal    lp_n_ao;
 wreal    lp_p_ao;
 electrical      bbmux_lp_n_ai;
 electrical      bbmux_lp_p_ai;
 electrical      lp_n_ai;
 electrical      lp_p_ai;
 
 real       offset = 2.5;
 
 
 
  v(bbmux_lp_n_ai)  <+ (offset + (bbmux_lp_n_ai_amplitude * sin(2*3.14159265358979323846*bbmux_lp_n_ai_frequency*$abstime)));
  v(bbmux_lp_p_ai)  <+ (offset + (bbmux_lp_p_ai_amplitude * sin(2*3.14159265358979323846*bbmux_lp_p_ai_frequency*$abstime)));
  v(lp_n_ai)        <+ (offset + (lp_n_ai_amplitude * sin(2*3.14159265358979323846*lp_n_ai_frequency*$abstime)));
  v(lp_p_ai)        <+ (offset + (lp_p_ai_amplitude * sin(2*3.14159265358979323846*lp_p_ai_frequency*$abstime)));
     $bound_step(0.05/lp_p_ai_frequency);
 
 

 
 
   // Instantiate the analog netlist
 rxbb_lp rxbb_lp_inst(
   .VDD1V8BB(VDD1V8BB) ,
   .VSS1V8A(VSS1V8A) ,
   .VSS1V8BB(VSS1V8BB) ,
   .VSS_SUB(VSS_SUB) ,
   .bbmux_lp_n_ai(bbmux_lp_n_ai) ,
   .bbmux_lp_p_ai(bbmux_lp_p_ai) ,
   .ibg_lp_untrim_50u_p_ai(ibg_lp_untrim_50u_p_ai) ,
   .iptat_lp_untrim_50u_p_ai(iptat_lp_untrim_50u_p_ai) ,
   .lp_en_i(lp_en_i) ,
   .lp_n_ai(lp_n_ai) ,
   .lp_noise_filter_en_i(lp_noise_filter_en_i) ,
   .lp_p_ai(lp_p_ai) ,
   .lp_test_sel_i(lp_test_sel_i) ,
   .trim_lp_fb_fc_i(trim_lp_fb_fc_i) ,
   .trim_lp_pass_fc_i(trim_lp_pass_fc_i) ,
   .vcm1_750m_ai(vcm1_750m_ai) ,
   .vcm3_600m_ai(vcm3_600m_ai) ,
   .lp1_n_amux_ao(lp1_n_amux_ao) ,
   .lp1_p_amux_ao(lp1_p_amux_ao) ,
   .lp2_n_amux_ao(lp2_n_amux_ao) ,
   .lp2_p_amux_ao(lp2_p_amux_ao) ,
   .lp_n_ao(lp_n_ao) ,
   .lp_p_ao(lp_p_ao)
 );
 

endmodule

I am trying to create a wrapper for my rxbb_lp module, the input of the wrapper is diffrent from the input of the module and I want to generate a signal(sine wave in my wrapper).
is this the correct way to do it?

Title: Re: Verilog AMS sine generator
Post by Ken Kundert on Jan 14th, 2022, 12:56am

Generally it is not very productive to dump 140 lines of code in a post and then ask a non-specific question like "is this the best way to do this.  It is hard to comment because I have no idea what you are trying to do, and yet I have lots of comments based on obvious problems in the code, but I am not sure what you are looking for. So I risk investing my time in a long response that of little value to you.

When posting, try to make you code fragments much shorter and your questions specific and bounded.

-Ken

Title: Re: Verilog AMS sine generator
Post by Praseetha Pn on Jan 14th, 2022, 1:03am

Hi Ken,
In short this is what I am trying to do.. I have created a wrapper around my  .vams netlist of an anlog circuit. I want to drive a signal as an input from the digital domain to my analog netlist hence I created a wrapper.
The input to the wrapper is a frequency ,phase and amplitude but I want to drive a sine wave as input to my analog netlist, hence I am creating this in my wrapper and trying to feed that as input to my vams netlist as it needs a signal as an input.

This is the part of the code which I need help with:
electrical      bbmux_lp_n_ai;
 electrical      bbmux_lp_p_ai;
 electrical      lp_n_ai;
 electrical      lp_p_ai;
 
 real       offset = 2.5;
 
 assign  bbmux_lp_n_ai = offset + (bbmux_lp_n_ai_amplitude * $cos(2*3.14159265358979323846*bbmux_lp_n_ai_frequency*$abstime));
 assign  bbmux_lp_p_ai = offset + (bbmux_lp_p_ai_amplitude * $cos(2*3.14159265358979323846*bbmux_lp_p_ai_frequency*$abstime));
 assign  lp_n_ai = offset + (lp_n_ai_amplitude * $cos(2*3.14159265358979323846*lp_n_ai_frequency*$abstime));
 assign  lp_p_ai = offset + (lp_p_ai_amplitude * $cos(2*3.14159265358979323846*lp_p_ai_frequency*$abstime));
 

 
 
   // Instantiate the analog netlist
 rxbb_lp rxbb_lp_inst(
   .bbmux_lp_n_ai(bbmux_lp_n_ai) ,
   .bbmux_lp_p_ai(bbmux_lp_p_ai) ,
   .lp_n_ai(lp_n_ai) ,
   .lp_p_ai(lp_p_ai)
);

Title: Re: Verilog AMS sine generator
Post by Ken Kundert on Jan 14th, 2022, 11:55am

Okay, that helps. But you did not ask a question.

The fact that you instantiated the DUT in a wrapper model seem to be of no consequence, correct?  You asking about how to generate a sine wave?

-Ken

Title: Re: Verilog AMS sine generator
Post by Praseetha Pn on Jan 14th, 2022, 12:20pm

Hi,
Yes as of now I do not see an issue with that.
1. The input to my wrapper is amplitude, frequency and phase
2. But my DUT is an Low pass filter  and I want to drive a signal as input (sine signal).
I want to know how to generate this sine wave in my wrapper ?
what should be the type of this variable be, as it is not an input/output to my wrapper, but only an input to my DUT.

I have tried to create it in my previous code snip but does not work.

Title: Re: Verilog AMS sine generator
Post by Ken Kundert on Jan 14th, 2022, 1:01pm

Let me focus on a simplified example.

First consider the sine generator as a simple component with no hierarchy.  Conceptually it is as simple as this:

Code:
   module sinegen(out, freq, ampl, phase, offset);
   output electrical out;
   input wreal freq, ampl, phase, offset;

   analog V(out) <+ ampl*sin(freq*$abstime + phase) + offset;
   endmodule


I'm don't really understand why you want to instantiate the filter in the generator, but conceptually here is how you would do it:

Code:
   module sinegen(out, freq, ampl, phase, offset);
   output electrical out;
   input wreal freq, ampl, phase, offset;
   electrical in;

   lpf(.o(out), .i(.in));

   analog V(in) <+ ampl*sin(freq*$abstime + phase) + offset;
   endmodule


Having said that, this generator has a number of issues.  First, it is filled with discontinuities.  They should be eliminated with transition functions.

Code:
   module sinegen(out, freq, ampl, phase, offset);
   output electrical out;
   input wreal freq, ampl, phase, offset;
   parameter tt=1u from [0:inf);

   analog V(out) <+ transition(ampl, 0, tt)*sin(transition(freq, 0, tt)*$abstime + transition(phase, 0, tt)) + transition(offset, 0, tt);
   endmodule


For efficiency sake you want to make the transition time tt as long as possible.

Second, when you are generating a high frequency output when there is no corresponding high frequency input, you need to inform the simulator so you don't get aliasing.  You do that by adding a bound on the time step.

Code:
   module sinegen(out, freq, ampl, phase, offset);
   output electrical out;
   input wreal freq, ampl, phase, offset;
   parameter tt=1u from [0:inf);

   analog begin
       V(out) <+ transition(ampl, 0, tt)*sin(transition(freq, 0, tt)*$abstime + transition(phase, 0, tt)) + transition(offset, 0, tt);
       $bound_step(10/freq);
   endmodule


I use ten points per period.  You probably need at least 4, but realize that the larger you make this number the slower you simulation will be.

Finally, you need to synchronize your kernels, meaning that you need to force the analog simulator to place time points at the events in the digital inputs.  Conceptually you can do that with:

Code:
   module sinegen(out, freq, ampl, phase, offset);
   output electrical out;
   input wreal freq, ampl, phase, offset;
   parameter tt=1u from [0:inf);

   analog begin
       @(freq or ampl or phase or offset)
           ;
       V(out) <+ transition(ampl, 0, tt)*sin(transition(freq, 0, tt)*$abstime + transition(phase, 0, tt)) + transition(offset, 0, tt);
       $bound_step(10/freq);
   endmodule


I say conceptually because even though that is legal Verilog-AMS code, Cadence has never supported arbitrary events in the analog block, so it must be rewritten as:

Code:
   module sinegen(out, freq, ampl, phase, offset);
   output electrical out;
   input wreal freq, ampl, phase, offset;
   parameter tt=1u from [0:inf);
   reg break = 0;

   always @(freq or ampl or phase or offset) break <= !break;

   analog begin
       @(posedge break or negedge break)
           ;
       V(out) <+ transition(ampl, 0, tt)*sin(transition(freq, 0, tt)*$abstime + transition(phase, 0, tt)) + transition(offset, 0, tt);
       $bound_step(10/freq);
   endmodule


I just typed this code in from memory, so it might not work as given. But hopefully you find it useful.


Title: Re: Verilog AMS sine generator
Post by Ken Kundert on Jan 14th, 2022, 1:09pm

Oh, one last thing.  The argument to a sine function is phase, and phase is the integral  of frequency.  You can only use sin(ωt) if ω is a constant.  If you are only interested in the output of the generator when ω is constant and you are okay with either very high or very low frequencies during changes, then you can continue to use sin(ωt).  This is generally preferred when creating testbench components.  Otherwise you should compute the phase using the idtmod operator.  You would need to do this when modeling a VCO.

Title: Re: Verilog AMS sine generator
Post by Praseetha Pn on Jan 15th, 2022, 1:17pm

Hi ken,
Thank you so much for the method and help.
I have used it in a similar way now, but modified as I need 4 signal sources.

Code:
module rxbb_lp_wrapper


 (

 
   bbmux_lp_n_ai_amplitude ,
   bbmux_lp_n_ai_frequency ,
   bbmux_lp_n_ai_phase ,
   bbmux_lp_p_ai_amplitude ,
   bbmux_lp_p_ai_frequency ,
   bbmux_lp_p_ai_phase ,
   lp_n_ai_amplitude ,
   lp_n_ai_frequency ,
   lp_n_ai_phase ,
   lp_p_ai_amplitude ,
   lp_p_ai_frequency ,
   lp_p_ai_phase ,
   lp1_n_amux_ao,
   lp1_p_amux_ao,
   lp2_n_amux_ao,
   lp2_p_amux_ao,
   lp_n_ao,
   lp_p_ao
   );
       
 input   bbmux_lp_n_ai_amplitude ;
 input   bbmux_lp_n_ai_frequency ;
 input   bbmux_lp_n_ai_phase ;
 input   bbmux_lp_p_ai_amplitude ;
 input   bbmux_lp_p_ai_frequency ;
 input   bbmux_lp_p_ai_phase ;
 input   lp_n_ai_amplitude ;
 input   lp_n_ai_frequency ;
 input   lp_n_ai_phase ;
 input   lp_p_ai_amplitude ;
 input   lp_p_ai_frequency ;
 input   lp_p_ai_phase ;

 output  lp1_n_amux_ao;
 output  lp1_p_amux_ao;
 output  lp2_n_amux_ao;
 output  lp2_p_amux_ao;
 output  lp_n_ao;
 output  lp_p_ao;
 

 wreal   bbmux_lp_n_ai_amplitude ;
 wreal   bbmux_lp_n_ai_frequency ;
 wreal   bbmux_lp_n_ai_phase ;
 wreal   bbmux_lp_p_ai_amplitude ;
 wreal   bbmux_lp_p_ai_frequency ;
 wreal   bbmux_lp_p_ai_phase ;
 wreal   lp_n_ai_amplitude ;
 wreal   lp_n_ai_frequency ;
 wreal   lp_n_ai_phase ;
 wreal   lp_p_ai_amplitude ;
 wreal   lp_p_ai_frequency ;
 wreal   lp_p_ai_phase ;
 
 electrical  lp1_n_amux_ao;
 electrical  lp1_p_amux_ao;
 electrical  lp2_n_amux_ao;
 electrical  lp2_p_amux_ao;
 electrical  lp_n_ao;
 electrical  lp_p_ao;
 
 electrical      bbmux_lp_n_ai;
 electrical      bbmux_lp_p_ai;
 electrical      lp_n_ai;
 electrical      lp_p_ai;
 

  parameter tt=1u from [0:inf);

   analog begin
   V(bbmux_lp_n_ai) <+ transition(bbmux_lp_n_ai_amplitude, 0, tt)*sin(transition(bbmux_lp_n_ai_frequency, 0, tt)*$abstime + transition(bbmux_lp_n_ai_phase, 0, tt)) + transition(0, 0, tt);
   $bound_step(10/bbmux_lp_n_ai_frequency);
   V(bbmux_lp_p_ai) <+ transition(bbmux_lp_p_ai_amplitude, 0, tt)*sin(transition(bbmux_lp_p_ai_frequency, 0, tt)*$abstime + transition(bbmux_lp_p_ai_phase, 0, tt)) + transition(0, 0, tt);
   $bound_step(10/bbmux_lp_p_ai_frequency);
   V(lp_n_ai) <+ transition(lp_n_ai_amplitude, 0, tt)*sin(transition(lp_n_ai_frequency, 0, tt)*$abstime + transition(lp_n_ai_phase, 0, tt)) + transition(0, 0, tt);
   $bound_step(10/lp_n_ai_frequency);
   V(lp_p_ai) <+ transition(lp_p_ai_amplitude, 0, tt)*sin(transition(lp_p_ai_frequency, 0, tt)*$abstime + transition(lp_p_ai_phase, 0, tt)) + transition(0, 0, tt);
   $bound_step(10/lp_p_ai_frequency);
   end
   
 
   // Instantiate the analog netlist
 rxbb_lp rxbb_lp_inst(
   .bbmux_lp_n_ai(bbmux_lp_n_ai) ,
   .bbmux_lp_p_ai(bbmux_lp_p_ai) ,
   .lp_n_ai(lp_n_ai) ,

   .lp_p_ai(lp_p_ai) ,
   .lp1_n_amux_ao(lp1_n_amux_ao) ,
   .lp1_p_amux_ao(lp1_p_amux_ao) ,
   .lp2_n_amux_ao(lp2_n_amux_ao) ,
   .lp2_p_amux_ao(lp2_p_amux_ao) ,
   .lp_n_ao(lp_n_ao) ,
   .lp_p_ao(lp_p_ao)
 );
 

endmodule


I have declared the inputs of the wrapper as wreal and my intermediate inputs as electrical and my final outputs as electrical.
When I execute this model, which is actually being instantiated in a bigger model;
I come across this error:
xmelab: *E,CUVNCM (../rxbb_lp_wrapper_13_puducodenarp/vams/testfixture_reference_rxbb_lp_model_wrapper.vams,190|39): No connection module found:Need an input port of continuous discipline electrical, and a wreal output port of discrete discipline logic, at instance tb_rxbb_lp_model_wrapper.converter_shell_reference_rxbb_lp_model_wrapper_inst.testfixture_reference_rxbb_lp_model_wrapper_inst.reference_rxbb_lp_wrapper_inst, between actual port lp_p_ai_frequency and formal port lp_p_ai_frequency.
   .lp_p_ai_phase(lp_p_ai_phase) ,
For all the 12 input parameters I have used:
should be defined as wreal or can I change it to a suitabe option ?
The module that instantiates this module has defined it as
electrical  bbmux_lp_p_ai_phase.

Title: Re: Verilog AMS sine generator
Post by Praseetha Pn on Jan 26th, 2022, 6:09am

Hi again,
I tried the exact code and it works well for the first frequency rage.
I am using a for loop in my test bench to increase the frequency from 1mhz to 100mhz in steps of 10, when I do so the frequency of the second set of sine wave should be 11mhz but it is in ghz range! is there any reason for that ?

Title: Re: Verilog AMS sine generator
Post by Ken Kundert on Jan 26th, 2022, 4:58pm

Asking someone to help you spot a bug in code you have not disclosed is a ridiculous request.

Title: Re: Verilog AMS sine generator
Post by Praseetha Pn on Jan 31st, 2022, 12:12am

Hi,
This works fine,
  V(bbmux_lp_n_ai) <+ bbmux_lp_n_ai_amplitude * sin(2*`M_PI* bbmux_lp_n_ai_frequency*$abstime) + 0.75;
  $bound_step(0.1/bbmux_lp_n_ai_frequency);
  V(bbmux_lp_p_ai) <+ bbmux_lp_p_ai_amplitude * sin(2*`M_PI* bbmux_lp_p_ai_frequency*$abstime)+ 0.75;
  $bound_step(0.1/bbmux_lp_n_ai_frequency);
  V(lp_n_ai) <+ lp_n_ai_amplitude * sin(2*`M_PI* lp_n_ai_frequency*$abstime) + 0.75;
  $bound_step(0.1/bbmux_lp_n_ai_frequency);
  V(lp_p_ai) <+ lp_p_ai_amplitude * sin(2*`M_PI* lp_p_ai_frequency*$abstime) +0.75;
  $bound_step(0.1/bbmux_lp_n_ai_frequency);

It was the extra features like the transition that caused the issue.

Title: Re: Verilog AMS sine generator
Post by Ken Kundert on Feb 1st, 2022, 1:22pm

The transition functions should only be applied to the values that change abruptly  Not to the values that change continuously.  So, you code should look like this:

Code:
V(out) <+ transtition(ampl, 0, tt) * sin(6.28*transition(freq, 0, t)*$abstime) + transition(offset, 0 tt);

Notice that the sine function is outside any transition funciton.

-Ken

The Designer's Guide Community Forum » Powered by YaBB 2.2.2!
YaBB © 2000-2008. All Rights Reserved.