Assymetric delay modelling

L

Lou Barth

Guest
Hi guys,

I try to model a complexe analog circuit with assymetric timing behavior. Imagine a circuit with start as input and out as output.
When start rise, out rise after 10 ns.
When start fall, out fall after 100ns.

If a falling glitch occurs on start, I expect to have out staing at 1, I expect to have the out falling event cancel of the simulator memory when start rise again. I try many solutions like blocking and non blocking assignement, using join fork ... I have no idea how I can model that correctly.

You will find code + tb just after, any help will be warmly welcome!

Lou Barth






reg start;
reg out_be;


always @ (start) begin
if ( start == 1'b1) begin
#10 out = 1'b1;
end
else begin
#100 out = 1'b0;
end
end

initial begin: main_loop
start = 1'b1;
#20 start = 1'b0;
#20 start = 1'b1;
end
 
Lou Barth wrote:
Hi guys,

I try to model a complexe analog circuit with assymetric timing behavior. Imagine a circuit with start as input and out as output.
When start rise, out rise after 10 ns.
When start fall, out fall after 100ns.

If a falling glitch occurs on start, I expect to have out staing at 1, I expect to have the out falling event cancel of the simulator memory when start rise again. I try many solutions like blocking and non blocking assignement, using join fork ... I have no idea how I can model that correctly.

You will find code + tb just after, any help will be warmly welcome!

Lou Barth






reg start;
reg out_be;


always @ (start) begin
if ( start == 1'b1) begin
#10 out = 1'b1;
end
else begin
#100 out = 1'b0;
end
end

initial begin: main_loop
start = 1'b1;
#20 start = 1'b0;
#20 start = 1'b1;
end
You can't model this with blocking delays in a single always block.
The best approach is two always blocks with edge dependence and
non-blocking delays like:

always @ (negedge start) out <= #100 1'b0;
always @ (posedge start) out <= #10 1'b1;

--
Gabor
 
On 5/31/2013 3:03 PM, GaborSzakacs wrote:

always @ (negedge start) out <= #100 1'b0;
always @ (posedge start) out <= #10 1'b1;
This will not work either since non-blocking delays are implemented as
transport delays. Given the timing specified above the output will go
from undefined to high at 10ns and then go low at 120ns even though the
input is high. Not what the original poster requested regarding pulse
filtering and obviously incorrect from a simple buffer standpoint!

To get glitch filtering you need to use a construct that supports
inertial delays and for that a simple assignment with both a rising and
falling delay works as expected. Assuming the module timescale is 1ns
then the following should give the expected results:

wire out;
assign #(10, 100) out = start;

Cary
 
Thanks for your answers.

Perhaps I was not totally clear, I want that glitch have an impact on my circuit behavior. Following next waveform, with the glitch on start, the rising edge on out is delayed and occurs 100ns after the second rising edge of start.

____ ____________
start ___| |_| |___
______
out __________________| |____



With your solution Gabor, we have this behavior:
____ ____________
start ___| |_| |___
_____________
out ____________| |____

and the rising edge on out occurs 100ns after the first rising edge on start.


Cary, I do not succeed to simulate your solution. I am using ncsim, is there some extra command to add at simulation??


I succeed to model a solution using this syntaxe and the symectrical for handling the negedge. If any one has something smaller, it will be wellcomed!

always @( posedge start ) begin
fork : fork_p
begin
#`t_r out = 1'b1;
disable fork_p;
end
@( pdn) begin
disable fork_p;
end
join
end



Thanks and best regards

Lou Barth
 
On 6/5/2013 8:19 AM, Lou Barth wrote:
Cary, I do not succeed to simulate your solution. I am using ncsim,
is there some extra command to add at simulation??
Hi Lou,

It looks like you swapped the rising and falling delays between your
initial post and your second post.

What I wrote should work on any simulator, but you may have left in a
"reg out;" definition. A signal can only have one definition. In this
case it needs to be defined as a wire. Well that's not exactly true
anymore since in SystemVerilog you can also have a continuous assignment
to a variable (reg), but I find it is best to write it as a wire for
portability. Section 10.3.3 in 1800-2012 (free from the IEEE) describes
how delays in a continuous assignment work. You may have also put the
continuous assignemnt inside a procedural block which is not correct
either. A continuous assignment (assign statement) is placed in a module
definition at the same hierarchical level as an initial or always process.

Regarding your latest code; conceptually that looks like it should work
if pdn is triggered by the negative edge of start. If pdn is coming from
the negative edge I think you can omit the disable after the delayed
assignment since the other fork branch will cancel the fork before the
next positive edge of start and you could write it simply as

reg out;

always @(posedge start) begin
fork : fork_p
#`t_r out = 1'b1;
@(negedge start) disable fork_p;
join
end

always @(negedge start) begin
fork : fork_n
#`t_f out = 1'b0;
@(posedge start) disable fork_n;
join
end

This is subtly different from how the delay in a continuous assignment
works, but matches for the normal 0/1 transitions. Using a continuous
assignment this all could be replaced with.

wire out;

assign #(`t_r, `t_f) out = start;

In the end it all depends on exactly what functionality you are trying
to model. Also I doubt a synthesizer could do anything usable with the
dual always blocks. That is likely not an issue for you since you stated
in the initial post this was going to be used in a block modeling analog
circuitry.

Regards,

Cary
 
I'm not sure if it's the easiest way, but you might want to make a simple UDP (User-Defined Primitive). This will let you specify separate rise and fall times. I've rarely used them but it might look something like this:

module delay_elem(input in, output out);
buf (out, in); // primitive buffer
specify
(in => out) = (10, 100); // rise and fall times
endspecify
end

Then you instantiate is where desired. I'm not certain if this does what you want but it's an option to look at. (It definitely won't synthesize.)
 
On 6/5/2013 11:06 AM, Kevin Neilson wrote:
I'm not sure if it's the easiest way, but you might want to make a
simple UDP (User-Defined Primitive). This will let you specify
separate rise and fall times. I've rarely used them but it might
look something like this:

module delay_elem(input in, output out);
buf (out, in); // primitive buffer
specify
(in => out) = (10, 100); // rise and fall times
endspecify
end

Then you instantiate is where desired. I'm not certain if this does
what you want but it's an option to look at. (It definitely won't
synthesize.)
Hi Kevin,

This is actually a primitive with a specify block to define the timing.
For this simple case you can omit the specify block and write this as
just a primitive instantiation with a delay:

buf #(`t_r, `t_f) (out, in);

Primitives have inertial delays just like a continuous assignment so
they should behave the same as what I described in a previous post. I
sometimes use a primitive instead of a continuous assignment to make it
clear that the block is a model and is not intended to be synthesized.

A user defined primitive (denoted by primitive/endprimitive) is used to
define a non-standard logic relationships and can use a specify block
for timing or the simple timing that all the basic primitives support.

Cary
 

Welcome to EDABoard.com

Sponsor

Back
Top