Clocked Shorthand

Proposal Details

  • Who Updates: DanielKho, JimLewis, ...
  • Date Proposed: 4 Jan 2012
  • Date Last Updated: 4 Jan 2011
  • Priority:
  • Complexity:
  • Focus:

See also ISAC IR-2034 and ISAC IR-2035.

Related Issues

* MultiCyclePath*.

Current Situation

A couple of discussion threads on the reflector expressed a desire for:

  • Shorthand for clocked processes - to reduce amount of boilerplate typing
  • Shorthand for pipelining - this was also referred to as adding a "z-transform" function. This has two benefits - reducing boilerplate code, but more importantly explicitly signalling the tools that a pipeline chain is what is required, and removing a clutter of intermediate signals which are otherwise explicit in the source.

((Also falling into this "heading" were some suggestions on a library of standard functions (like and, or, mux2, ....). I will discuss these in another place (link to be added!)))

Requirement Summary

To reduce the amount of typing involved in creating clocked processes

To reduce intermediate signal clutter

To more explicity state intention to tools

Demonstrate (via examples) of support for numerous flip-flop coding styles: simple (no reset), reset (asynchronous, synchronous, power-on), load enable, mixing registers that have reset with those that do not, clock gates

Code Examples & Use Models

A number of possible syntaxes were discussed.

Non-Syntax Option:

Use a procedure call per ExtendedHwFunctions.

Reg(Clk, D, Q) ;

RegPipe (Clk, D, Q, 5) ; -- adds a 5 deep pipelining / shift register.

Current Syntax Option:

Q <= D when rising_edge(Clk) ;

type RegBankType is array (gDEPTH downto 0) of std_logic_vector(gWIDTH downto 0) ;

signal aQ : RegBankType ;

aQ <= aQ(gDEPTH -1 downto 0) & D when rising_edge(Clk) ;

Q <= aQ(gDEPTH) ;

Tap1 <= aQ(TAP1_INDEX) ;

With VHDL-2008 and unconstrained arrays of arrays could use a standard type for arrays of std_logic_vector

Proposed Syntax Option 6/16/2016:

Q <= D @ 2 when rising_edge(Clk) ;

Q <= D[2] when rising_edge(Clk) ;

...

How does reset work and clear out the pipeline?

Offers little over the vhdl-2008 syntax, especially for complex cases.

Could work this in with channels proposal AsynchronousChannels

Syntax Option 1:

Text originally on Collected Requirements Page:

  • Create default attributes to define registers
    • Syntax A <= B @ 2; -- B becomes A after 2 clock cycles
    • Predifined attribues like clock, reset, reset_value, enable, rising_edge would be needed.
      • Put on a signal, a group, or an entity.
  • Allow synthesis if "@ 2" is used, ignore synthesis (sim only) if "after 2 ns" or "@ 2 ns" is used.
q <= d @ 2;

or

q <= d after 2;

with the '2' implying 2 cycles. Attributes could then be assigned at the entity or signal level to define clock signal, reset value, enable, etc;

   attribute default_clock : STD_ULOGIC; 
   attribute default_reset : STD_ULOGIC; 
   attribute default_enable : STD_ULOGIC; 
   attribute default_reset_value : STD_ULOGIC; 
   attribute default_clock_edge : STD_ULOGIC; 
   attribute default_clock of ent1 : entity is clk_sig;

which could lead to a very compact definition.

Use Cases

q <= d @ 2;

Asynchronous resets:

q <= x"0" when not nReset else d @ 2;

Synchronous resets:

q <= x"0" when not nReset and rising_edge(clk) else d @ 2;

Mathematical example that uses asynchronous reset:

q <= to_signed(0, dataWidth) when not enable else to_signed((d*123_456 - 78_901) / 2**d, dataWidth) @ 2;

Allow '@' notation within processes, so as to tell the synthesis tool to implicitly add pipeline registers:

p0: process(clk,enable) is begin
   if enable='0' then q <= to_signed(0, dataWidth);
   elsif rising_edge(clk) then
      q <= to_signed((d*123_456 - 78_901) / 2**d, dataWidth) @ 2;
      --more statements...
   end if;
end process p0;

For dual-edge-triggered processes, the pipelined signal should appear considering both edges of the clock:

p1: process(clk,enable) is begin
   if enable='0' then q <= to_signed(0, dataWidth);
   elsif rising_edge(clk) or falling_edge(clk) then
      q <= to_signed((d*123_456 - 78_901) / 2**d, dataWidth) @ 2;    --here, "@ 2" means after 2 edge detections, i.e. after both rising and falling edges.
      --more statements...
   end if;
