ONE clock period pulse based on trigger signal - triggers

i am making a midi interface. UART works fine, it sends the 8 bit message along with a flag to a control unit. When the flag goes high, the unit will store the message in a register and make a clr_flag high in order to set the flag of UART low again. The problem is that i can not make this clr_flag one period long. I need it to be ONE period long, because this signal also controls a state machine that indicates what kind of message is being stored (note_on -> key_note -> velocity, for example).
My question here is, how can a signal (flag in this case) trigger a pulse just for one clk period? what i have now makes almost a pulse during a clock period, but i does it twice, because the flag has not become 0 yet. ive tried many ways and now i have this:
get_data:process(clk, flag)
begin
if reset = '1' then
midi <= (others => '0');
clr_flag <= '0';
control_flag <= '0';
elsif ((clk'event and clk='1') and flag = '1') then
midi <= data_in;
clr_flag <= '1';
control_flag <= '1';
elsif((clk'event and clk='0') and control_flag = '1') then
control_flag <= '0';
elsif((clk'event and clk='1') and control_flag = '0') then
clr_flag <= '0';
end if;
end process;
the problem with this double pulse or longer than one period pulse(before this, i had something that made clr_flag a two period clk pulse), is that the system will go though two states instead of one per flag.
so in short: when one signal goes high (independent of when it goes low), a pulse during one clock period should be generated.
thanks for your help.

The trick to making a single cycle pulse is realising that having made the pulse, you have to wait as long as the trigger input is high before getting back to the start. Essentially you are building a very simple state machine, but with only 2 states you can use a simple boolean to tell them apart.
Morten is correct about the need to adopt one of the standard patterns for a clocked process; I have chosen a different one that works equally well.
get_data:process(clk, reset)
variable idle : boolean;
begin
if reset = '1' then
idle := true;
elsif rising_edge(clk) then
clr_flag <= '0'; -- default action
if idle then
if flag = '1' then
clr_flag <= '1'; -- overrides default FOR THIS CYCLE ONLY
idle <= false;
end if;
else
if flag = '0' then
idle := true;
end if;
end if;
end if;
end process;

There are several issues to address in order to make the design for a one cycle
pulse using flip flops (registers).
First, the use of flip flops in hardware through VHDL constructions typically
follows a structure like:
process (clk, reset) is
begin
-- Clock
if rising_edge(clk) then
-- ... Flip flops to update at rising edge
end if;
-- Reset
if reset = '1' then
-- Flip flops to update at reset, which need not be all
end if;
end process;
So the get_data process should be updated accordingly, thus:
Sensitivity list should contain only clock (clk) and reset
The nested structure with if on event should be as above
Only rising edge of clk should be used, thus no check on clk = '0'
Making a one cycle pulse on clr_flag when flag goes high can be made with a
synchronous '0' to '1' detector on flag, using a version of flag that is
delayed a single cycle, called flag_ff below, and then checking for (flag =
''1) and (flag_ff = '0').
The resulting code may then look like:
get_data : process (clk, reset) is
begin
-- Clock
if rising_edge(clk) then
flag_ff <= flag; -- One cycle delayed version
clr_flag <= '0'; -- Default value with no clear
if (flag = '1') and (flag_ff = '0') then -- Detected flag going from '0' to '1'
midi <= data_in;
clr_flag <= '1'; -- Override default value making clr_flag asserted signle cycle
end if;
end if;
-- Reset
if reset = '1' then
midi <= (others => '0');
clr_flag <= '0';
-- No need to reset flag_ff, since that is updated during reset anyway
end if;
end process;

Synchronisation and Edge Detection for FSM
The Rise, Edge and Fall outputs will strobe for one cycle when those events are detected. Inputs and outputs are synchronised for use with a Finite State Machine.
entity SynchroniserBit is
generic
(
REG_SIZE: natural := 3 -- Default number of bits in sync register.
);
port
(
clock: in std_logic;
reset: in std_logic;
async_in: in std_logic := '0';
sync_out: out std_logic := '0';
rise_out: out std_logic := '0';
fall_out: out std_logic := '0';
edge_out: out std_logic := '0'
);
end;
architecture V1 of SynchroniserBit is
constant MSB: natural := REG_SIZE - 1;
signal sync_reg: std_logic_vector(MSB downto 0) := (others => '0');
alias sync_in: std_logic is sync_reg(MSB);
signal rise, fall, edge, previous_sync_in: std_logic := '0';
begin
assert(REG_SIZE >= 2) report "REG_SIZE should be >= 2." severity error;
process (clock, reset)
begin
if reset then
sync_reg <= (others => '0');
previous_sync_in <= '0';
rise_out <= '0';
fall_out <= '0';
edge_out <= '0';
sync_out <= '0';
elsif rising_edge(clock) then
sync_reg <= sync_reg(MSB - 1 downto 0) & async_in;
previous_sync_in <= sync_in;
rise_out <= rise;
fall_out <= fall;
edge_out <= edge;
sync_out <= sync_in;
end if;
end process;
rise <= not previous_sync_in and sync_in;
fall <= previous_sync_in and not sync_in;
edge <= previous_sync_in xor sync_in;
end;

Below is a way of creating a signal (flag2) that lasts exactly one clock period from a signal (flag1) that lasts at least one clock period.

I don't program in VHDL~ here is what I usually do for the same propose in Verilog:
always #(posedge clk or negedge rst) begin
if(~rst) flgD <= 1'b0;
else flgD <= flg;
end
assign trg = (flg^flgD)&flgD;

I am new to verilog and this is the sample code, which I used for triggering. Hope this serves your purpose. You can try same logic in VHDL.
module main(clk,busy,rd);
input clk,busy; // busy input condition
output rd; // trigger signal
reg rd,en;
always #(posedge clk)
begin
if(busy == 1)
begin
rd <= 0;
en <= 0;
end
else
begin
if (en == 0 )
begin
rd <= 1;
en <= 1;
end
else
rd <= 0;
end
end
endmodule

The below verilog code shall hold the value for the signals for one clock cycle exactly.
module PulseGen #(
parameter integer BUS_WIDTH = 32
)
(
input [BUS_WIDTH-1:0] i,
input clk,
output [BUS_WIDTH-1:0] o
);
reg [BUS_WIDTH-1:0] id_1 = 0 ;
reg [BUS_WIDTH-1:0] id_2 = 0 ;
always #(posedge clk)begin
id_1 <= i;
id_2 <= id_1;
end
assign o = (id_1 & ~id_2);

The way to achieve this is to create a debounce circuit. If you need a D flip-flop to change from 0 to 1, only for the first clock, just add an AND gate before its input like the image below:
So here you can see a D flip-flop and its debounce circuit.
P.S. Circuit created using this.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--input of minimum 1 clock pulse will give output of wanted length.
--load number 5 to PL input and you will get a 5 clock pulse no matter how long input is.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
entity fifth is
port (clk , resetN : in std_logic;
pdata : in integer range 0 to 5; --parallel data in. to choose how many clock the out pulse would be.
din : in std_logic;
dout : out std_logic
) ;
end fifth ;
architecture arc_fifth of fifth is
signal count : integer range 0 to 5;
signal pl : std_logic; --trigger detect output.
signal sample1 : std_logic;
signal sample2 : std_logic;
--trigger sync proccess.
begin
process(clk , resetN)
begin
if resetN = '0' then
sample1<='0';
sample2<='0';
elsif rising_edge(clk) then
sample1<=din;
sample2<=sample1;
end if;
end process;
pl <= sample1 and (not sample2); --trigger detect output. activate the counter.
--counter proccess.
process ( clk , resetN )
begin
if resetN = '0' then
count <= 0 ;
elsif rising_edge(clk) then
if pl='1' then
count<=pdata;
else
if count=0 then
count<=count;
else
count<=count-1;
end if;
end if;
end if ;
end process ;
dout<='1' when count>0 else '0';--output - get the wanted lenght pulse no matter how long is input
end arc_fifth ;

Related

Input Signal Edge Detection on FPGA

I am trying to interface a Virtex 4 (ML401) FPGA and a TIVA C series board using 4 wire SPI (cs, sclk, miso, mosi). The tiva acts as a master and the FPGA as a slave.
I am able to receive the SPI data from the master and display the data on the LEDS present on the FPGA (Method 2). However,
I need to find the rising and falling transitions of the chip select signal (required for my application for synchronization purposes).
I have tried many methods with FIFO's (that work well in simulation) but just don't work on the FPGA, as shown:
NOTE: spi_cs is the asynchronous SPI chip select signal input to the FPGA from the TIVA board, while other signals (spi_cs_s, spi_cs_ss, spi_cs_h2l, spi_cs_l2h, etc) are created internally on the FPGA.
Method 1)
prc_sync_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_s <= spi_cs;
end if;
end process prc_sync_cs;
spi_cs_l2h <= not (spi_cs_s) and spi_cs;
spi_cs_h2l <= not (spi_cs) and spi_cs_s;
Method 2)
process (spi_cs)
begin
if (spi_cs = '0' or spi_cs = '1') then
-- update ledss with new MOSI on rising edge of CS
spi_cs_ss <= spi_cs_s;
spi_cs_s <= spi_cs;
--leds <= spi_wdata; --leds display the received data on the FPGA (saved into spi_wdata in another process)
-- THIS WORKS ON THE FGPA BUT the edge detection doesn't. Why?
end if;
end process;
spi_cs_h2l <= '1' when (spi_cs_s = '0' and spi_cs_ss = '1') else '0';
spi_cs_l2h <= '1' when (spi_cs_s = '1' and spi_cs_ss = '0') else '0';
leds <= "000000" & spi_cs_h2l & spi_cs_l2h; -- ALL leds are off always (i,e both transitions are '0' always).
Method 3)
prc_sync_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_ss <= spi_cs_s;
spi_cs_s <= spi_cs;
end if;
end process prc_sync_cs;
prc_edge_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_ss_del <= spi_cs_ss;
end if;
end process prc_edge_cs;
spi_cs_h2l <= '1' when (spi_cs_ss_del = '1' and spi_cs_ss = '0') else '0';
spi_cs_l2h <= '1' when (spi_cs_ss_del = '0' and spi_cs_ss = '1') else '0';
ALL the methods work perfectly in simulation but not when downloaded on the FPGA. I wrote a process to monitor the transitions more closely (to monitor metastable values, if any):
led_test: process(spi_cs_h2l, spi_cs_l2h)
begin
if spi_cs_h2l = '1' or spi_cs_l2h = '1' then
leds <= "111100" & spi_cs_h2l & spi_cs_l2h;
elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or
spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then
leds <= "00001111";
else
leds <= "10101010";
end if;
end process led_test;
The leds are always "10101010" i.e is the else case where both spi_cs_h2l and spi_cs_l2h are = '0'. What am I missing ??
Any pointers would be very helpful as I am stuck with this issue since many days.
UPDATE
Using method 3 of clock domain crossing (as suggested by Jeff), and by initializing all the leds and signals to zero, the process to light up the leds is changed as follows:
led_test: process(spi_cs_h2l)
begin
if rising_edge(clk) then
if spi_cs_h2l = '1' then
leds <= "11110011";
end if;
end if;
end process led_test;
At least one high to low transition of the chip select pin is expected to light up the leds. The SPI chip select pin is receiving a '1' always and when FPGA is started/reset, the leds light up.
How is this possible? How can this false high to low transition occur ?
Method 1
This does not perform any sort of clock domain crossing on the spi_cs signal, and so is not a reliable circuit.
Method 2
The line if (spi_cs = '0' or spi_cs = '1') then is always true in the synthesised design, I wouldn't expect you to be able to detect an edge using this
Method 3
This does provide clock domain crossing for spi_cs, and in general looks pretty good. The reason you see "10101010" on your LEDs, is because they only show something different to this for one clk period at a time, at the start or end of an SPI transaction. This is probably much faster than you can see with the naked eye on the LEDs.
Additionally, the line elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then will not translate into any real hardware in the FPGA, because the real hardware does not have a way to check for 'U', 'Z', etc.
Method 3 update
It sounds like spi_cs is actually active low. You need to make sure that the initial values for your signals like spi_cs_s and spi_cs_ss are all correct. In this case, I think you should initialise them all to '1', as this seems to be the normal state for spi_cs. So your signal declarations would look like signal spi_cs_s : std_logic := '1'. You should be able to see this behaving properly in simulation.

Good Counter Design or Possible Metastability Issues?

Quick summary of my goal:
Design a counter triggered by a variable length auto-reload timer.
A little more verbose: There will be a register with a value that changes (predictably changes, and is latched before the EN signal for the AutoReloadTimer module) that sets the rate at which the counter increments.
Here's the auto-reload timer:
module AutoReloadTimer( clk, rst, EN, D, done );
input clk;
input rst;
input EN;
input [WIDTH-1:0] D;
output done;
parameter WIDTH = 8;
// OneShot EN -> load
wire load;
OneShotD OneShot_D(
.clk( clk ),
.rst( rst ),
.in( EN ),
.RE( load )
);
reg [WIDTH-1:0] counter, load_value;
always #( posedge clk ) begin
if ( rst ) begin
counter <= {WIDTH{1'b1}};
load_value <= {WIDTH{1'b1}};
end else if ( load ) begin
counter <= D;
load_value <= D;
end else if (counter == 0 ) begin
counter <= load_value;
load_value <= load_value;
end else begin
counter <= counter - 1'b1;
load_value <= load_value;
end
end
assign done = ( counter == 0 );
endmodule
And here is the counter triggered by the done signal from the AutoReloadTimer module:
module Counter( clk, rst, EN, CLR, Q );
input clk;
input rst;
input EN;
input CLR;
output [WIDTH-1:0] Q;
parameter WIDTH = 8;
reg [WIDTH-1:0] ctr;
always #( posedge clk ) begin
if ( rst ) begin
ctr <= {WIDTH{1'b0}};
end else if ( CLR ) begin
ctr <= {WIDTH{1'b0}};
end else if ( EN ) begin
ctr <= ctr + 1'b1;
end else begin
ctr <= ctr;
end
end
assign Q = ctr;
endmodule
And here is a portion of the waveform from a testbench:
What I'm curious about here is my counter's stability - is it an issue that the done signal goes low at the rising edge of the clock? I'm still fairly new to Verilog and digital design. I'm familiar with the term and somewhat the idea of metastability but I'm not fully comfortable with my understanding of it.
Looking for input, criticism, etc.
Edit
I forgot to include what configuration I had the modules in to produce that diagram:
wire ART_done;
AutoReloadTimer ART0 (
.clk( clk ),
.rst( rst ),
.EN( EN ),
.D( 4 ),
.done( ART_done )
);
Counter uut (
.clk(clk),
.rst(rst),
.EN(ART_done),
.CLR(CLR),
.Q(Q)
);
As long as your AutoReloadTimer and Counter modules, as well as any logic that uses the done signal are on the same clock, you won't have any metastability issues. What you would have is a fully synchronous implementation. Naturally, you must also meet the timing requirements of the device your using
The done signal will actually change some small combinatorial path delay after the rising clock edge that causes the counter to hit 0. Any logic that uses the done signal has the rest of the clock period before the next rising edge, to do what it needs to do (more combinatorial logic) and still meet the setup time of any register input that is conditioned by the done signal.
The metastability issues will only arise if the input to any registers are transitioning right as the clock is transitioning. This can happen if the data that's being registered is coming from a register that uses an asynchronous clock, or if the register's setup or hold timing is violated.

VHDL - How should I create a clock in a testbench?

How should I create a clock in a testbench? I already have found one answer, however others on stack overflow have suggested that there are alternative or better ways of achieving this:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test_tb IS
END test_tb;
ARCHITECTURE behavior OF test_tb IS
COMPONENT test
PORT(clk : IN std_logic;)
END COMPONENT;
signal clk : std_logic := '0';
constant clk_period : time := 1 ns;
BEGIN
uut: test PORT MAP (clk => clk);
-- Clock process definitions( clock with 50% duty cycle is generated here.
clk_process :process
begin
clk <= '0';
wait for clk_period/2; --for 0.5 ns signal is '0'.
clk <= '1';
wait for clk_period/2; --for next 0.5 ns signal is '1'.
end process;
END;
(source here)
My favoured technique:
signal clk : std_logic := '0'; -- make sure you initialise!
...
clk <= not clk after half_period;
I usually extend this with a finished signal to allow me to stop the clock:
clk <= not clk after half_period when finished /= '1' else '0';
If you use a std_logic item for your finished signal, it can be driven from all the items in your test environment:
signal finished : std_logic;
....
stimulus_process:process
begin
finished <= '0';
drive_various_signals_sync_with_clk;
finished <= '1';
end process;
monitor_process:process
begin
finished <= '0';
check_all_signals_until_all_tests_complete;
finished <= '1';
end process;
Then the clock only stops after all elements have finishde. And when there are no more transactions (on signals) scheduled, your simulation will stop cleanly.
Gotcha alert:
Care needs to be taken if you calculate half_period from another constant by dividing by 2. The simulator has a "time resolution" setting, which often defaults to nanoseconds... In which case, 5 ns / 2 comes out to be 2 ns so you end up with a period of 4ns! Set the simulator to picoseconds and all will be well (until you need fractions of a picosecond to represent your clock time anyway!)
If multiple clock are generated with different frequencies, then clock generation can be simplified if a procedure is called as concurrent procedure call. The time resolution issue, mentioned by Martin Thompson, may be mitigated a little by using different high and low time in the procedure. The test bench with procedure for clock generation is:
library ieee;
use ieee.std_logic_1164.all;
entity tb is
end entity;
architecture sim of tb is
-- Procedure for clock generation
procedure clk_gen(signal clk : out std_logic; constant FREQ : real) is
constant PERIOD : time := 1 sec / FREQ; -- Full period
constant HIGH_TIME : time := PERIOD / 2; -- High time
constant LOW_TIME : time := PERIOD - HIGH_TIME; -- Low time; always >= HIGH_TIME
begin
-- Check the arguments
assert (HIGH_TIME /= 0 fs) report "clk_plain: High time is zero; time resolution to large for frequency" severity FAILURE;
-- Generate a clock cycle
loop
clk <= '1';
wait for HIGH_TIME;
clk <= '0';
wait for LOW_TIME;
end loop;
end procedure;
-- Clock frequency and signal
signal clk_166 : std_logic;
signal clk_125 : std_logic;
begin
-- Clock generation with concurrent procedure call
clk_gen(clk_166, 166.667E6); -- 166.667 MHz clock
clk_gen(clk_125, 125.000E6); -- 125.000 MHz clock
-- Time resolution show
assert FALSE report "Time resolution: " & time'image(time'succ(0 fs)) severity NOTE;
end architecture;
The time resolution is printed on the terminal for information, using the concurrent assert last in the test bench.
If the clk_gen procedure is placed in a separate package, then reuse from test bench to test bench becomes straight forward.
Waveform for clocks are shown in figure below.
An more advanced clock generator can also be created in the procedure, which can adjust the period over time to match the requested frequency despite the limitation by time resolution. This is shown here:
-- Advanced procedure for clock generation, with period adjust to match frequency over time, and run control by signal
procedure clk_gen(signal clk : out std_logic; constant FREQ : real; PHASE : time := 0 fs; signal run : std_logic) is
constant HIGH_TIME : time := 0.5 sec / FREQ; -- High time as fixed value
variable low_time_v : time; -- Low time calculated per cycle; always >= HIGH_TIME
variable cycles_v : real := 0.0; -- Number of cycles
variable freq_time_v : time := 0 fs; -- Time used for generation of cycles
begin
-- Check the arguments
assert (HIGH_TIME /= 0 fs) report "clk_gen: High time is zero; time resolution to large for frequency" severity FAILURE;
-- Initial phase shift
clk <= '0';
wait for PHASE;
-- Generate cycles
loop
-- Only high pulse if run is '1' or 'H'
if (run = '1') or (run = 'H') then
clk <= run;
end if;
wait for HIGH_TIME;
-- Low part of cycle
clk <= '0';
low_time_v := 1 sec * ((cycles_v + 1.0) / FREQ) - freq_time_v - HIGH_TIME; -- + 1.0 for cycle after current
wait for low_time_v;
-- Cycle counter and time passed update
cycles_v := cycles_v + 1.0;
freq_time_v := freq_time_v + HIGH_TIME + low_time_v;
end loop;
end procedure;
Again reuse through a package will be nice.
Concurrent signal assignment:
library ieee;
use ieee.std_logic_1164.all;
entity foo is
end;
architecture behave of foo is
signal clk: std_logic := '0';
begin
CLOCK:
clk <= '1' after 0.5 ns when clk = '0' else
'0' after 0.5 ns when clk = '1';
end;
ghdl -a foo.vhdl
ghdl -r foo --stop-time=10ns --wave=foo.ghw
ghdl:info: simulation stopped by --stop-time
gtkwave foo.ghw
Simulators simulate processes and it would be transformed into the equivalent process to your process statement. Simulation time implies the use of wait for or after when driving events for sensitivity clauses or sensitivity lists.
How to use a clock and do assertions
This example shows how to generate a clock, and give inputs and assert outputs for every cycle. A simple counter is tested here.
The key idea is that the process blocks run in parallel, so the clock is generated in parallel with the inputs and assertions.
library ieee;
use ieee.std_logic_1164.all;
entity counter_tb is
end counter_tb;
architecture behav of counter_tb is
constant width : natural := 2;
constant clk_period : time := 1 ns;
signal clk : std_logic := '0';
signal data : std_logic_vector(width-1 downto 0);
signal count : std_logic_vector(width-1 downto 0);
type io_t is record
load : std_logic;
data : std_logic_vector(width-1 downto 0);
count : std_logic_vector(width-1 downto 0);
end record;
type ios_t is array (natural range <>) of io_t;
constant ios : ios_t := (
('1', "00", "00"),
('0', "UU", "01"),
('0', "UU", "10"),
('0', "UU", "11"),
('1', "10", "10"),
('0', "UU", "11"),
('0', "UU", "00"),
('0', "UU", "01")
);
begin
counter_0: entity work.counter port map (clk, load, data, count);
process
begin
for i in ios'range loop
load <= ios(i).load;
data <= ios(i).data;
wait until falling_edge(clk);
assert count = ios(i).count;
end loop;
wait;
end process;
process
begin
for i in 1 to 2 * ios'length loop
wait for clk_period / 2;
clk <= not clk;
end loop;
wait;
end process;
end behav;
The counter would look like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- unsigned
entity counter is
generic (
width : in natural := 2
);
port (
clk, load : in std_logic;
data : in std_logic_vector(width-1 downto 0);
count : out std_logic_vector(width-1 downto 0)
);
end entity counter;
architecture rtl of counter is
signal cnt : unsigned(width-1 downto 0);
begin
process(clk) is
begin
if rising_edge(clk) then
if load = '1' then
cnt <= unsigned(data);
else
cnt <= cnt + 1;
end if;
end if;
end process;
count <= std_logic_vector(cnt);
end architecture rtl;
Related: https://electronics.stackexchange.com/questions/148320/proper-clock-generation-for-vhdl-testbenches

Design for assingning output with the counted value of clock on some condition in VHDL

I'm new to VHDL and confused with this design
when Acknwledgement= '1' and clk='1' then
count should be count+1;
and when Acknwledgement= '0' my total counted value of clocks should be assigned to the 'output' and after that resetting count='0' and output='0'.
can anyone help with this.
Thanks in advance.
EDIT:
Code from comment pasted in:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity acknw is
port (acknw : in std_logic;
clk : in std_logic;
output : out integer range 0 to 15);
end acknw;
architecture Behavioral of acknw is
begin
process(clk, acknw) variable c : integer range 0 to 15;
begin
if(clk'event and clk = '1') then
if(acknw = '1') then
c := c+1;
output <= c;
else
c := 0;
output <= c;
end if;
end if;
end process;
end Behavioral;
from your comment it sounds like you want an asynchronous acknw, try something like this:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity acknw is
port (acknw : in std_logic;
clk : in std_logic;
output : out integer range 0 to 15);
end acknw;
architecture Behavioral of acknw is
begin
process(clk, acknw)
begin
if (acknw = '0') then
output <= 0;
elsif rising_edge(clk) then
-- rollover
if (output /= 15) then
output <= output + 1;
else
output <= 0;
end if;
end if;
end process;
end Behavioral;

Is there a better way to re-write a BCD_counter in VHDL code with less "if-statement"?

I am just beginning to learn VHDL in modelsim, so i apologize in advance if what I'm doing seems really noob.
Basically what i am trying to create is a synthesizable VHDL code for a one-digit up/down BCD counter. The counter will count when "Enable" is '1', or else it stays the same. When input "Init" is initialized, the counter is set to 0 or 9 depending on the value of "Direction" input. (When "Direction" is '1', it is an up counter).
I'm just wondering if there are better tools to use for this to work other than using 100 if and else in a row.
Here is my code, I am writing a test bench for it right now, so I am not yet sure if this will even work. So if you happen to also spot some mistake please point it out for me.
Thanks a lot in advance, and here is my code
entity BCD_counter is
port(clk, direction, init, enable: in bit;
q_out: out integer);
end entity BCD_counter;
architecture behaviour of BCD_counter is
signal q: integer;
begin
process(clk)
begin
if(Clk'event and Clk = '1') then
if(direction = '1') then -- counting up
if(init = '1')then --initialize
q<=0; -- reset to 0
else
if(enable = '1')then -- counting
if (q<9) then
q<=q+1;
else
q<=0;
end if;
else
q<=q;
end if;
end if;
elsif(direction = '0') then --counting down
if(init = '1') then --initialize
q<=9; --reset to 9
else
if(enable = '1') then --counting
if (q>0) then
q<=q-1;
else
q<=9;
end if;
else
q<=q;
end if;
end if;
end if;
end if;
end process;
q_out <= q;
end architecture behaviour;
Slightly different style, but this is how I would write it
architecture behaviour of BCD_counter is
signal next_q : integer;
signal q : integer;
begin
pReg : process
begin -- process pReg
wait until clk'event and clk = '1';
if init = '1' then
q <= 0;
else
q <= next_q;
end if;
end process pReg;
pCount : process (direction, enable, q)
begin -- process pCount
next_q <= q;
if enable = '1' then
if direction = '1' then
next_q <= q + 1;
if q = 9 then
next_q <= 0;
end if;
else
next_q <= q - 1;
if q = 0 then
next_q <= 9;
end if;
end if;
end if;
end process pCount;
q_out <= q;
end architecture behaviour;
Points to note:
The register behaviour is in a separate process from the logic. I find this style is clean. Others have different opinions which normally come down to not liking having next_blah signals.
init is your reset signal, so it overrides everything else, and I put reset signals in the register process.
The first line of the counter process is what I want to happen by default. In this case it says have the next state of q be the current state.
I have the outer if be the check of enable. If we're not enabled we don't do anything, so why check direction first?
Inside each half of the direction condition the code structure is the same. Set-up what I want the normal case to be, and then check for the exception to the rule. For example: if we're going up, I set the next state to be q+1, but if q is 9 I override it with q <= 0.
I'm not using >, < in any comparisons. These are more expensive than =, and = is just fine.
Alternatively you could take the enable into the register process. It's slightly shorter, and possibly clearer. It also makes it obvious that you're expecting to use the enable pin of a register for this function.
pReg : process
begin -- process pReg
wait until clk'event and clk = '1';
if init = '1' then
q <= 0;
else
if enable = '1' then
q <= next_q;
end if;
end if;
end process pReg;
pCount : process (direction, q)
begin -- process pCount
if direction = '1' then
next_q <= q + 1;
if q = 9 then
next_q <= 0;
end if;
else
next_q <= q - 1;
if q = 0 then
next_q <= 9;
end if;
end if;
end process pCount;
The only thing that comes to my mind is that you could ommit the two
else
q<=q;
statements because this is implicitly done if none of the other conditions check out.
I do a lot of this - I created a function called modulo_increment which takes an input integer, and "modulus" integer and returns the wrapped around value.
so you can then do
q <= modulo_increment(q, 10);