FDCP: D flip-flop with asynchronous Clear/Preset
FDCP is a D-type flip-flop with active-high asynchronous clear (CLR) and preset (PRE) inputs. The CLR input takes precedence over the PRE input. If CLR is asserted, the Q output is set to 0. If CLR is not asserted, and PRE is asserted, the Q output is set to 1. The data on the D input is otherwise loaded to the Q output on the low-to-high transition of the clock (C) input. |
Verilog
This Verilog code will correctly synthesise into a D flip-flop with an
asynchronous clear and an asynchronous preset (assuming, of course, that
your technology library has such a device). However, the code simulates
incorrectly, and fails the testbench. The error messages from the testbench
output log are:
(Error) (D100) 'fdcp.tv', line 10, 24 ns: 'Q': expected 'b1; got 'b0 (Error) (D100) 'fdcp.tv', line 11, 34 ns: 'Q': expected 'b1; got 'b0 (Log) (60 ns) 6 vectors executed (4 passes, 2 fails)
In other words, the model simulates incorrectly when both the CLR and PRE
inputs are asserted, and the CLR input is then released (at line 10 of the
testbench). The testbench expects the output to preset to 1 at this point,
but it instead holds at 0, and remains at 0 when the preset input is also
released (line 11).
The fundamental problem here is that Verilog's event controls cannot, by
themselves, handle this situation. There is no mechanism to tell whether or
not a particular edge triggered an event control (the equivalent of VHDL's
'event
attribute), and no combination or edge- or
level-sensitive controls gives the required behaviour. The simulation model
can be fixed, but this requires the addition of some fairly complex code;
see FDCP-FixedVerilog. Note that the VHDL model does not have this
problem, because the process triggers on the falling edge of CLR, and can
then detect than PRE is set (this works because the
rising_edge
function can detect whether or not a clock edge has
occurred).
module FDCP( input CLR, PRE, D, C, output reg Q); always @(posedge C or posedge CLR or posedge PRE) if(CLR) Q <= 0; else if(PRE) Q <= 1; else Q <= D; endmodule
VHDL
library IEEE; use IEEE.std_logic_1164.all; entity FDCP is port ( CLR, PRE, D, C : in std_logic; Q : out std_logic); end entity FDCP; architecture A of FDCP is begin process (C, CLR, PRE) is begin if CLR = '1' then Q <= '0'; elsif PRE = '1' then Q <= '1'; elsif rising_edge(C) then Q <= D; end if; end process; end architecture A;
Testbench
1 DUT { 2 module FDCP(input CLR, PRE, D, C; output Q) 3 create_clock C 4 [CLR, PRE] -> [Q] // test async clear/preset 5 [CLR, PRE, D, C] -> [Q] // test sync operation 6 } 7 8 [1, .X] -> [0] // async clear, takes precedence over preset 9 [1, 1] -> [0] // assert preset, output unchanged 10 [0, 1] -> [1] // release clear, output sets to 1 11 [0, 0] -> [1] // release preset, output holds at 1 12 13 [0, 0, 0, .C] -> [0] // clock to 0 14 [0, 0, 1, .C] -> [1] // clock to 1