Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
17 years ago

Changing The Value of a Register On Both Negative and Positive Edge of a Clock.


ENTITY test IS 
    PORT (
        CLK1,CLK2, done         : IN  STD_LOGIC; 
        pr_out                    : OUT STD_LOGIC                                
        );
END test;
ARCHITECTURE test1 OF test IS
    SIGNAL PR, done_flag : STD_LOGIC; 
BEGIN
    PROCESS (CLK1, CLK2, done)
        BEGIN
            IF ( done = '1' ) THEN 
                done_flag <= '1';
            ELSIF (CLK1'EVENT AND CLK1 = '1') THEN 
                IF ( done_flag = '1') THEN
                    PR <='1';
                END IF; 
            ELSIF (CLK2'EVENT AND CLK2 = '0') THEN
             IF ( done_flag = '1') THEN
                    done_flag <= '0';
                    PR <='0';
                END IF;
            END IF;
    END PROCESS; 
pr_out <= PR; 
END test1;
        
---           --------          -------
---          |        |        |       |
--- ---------          --------         -------- (CLK1)
--- -----          --------          --------                       
---      |        |        |        |        |        
---       --------          --------          -------- (CLK2)
Hello,

The logic behind this code is simple. You get an ASYNC ‘done’ at any point during the clock cycle CLK1 then you raise a flag called done_flag. On the next positive edge of the clock (CLK1) I set PR = 1 if done_flag is set from the previous cycle, and I lower both PR and done_flag on the NEGATIVE edge of the SECOND clock (clk2).

The clocks has a 90 degrees phase shift as seen in the commented section in the code.

this code will not compile because pr will be an inferred register and its behaviour will depend on the edges of 2 independent clocks. i understand that. however i still need to write a code that will make the circuit behave in an equivalent manner.

What do you do when you are faced with a similar problem? How do you go around it?

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi DerekJ,

    First I apologise if my suggestion is silly, I am based in the UK but have severe insomnia...

    Your functionality is not that sort of a standard RTL.

    However, there are several ways of playing gym with twin registers or more using the asynchronous reset.

    Ideally a much faster clock plus state machine will do the job easily and cleanly..

    Your notion of async being first cycle ...etc is not clear

    Anyway I suggest the following(asuming both clks stay related as stated):

    -register "done" to become "done_flag" using one process(clk1).

    -register "done_flag" to become PR in the same process(clk1). This leads to two FF.(may be you don't need done_flag)

    -reset both above asynchronously when done_flag AND Q2 = 1

    -Q2: This is the funny part:

    use a process on clk2(falling edge).

    Q2 <= '1' always but reset asynchronously e.g. on rising edge of clk1, for this you may just connect clk1 to reset.

    Kaz
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks Kaz,

    --- Quote Start ---

    Hi DerekJ,

    Ideally a much faster clock plus state machine will do the job easily and cleanly..

    Kaz

    --- Quote End ---

    I thought about that, and it will be my last resort, however the code is part of a multistage RISC processor, and the clock controls many stages. So I'd rather not.

    --- Quote Start ---

    Hi DerekJ,

    Anyway I suggest the following(asuming both clks stay related as stated):

    -register "done" to become "done_flag" using one process(clk1).

    -register "done_flag" to become PR in the same process(clk1). This leads to two FF.(may be you don't need done_flag)

    -reset both above asynchronously when done_flag AND Q2 = 1

    -Q2: This is the funny part:

    use a process on clk2(falling edge).

    Q2 <= '1' always but reset asynchronously e.g. on rising edge of clk1, for this you may just connect clk1 to reset.

    Kaz

    --- Quote End ---

    Yah I've thought about some solutions like that , all of them will cause significant delay in the circuit (The actual code has this problem repeated several times) let a lone complicate the code a lot.

    I'm surprised there is no straight forward solution to this problem. And I hate that Altera FPGAs doesn't have a delay block, which would have saved me adding another clock.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    As a first point, I have problems to understand which behaviour is exactly intended with the original code. The text explanation is partly different fromt the code. E. g. in the code, the done_flag won't be processed, before done has fallen to low level. Is this behaviour intended?

    For the same reason, I'm unable to see, if a two-phase clock is actually needed. Altera FPGA have several means to achieve clock delays, e. g. PLLs. In many applications, the delays adjusted by the fitter according to timing constraints are sufficient, in special cases, additional logic elements may be introduced as delay line.

    I would start with a behavioral specification of input and output signals (without a second clock), showing the intended pr_out waveform for different phases of done.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    You can design some crude delay through using Lcells or invert-invert or force routing through pins and back but none of them can be relied on interms of repeatability.

    It might help if you explain your required functionality in a broader perspective. For a complex design you certainly need to adhere to RTL methodology strictly at least for timing control.

    Kaz
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks KAZ, and KvM,

    Lets forget about the code for a second and let me ask the question in a different way.

    Here is what I want to implement:

    read <= '0' WHEN done = '0' after 5 ns;

    Any time within a clock cycle some external signal called "done" will be asserted asynchronously changing the value of some signal "read" from 1 to 0.

    Since this is a sequential logic circuit, the change happens very quickly in less than 0.5 ns However I need the change to be delayed by 5 ns to allow a latch that depends on the functionality of read to have the time to latch the results correctly.

    Quartus does not support the VHDL statement "after". So I tried to introduce another clock to control the delay. That failed.

    So roughly speaking, I am trying to find a way to implement the VHDL statement “after” because Quartus doesn’t support it.

    Your help will be greatly appreciated.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    read <= '0' WHEN done = '0' after 5 ns;

    --- Quote End ---

    This isn't a specification. A specification would imply edges and the state of all signals taking part in the logic processing. The only clear thing is, that you want to achieve a delay, which isn't available in the present form, as we all know. But without knowing the exact purpose of the delay in your logic, we can't discuss an alternative way. Methods to introduce delays by manually inserting logic cells with a keep attribute or using timing constraints have been recently discussed in the forum.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi

    How to write below code in C. I want collect some data using clock triggering.

    ENTITY test IS

    PORT (

    CLK1,CLK2, done : IN STD_LOGIC;

    pr_out : OUT STD_LOGIC

    );

    END test;

    ARCHITECTURE test1 OF test IS

    SIGNAL PR, done_flag : STD_LOGIC;

    BEGIN

    PROCESS (CLK1, CLK2, done)

    BEGIN

    IF ( done = '1' ) THEN

    done_flag <= '1';

    ELSIF (CLK1'EVENT AND CLK1 = '1') THEN

    IF ( done_flag = '1') THEN

    PR <='1';

    END IF;

    ELSIF (CLK2'EVENT AND CLK2 = '0') THEN

    IF ( done_flag = '1') THEN

    done_flag <= '0';

    PR <='0';

    END IF;

    END IF;

    END PROCESS;

    pr_out <= PR;

    END test1;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    if your signals are connected to PIOs you can configure them to trigger an interrupt on signal change. Then write an ISR that reads the values you want.

    There will be a delay due to the CPU's interrupt trigger mechanism though, so the timing won't be as accurate as a hardware solution.