Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Shift register delay generator error

Status
Not open for further replies.

shaiko

Advanced Member level 5
Joined
Aug 20, 2011
Messages
2,644
Helped
303
Reputation
608
Reaction score
297
Trophy points
1,363
Activity points
18,302
I described a delay generator based on a shift register.

CLOCK - Global clock.
RESET - Global reset.
"INPUT" - Input signal to apply the delay on.
"DELAY_DURATION" - Desired time (in nano seconds) to delay the input.
"OUTPUT" - The "INPUT" signal delayed by "DELAY_DURATION" nanoseconds.
"FREQUENCY" - The frequency of the global clock that drives the design.

My code:

Code:
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
library work ;
use work.package_functions_general.all ;
		
entity delay_generator is

generic 
(
  FREQUENCY : positive := 50000000
) ;                                                                            
															                   
port                                                                           
(							                                                   
  CLOCK : in std_logic ;            
  INPUT : in std_logic ; 		
  RESET : in std_logic ;            
  DELAY_DURATION : in unsigned ;             
  OUTPUT : out std_logic		       
);                                       
	   
end entity delay_generator ;

architecture synthesizable_generator_delay of delay_generator is

constant width_unsigned_frequency : positive := log_2_decimal ( FREQUENCY ) ;	
constant unsigned_frequency : unsigned := to_unsigned ( FREQUENCY , width_unsigned_frequency ) ;
constant maximum_possible_delay_duration : unsigned ( DELAY_DURATION ' range ) := ( others => '1' ) ;  
constant maximum_possible_cycles_to_delay : unsigned := cylces_from_time ( maximum_possible_delay_duration , "ns" , unsigned_frequency ) ;
constant shift_register_width : positive := to_integer ( maximum_possible_cycles_to_delay ) ;
signal shift_register : unsigned ( shift_register_width - 1 downto 0 ) := ( others => '0' ) ;
signal required_number_of_cycles : unsigned ( 31 downto 0 ) := ( others => '0' ) ;

begin
					
  required_number_of_cycles <= cylces_from_time ( DELAY_DURATION , "ns" , unsigned_frequency ) ;
  [COLOR="#FF0000"]OUTPUT <= shift_register ( to_integer ( required_number_of_cycles ) ) ;[/COLOR]
  
  shifting_left : process ( RESET , CLOCK ) is 
  begin		
    if RESET = '1' then
      shift_register <= ( others => '0' ) ;
    elsif rising_edge ( CLOCK ) then
      shift_register <= shift_register ( shift_register ' high - 1 downto 0 ) & INPUT ; 
    end if ;
  end process shifting_left ;  							
	
end architecture synthesizable_generator_delay ;


At my Modelsim TB I drive DELAY_DURATION port with the value: "000000010011100010000" (decimal 10000) and press the run key.

Simulation terminates immediately with a fatal error pointing to the line I marked in red:
** Fatal: (vsim-3734) Index value 2097151 is out of range 104856 downto 0.
This suggests that the signal "required_number_of_cycles" is supposedly 2097151 . Looking at the waveform window indeed shows that the signal is given this value (when it should've been given "000000000000111110100" (500 decimal).

Strange enough, when I omit the erroneous line and rerun the simulation
Code:
--OUTPUT <= shift_register ( to_integer ( required_number_of_cycles ) ) ;
"required_number_of_cycles" becomes "000000000000111110100" (500 decimal) as it should!

Any ideas?
 

we need package_functions_general.all to compile the code

Wouldn't it be better to use log2() function from math_real library then create ist's own version ?

Also you need to take into account that if DELAY_DURATION port is not driven by a constant you will end up with very unsythesable code for higher f_clk frequency. As synthezer will create shift registers on DFF and not on SR modules, each DFF output will be connected to OUTPUT port via mux driven by DELAY_DURATION control signal.
 
Last edited:

Thanks for the reply.

Wouldn't it be better to use log2() function from math_real library then create ist's own version ?
I don't see why. My log2 is thoroughly tested and works fine.

Also you need to take into account that if DELAY_DURATION port is not driven by a constant you will end up with very unsythesable code.
I disagree. Driving "DELAY_DURATION" with a variable ( not a constant) may result in the implementation of very slow combinatorial logic - yet it's perfectly synthesizable. Anyways, this is out of the scope for this post.

we need package_functions_general.all to compile the code
sure.

Code:
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;




package package_functions_general is



function log_2_decimal ( d : natural ) return natural ;	-- Gives the bit number of the MSB ( for example 230 in decimal is 11100110	in binary. So the function will return the number: 7. 		



function restoring_divide 
( 
numerator : unsigned ; 
denominator : unsigned 
) 
return unsigned ;	

	

function time_period_from_frequency -- Calculates the time period in "time_units" of "frequency_hz". 	
( 
frequency_hz : unsigned ; 
time_units : string 
) 
return unsigned ;					

	
	
function cylces_from_time -- Calculates the number of cycles that are needed for "desired_time" in "time_units" to pass when the clock frequency is "frequency_hz".
( 
desired_time : unsigned ; 
time_units : string ; 
frequency_hz : unsigned 
) 
return unsigned ;	


end package package_functions_general ;






package body package_functions_general is

function restoring_divide 
( 
numerator : unsigned ; 
denominator : unsigned 
) 
return unsigned is
variable temp_numerator : unsigned ( numerator ' range ) := numerator ;
variable temp_numerator_with_denominator_length : unsigned ( denominator ' range ) := ( others => '0' ) ;	
variable temp_denominator : unsigned ( denominator ' range ) := denominator ;
variable temp_denominator_with_numerator_length : 	unsigned ( numerator ' range ) := ( others => '0' ) ;	
variable temp_remainder : unsigned ( denominator ' length downto 0 ) := ( others => '0' ) ;
variable temp_remainder_with_numerator_length : unsigned ( numerator ' length downto 0 ) := ( others => '0' ) ;	
begin
  if numerator ' length = denominator ' length then 
    for index in 0 to denominator ' length - 1 
    loop
      temp_remainder ( denominator ' length - 1 downto 1 ) := 
      temp_remainder ( denominator ' length - 2 downto 0 ) ;
      temp_remainder ( 0 ) := 
      temp_numerator ( numerator ' length - 1 ) ;
      temp_numerator ( numerator ' length - 1 downto 1 ) := 
      temp_numerator ( numerator ' length - 2 downto 0 ) ;
      temp_remainder := temp_remainder - temp_denominator ;
      if ( temp_remainder ( denominator ' length ) = '1' ) then
        temp_numerator ( 0 ) := '0' ;
        temp_remainder := temp_remainder + temp_denominator ;
      else
        temp_numerator ( 0 ) := '1' ;
      end if ;
    end loop ;
    return temp_numerator ;
  elsif numerator ' length > denominator ' length then 
    temp_denominator_with_numerator_length := resize ( denominator , numerator ' length ) ;	
    for index in 0 to temp_denominator_with_numerator_length ' length - 1 
    loop
      temp_remainder_with_numerator_length ( temp_denominator_with_numerator_length ' length - 1 downto 1 ) := 
      temp_remainder_with_numerator_length ( temp_denominator_with_numerator_length ' length - 2 downto 0 ) ;
      temp_remainder_with_numerator_length ( 0 ) := temp_numerator ( numerator ' length - 1 ) ;
      temp_numerator ( numerator ' length - 1 downto 1 ) := temp_numerator ( numerator ' length - 2 downto 0 ) ;
      temp_remainder_with_numerator_length := temp_remainder_with_numerator_length - temp_denominator ;
      if ( temp_remainder_with_numerator_length ( temp_denominator_with_numerator_length ' length ) = '1' ) then
        temp_numerator ( 0 ) := '0' ;
        temp_remainder_with_numerator_length := temp_remainder_with_numerator_length + temp_denominator ;
      else
        temp_numerator ( 0 ) := '1' ;
      end if ;
      end loop ;
    return temp_numerator ;			
  else 
    temp_numerator_with_denominator_length := resize ( numerator , denominator ' length ) ;	
    for index in 0 to denominator ' length - 1 
    loop
      temp_remainder ( denominator ' length - 1 downto 1 ) := temp_remainder ( denominator ' length - 2 downto 0 ) ;
      temp_remainder ( 0 ) := temp_numerator_with_denominator_length ( temp_numerator_with_denominator_length ' length - 1 ) ;
      temp_numerator_with_denominator_length ( temp_numerator_with_denominator_length ' length - 1 downto 1 ) := 
      temp_numerator_with_denominator_length ( temp_numerator_with_denominator_length ' length - 2 downto 0 ) ;
      temp_remainder := temp_remainder - temp_denominator ;
      if ( temp_remainder ( denominator ' length ) = '1' ) then
        temp_numerator_with_denominator_length ( 0 ) := '0' ;
        temp_remainder := temp_remainder + temp_denominator ;
      else
        temp_numerator_with_denominator_length ( 0 ) := '1' ;
      end if ;
    end loop ;
    return temp_numerator_with_denominator_length ;
  end if ;			
end function restoring_divide ;  



function log_2_decimal 
( 
d : natural 
) 
return natural is
variable temp_d : natural := d ;
variable n : natural := 0 ;
begin
  while temp_d > 1 
  loop
    temp_d := temp_d / 2 ;
    n := n + 1 ;
  end loop ;
  if d > 2 ** n then
    return ( n + 1 ) ; 
  else
    return ( n ) ; 
  end if ;
end function log_2_decimal ;

	
	
function time_period_from_frequency 
( 
frequency_hz : unsigned ; 
time_units : string 
) 
return unsigned is
variable second_ms : unsigned ( 9 downto 0 ) := "1111101000" ; -- 1,000 ms is 1 second.
variable second_us : unsigned ( 19 downto 0 ) := "11110100001001000000" ; -- 1,000,000 us is 1 second.
variable second_ns : unsigned ( 31 downto 0 ) := "00111011100110101100101000000000" ; -- 1,000,000,000 ns is 1 second.
variable result_ms : unsigned ( 9 downto 0 ) := ( others => '0' ) ;
variable result_us : unsigned ( 19 downto 0 ) := ( others => '0' ) ;
variable result_ns : unsigned ( 31 downto 0 ) := ( others => '0' ) ;
begin 
  if time_units = "ms" then 
    result_ms := restoring_divide ( second_ms , frequency_hz ) ;
    return result_ms ;
  elsif time_units = "us" then 
    result_us := restoring_divide ( second_us , frequency_hz ) ;
    return result_us ;
  elsif time_units = "ns" then 
    result_ns := restoring_divide ( second_ns , frequency_hz ) ;
    return result_ns ;
  end if ;	
end function time_period_from_frequency ;		

	
	
function cylces_from_time -- Calculates the number of cycles that are needed for "desired_time" in "time_units" to pass when the clock frequency is "frequency_hz".
( 
desired_time : unsigned ; 
time_units : string ; 
frequency_hz : unsigned 
) 
return unsigned is	
variable result_ms : unsigned ( 9 downto 0 ) := ( others => '0' ) ;
variable result_us : unsigned ( 19 downto 0 ) := ( others => '0' ) ;
variable result_ns : unsigned ( 31 downto 0 ) := ( others => '0' ) ;
variable result_ps : unsigned ( 39 downto 0 ) := ( others => '0' ) ;
variable result_fs : unsigned ( 49 downto 0 ) := ( others => '0' ) ;
begin
if time_units = "ms" then 
  result_ms := restoring_divide ( desired_time , time_period_from_frequency ( frequency_hz , time_units ) ) ;
  return result_ms ;
elsif time_units = "us" then 
  result_us := restoring_divide ( desired_time , time_period_from_frequency ( frequency_hz , time_units ) ) ;
  return result_us ;
elsif time_units = "ns" then 
  result_ns := restoring_divide ( desired_time , time_period_from_frequency ( frequency_hz , time_units ) ) ;
  return result_ns ;
elsif time_units = "ps" then 
  result_ps := restoring_divide ( desired_time , time_period_from_frequency ( frequency_hz , time_units ) ) ;
  return result_ps ;
elsif time_units = "fs" then 
  result_fs := restoring_divide ( desired_time , time_period_from_frequency ( frequency_hz , time_units ) ) ;
  return result_fs ;
end if ;	
end function cylces_from_time ;		
	


end package body package_functions_general ;
 

I don't see why. My log2 is thoroughly tested and works fine.

It's just reinventing the wheel situation

Again in Active-HDL with stimulus:

Code:
  signal CLOCK,INPUT,RESET,OUTPUT : std_logic := '1';
  signal DELAY_DURATION : unsigned(20 downto 0) := to_unsigned(0,21);
  
begin
	DELAY_DURATION <= to_unsigned(10000,21);
  CLOCK <= not CLOCK after 10 ns;
  RESET <= '0' after 5 ns;
  
  INPUT <= '0' after 30 ns;

works well.


I disagree. Driving "DELAY_DURATION" with a variable ( not a constant) may result in the implementation of very slow combinatorial logic - yet it's perfectly synthesizable. Anyways, this is out of the scope for this post.

On 2nd biggest Cyclone V with 21-bit delay_duraration, Quartus try to synthesie the code now for 16 minutes (46%) and still counting the time



update

On modelsim 10.1 also no problems
 
Last edited:
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
works well.
Strange. I use Modelsim and it fails...

On 2nd biggest Cyclone V with 21-bit delay_duraration, Quartus try to synthesie the code now for 16 minutes (46%) and still counting the time.
There's nothing un-synthesizable in nature with any of the functions in the package.

How did you constraint "DELAY_DURATION" ?
 

DELAY_DURATION is 21 -bit variable.

I used now Modelsim ALTERA STARTER EDITION 10.1d still ok
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
21 bits will require >100K DFFs...try limiting it to 16 bits for example. It should work.

I used now Modelsim ALTERA STARTER EDITION 10.1d still ok
can you please post your TB ?
I'll try to retest it with your code...
 

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;



entity eda is
 
end entity eda;

architecture BEHAVE of eda is




component delay_generator is

generic 
(
  FREQUENCY : positive := 50000000
) ;                                                                            
															                   
port                                                                           
(							                                                   
  CLOCK : in std_logic ;            
  INPUT : in std_logic ; 		
  RESET : in std_logic ;            
  DELAY_DURATION : in unsigned ;             
  OUTPUT : out std_logic		       
);                                       
	   
end component delay_generator ;
-----------------------------------------------------
  signal CLOCK,INPUT,RESET,OUTPUT : std_logic := '1';
  signal DELAY_DURATION : unsigned(20 downto 0) := to_unsigned(0,21);
  
begin
	DELAY_DURATION <= to_unsigned(10000,21);
  CLOCK <= not CLOCK after 10 ns;
  RESET <= '0' after 5 ns;
  
  INPUT <= '0' after 30 ns;
  
  DD: delay_generator port map (
    CLOCK => CLOCK,
  	INPUT => INPUT,
	RESET => RESET,
	DELAY_DURATION => DELAY_DURATION,
	OUTPUT => OUTPUT
	);




end architecture BEHAVE;
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Works.
checking for deltas...

- - - Updated - - -

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;



entity eda is
 
end entity eda;

architecture BEHAVE of eda is




component delay_generator is

generic 
(
  FREQUENCY : positive := 50000000
) ;                                                                            
															                   
port                                                                           
(							                                                   
  CLOCK : in std_logic ;            
  INPUT : in std_logic ; 		
  RESET : in std_logic ;            
  DELAY_DURATION : in unsigned ;             
  OUTPUT : out std_logic		       
);                                       
	   
end component delay_generator ;
-----------------------------------------------------
  signal CLOCK,INPUT,RESET,OUTPUT : std_logic := '1';
  signal DELAY_DURATION : unsigned(20 downto 0) [COLOR="#FF0000"]:= to_unsigned(0,21)[/COLOR];
  
begin
	DELAY_DURATION <= to_unsigned(10000,21);
  CLOCK <= not CLOCK after 10 ns;
  RESET <= '0' after 5 ns;
  
  INPUT <= '0' after 30 ns;
  
  DD: delay_generator port map (
    CLOCK => CLOCK,
  	INPUT => INPUT,
	RESET => RESET,
	DELAY_DURATION => DELAY_DURATION,
	OUTPUT => OUTPUT
	);




end architecture BEHAVE;

Please remove the line I marked in red.
Eliminating the pre-assignment during signal declaration, leaving only the runtime driver.

What do you get?
 

not working , because
# RUNTIME: Fatal Error: RUNTIME_0047 delay_generator2.vhd (38): Index 104857 out of range (104856 downto 0).

Modelsim initialize unintialize vectors with maximum number. Since
signal shift_register : unsigned ( shift_register_width - 1 downto 0 ) := ( others => '0' ) ; and
required_number_of_cycles <= cylces_from_time ( DELAY_DURATION , "ns" , unsigned_frequency ) ; is w/o -1 u got this error as required_number_of_cycles is 1 more then shift_register_width
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Please elaborate.

Signal "shift_register" IS defined with a "-1". This is done durnig compilation time not runtime...
Please note that the width of "shift_register" is set with the help of a constant named "maximum_possible_cycles_to_delay".

The only role "DURATION_DELAY" plays during compilation is setting the uncontrained boundaries of "shift_register".

Even if Modelsim does assume that "DURATION_DELAY" is a vector of 21 logic ones this shouldn't cause an error because it's a perfectly legal value for it...

Also,
Your error message isn't the same as mine. Please review post #1.
 

when u define DELAY_DURATION as 21 bit unsigned value the constant maximum_possible_delay_duration is 2^21-1= 2097151.
maximum_possible_cycles_to_delay = maximum_possible_delay_duration /20 = 104857
so shift_register is unsigned(104857-1 downto 0) = unsigned(104856 downto 0)
but
required_number_of_cycles <= cylces_from_time ( DELAY_DURATION , "ns" , unsigned_frequency ) ; = maximum_possible_cycles_to_delay = 104857

so
OUTPUT <= shift_register ( to_integer ( required_number_of_cycles ) ) ;
calls for shift_register(104857) but shift_register max value is 104856

my error message in MODELSIM is the same, the other one is from Active-HDL
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
So...you suggest to define "shift_register" as:
Code:
signal shift_register : unsigned ( shift_register_width downto 0 ) := ( others => '0' ) ;
and not as:
Code:
signal shift_register : unsigned ( shift_register_width [COLOR="#FF0000"]- 1[/COLOR] downto 0 ) := ( others => '0' ) ;
?
 

generally when u apply signal to dff ( shift_reg ) you apply already 1 clock delay so n delay requires n-1 registers. So i would rather change function that will return current -1 result, but that will need change in function that 0 delay will not wrap to "111....1111".

all in all

1. you take into account that delay_generator is always applying 1 cycle latency and change shift_register to : unsigned ( shift_register_width downto 0 ) := ( others => '0' ) ;

2. or change function to return -1 value and add some code that for 0 delay OUTPUT <= INPUT.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top