end process p1;

Arguments FOR

The 1st option allows for the implicit creation of the pipeline signals to reduce clutter, and for simple pipelines without reset logic could provide a compact representation.

Simplifies descriptions which are heavily mathematical- or DSP-based. Mathematical / DSP descriptions usually would require some level of pipelining, and the 1st option retains the original equations in the description. Without this, the description will be less understandable (the original equations will be "lost" or obscured), and it becomes more structural instead of behavioral.

If the equations involved are fairly complex, option 1 will reduce the amount of typing significantly, as it reduces the many intermediate signals which would otherwise have to be declared. Also, this reduces the many structural blocks that need to be described. Imagine having to instantiate a power-of-x and a divider and a few other mathematical blocks separately, then connecting all of them structurally together.

This introduces the ability to clock functions, as it signals the tool to automatically add pipeline registers even if the behaviour has been described using a set of functions.

Arguments AGAINST

This sounds scary and error-prone to me. With this approach I have to look all over the declarative regions inside and outside the entity (if the attribute is specified where the entity is instantiated) to find out what my clock is!

A decent IDE/editor removes most of the pain of boilerplate typing anyway.

Is the implicit creation of signals a bit "non-VHDL"?

Syntax Option 2:

Some more explicit variations on this theme include extending the definition of "time" to include events (and the * operator to count them, a bit like doing 2*1 ns):

q <= d after 2 * (rising_edge(clk) and enable = '1');

Asynchronous resets could be achieved thus:

q <= "0000" when nReset = '0' else d after 2 * (rising_edge(clk) and enable = '1');

Synchronous resets would require something like:

q <= "0000" after (rising_edge(clk) and nReset = '0') 
  else d after 2 * (rising_edge(clk) and enable = '1');

Mathematical example that uses asynchronous reset: -- DanielKho - 2012-04-26

q <= to_signed(0, dataWidth) when not enable else to_signed((d*123_456 - 78_901) / 2**d, dataWidth) after 2 * rising_edge(clk);

A variation on this using processes (processes are often needed for multiple sequential statements): -- DanielKho - 2012-04-26

p0: process(clk,enable) is begin
   if enable='0' then q <= to_signed(0, dataWidth);
   elsif rising_edge(clk) then
      q <= to_signed((d*123_456 - 78_901) / 2**d, dataWidth) after 2;
      --more statements...
   end if;
end process p0;

For dual-edge-triggered processes, the pipelined signal should appear considering both edges of the clock: -- DanielKho - 2012-03-11

p1: process(clk,enable) is begin
   if enable='0' then q <= to_signed(0, dataWidth);
   elsif rising_edge(clk) or falling_edge(clk) then
      q <= to_signed((d*123_456 - 78_901) / 2**d, dataWidth) after 2;    --here, "after 2" means after 2 edge detections, i.e. after both rising and falling edges.
      --more statements...
   end if;
end process p1;

Arguments FOR

Arguments AGAINST

Syntax Option 3:

label: process [rising|falling] clock(Clk) is 
  -- declaration region for constants, variables, aliases, etc. 
[asynchronous|synchronous] reset(Rst) 
  -- reset logic 
begin 
  -- non-reset logic 
end process; 

Arguments FOR

Arguments AGAINST

A comment was made that

This change doesn't give a huge benefit, but it ought to be easy to 
specify and use. 

Syntax Option 4:

Another possibility would be to provide an extra attribute on signals:

if clk'rising then

again, the benefit is marginal.

A variation on this theme was to allow functions in sensitivity lists to provide something like Verilog's sensitivity lists to define the clock edge (which reduces the need for the rising_edge() function within the process):

process (rising_edge(clk), falling_edge(reset_n))
begin
   if reset_n = '0' then q <= '0'
   else q <= d;
   end if;
end process;

Arguments FOR

Arguments AGAINST

Use Cases

Syntax Option 5:

Use PSL:

q <= d after Tpd, e after T + Tpd, f after T + Tperiod_clk + Tpd;

General Arguments FOR (not specific to a Syntax Option)

General Arguments AGAINST (not specific to a Syntax Option)

Most of the syntaxes are not much (if any) shorter than what everyone uses daily at the moment.

General Comments

-- ErnstChristen - 2015-01-27

There are 2 proposals related to clock management.

It seems worthwhile to formulate generic requirements for handling clocks (semantics, usage, restrictions, etc.) before looking at individual aspects in isolation.

Supporters

Add your signature here to indicate your support for the proposal

-- DanielKho - 2015-01-01

Topic revision: r12 - 2016-06-16 - 18:35:46 - JimLewis
 
Copyright © 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback