Task: Designing a 8-bit downcounter which takes an initial input value and start the downcount, and when count becomes 8'b0000_0000, it should automatically set to input value.
Ex: If given input is 8'b10010100, counter should start counting down, when value reaches 8'00000000, it should automatically reset to 8'b10010100, and again start downcount repeatedly.
For this had written a modified D flip flop using behavioral method, which works as follows:
When ld=0, output of d-flip flop q=d1 and q_bar=~d1
and when ld=1, q=d2 and q_bar=~d2
Here d2 stores the initial input values, and ld is being used as switch, i.e. when q=8'b00000000, ld=1 and sets counter output q=d2 and next cycle, ld=0 and takes d1 value.
Modified D-flip flop
module modified_d_flip_flop(q,q_bar,d1,d2,clk,ld
);
input d1,d2,clk,ld;
output q,q_bar;
reg q,q_bar;
always #(posedge clk)
begin
if(ld==0)
begin
q<=d1;
q_bar<=~d1;
end
else if(ld==1)
begin
q<=d2;
q_bar<=~d2;
end
else
begin
q<=q;
q_bar<=q_bar;
end
end
endmodule
Down Counter:
module down_counter(
input [7:0] d,
input clk,
input ld,
output [7:0] q,
output [7:0] q_bar
);
modified_d_flip_flop m_dff1 (.q(q[0]), .q_bar(q_bar[0]), .d1(q_bar[0]), .d2(d[0]), .clk(clk), .ld(ld));
modified_d_flip_flop m_dff2 (.q(q[1]), .q_bar(q_bar[1]), .d1(q_bar[1]), .d2(d[1]), .clk(q[0]), .ld(ld));
modified_d_flip_flop m_dff3 (.q(q[2]), .q_bar(q_bar[2]), .d1(q_bar[2]), .d2(d[2]), .clk(q[1]), .ld(ld));
modified_d_flip_flop m_dff4 (.q(q[3]), .q_bar(q_bar[3]), .d1(q_bar[3]), .d2(d[3]), .clk(q[2]), .ld(ld));
modified_d_flip_flop m_dff5 (.q(q[4]), .q_bar(q_bar[4]), .d1(q_bar[4]), .d2(d[4]), .clk(q[3]), .ld(ld));
modified_d_flip_flop m_dff6 (.q(q[5]), .q_bar(q_bar[5]), .d1(q_bar[5]), .d2(d[5]), .clk(q[4]), .ld(ld));
modified_d_flip_flop m_dff7 (.q(q[6]), .q_bar(q_bar[6]), .d1(q_bar[6]), .d2(d[6]), .clk(q[5]), .ld(ld));
modified_d_flip_flop m_dff8 (.q(q[7]), .q_bar(q_bar[7]), .d1(q_bar[7]), .d2(d[7]), .clk(q[6]), .ld(ld));
endmodule
Down counter Test Bench
module down_counter_tb;
reg [7:0] d;
reg clk;
reg ld;
wire [7:0] q;
wire [7:0] q_bar;
down_counter uut (
.d(d),
.clk(clk),
.ld(ld),
.q(q),
.q_bar(q_bar)
);
always #5 clk = ~clk;
initial begin
clk = 1;
ld = 1;
d = 8'b00000111;
end
initial begin
#20 ld = 0;
#20 ld = 1;
#30 ld = 0;
end
endmodule
Issue:
If initial input i.e. d2=8'b11111111, then i am getting the downcounter it works properly for the above code,
But if i give some thing like d2=8'10010011, then counter starts from 011, 010, 001 and 111, 110, 101, ........
it counts only the number of high bits from lsb + 1, if 0 is encountered next values till msb becomes x.
enter image description here
enter image description here
enter image description here
ld function too is not working as expected, when ld=0 instead of reset counter to initial input, it stops counter and starts it once ld=0.
Your code is too hard to debug because you are not designing at the proper level of abstraction. You should always use the highest level of abstraction to make the design easier to understand. Instead of designing an individual flip-flop then trying to connect them together, just design a simple counter.
With all those module instance connections, you may have a simple connection bug.
Another potential issue is a simulation race condition. Every flip-flop uses a different clock signal.
Here is a common way to design a synchronous counter. It uses the same clock for all flops of the counter:
module down_counter (
input [7:0] d,
input clk,
input ld,
output reg [7:0] q
);
always #(posedge clk) begin
if (ld || (q == 0)) begin
q <= d;
end else begin
q <= q - 1;
end
end
endmodule
module down_counter_tb;
reg [7:0] d;
reg clk;
reg ld;
wire [7:0] q;
down_counter uut (
.d(d),
.clk(clk),
.ld(ld),
.q(q)
);
always #5 clk = ~clk;
initial begin
clk = 1;
ld = 1;
d = 7;
repeat (2) #(posedge clk);
ld <= 0;
repeat (15) #(posedge clk);
ld <= 0;
d <= 8'b1001_0011;
repeat (1) #(posedge clk);
ld <= 0;
repeat (500) #(posedge clk);
$finish;
end
endmodule
By using nonblocking assignments (<=) and driving the inputs on #(posedge clk) in the testbench (as is done in the design), we also avoid race conditions in the testbench.
You didn't provide a thorough description of the ld signal. The code I showed loads the counter with the 8-bit input data (d) when ld=1. When ld=0, the counter counts down. When it reaches 0, the counter is automatically reloaded with d.
Thanks #toolic
You code surely gave me an idea. Modified it a little to solve my issue
I am trying to design a frequency divider for my project for that i needed this downcounter.
ld - Use was to make the counter reset to my expected value when ld=0 and again make ld=1 next cycle to start the downcount and again when downcounter value became 0, make ld=0 to reset the counter to expected value. This had to go on forever.
In your testbench we have to set it many times.
I just wanted to give one initial value and i wanted it to run forever.
I modified your code, to get my desired result.
I removed ld and added, initial q = 0
Down Counter
module down_counter(
input [7:0] d,
input clk,
output reg [7:0] q
);
initial q = 0;
always #(posedge clk)
begin
if (q == 0)
begin
q <= d;
end
else
begin
q <= q-1;
end
end
endmodule
Testbench:
module down_counter_tb;
// Inputs
reg [7:0] d;
reg clk;
// Outputs
wire [7:0] q;
// Instantiate the Unit Under Test (UUT)
down_counter uut (
.d(d),
.clk(clk),
.q(q)
);
always #5 clk=~clk;
initial begin
// Initialize Inputs
d = 8'b00000100;
clk = 1;
end
endmodule
Waveform:
Related
This is the module that I'm trying to implement. What I want to do is, receive a vector say 2 bits wide having 4 elements that I linearize and pass from the testbench to the test_module1. Now I want to de-linearize it and perform some combinational operations on it to get a fitness value based on Rosenbrock function. However, I get the fitness value as XX.
I'm unable to understand the issue here.
module test_module1 ( x, fitness);
input [4*2 -1:0] x;
output [1:0] fitness;
wire [1:0] x_i;
wire [1:0] x_im1;
wire [1:0] fitness_val = 2'b00;
wire [3:0] a;
wire [3:0] b;
wire [1:0] x_array1 [3:0];
genvar k;
assign fitness = fitness_val;
genvar j;
generate
for (j =0 ; j <4 ; j = j+1) begin
assign x_array1[j] = x[2*j +: 2];
end
for (k=1; k<4; k=k+1) begin
assign x_i = x_array1[k];
assign x_im1 = x_array1[k-1];
assign a = 100*(x_i[1:0] - x_im1[1:0])*(x_i[1:0] - x_im1[1:0]);
assign b = (1 - x_im1[1:0])*(1 - x_im1[1:0]);
assign fitness_val = fitness_val + a[2:1] + b[2:1];
end
endgenerate
endmodule
Testbench:
module tb_tm1();
wire [1:0] fitness;
wire [4*2-1:0] x_array;
test_module1 tm1(x_array, fitness);
assign x_array = 8'b11100100;
endmodule
The output I get is like this:
The cause of the X (unknown value) is due to contention caused by multiple drivers for the same signal.
For example, signal fitness_val has 5 drivers. The 1st is the line:
wire [1:0] fitness_val = 2'b00;
This is a continuous assignment, which means the simulator is always trying to drive it to 0. The other 4 drivers are from the for k loop:
assign fitness_val = fitness_val + a[2:1] + b[2:1];
If you were to write out the loop long-hand, you would have 4 identical assign lines. fitness_val should only have 1 driver, not 5.
You have multiple drivers of all 5 signals in that for loop.
Another problem with the assign fitness_val line is that it creates a combinational loop. You should not have fitness_val on both the LHS and RHS of a continuous assignment.
I've written a simple DFF with the following VHDL code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity DFF is
port (d: in STD_LOGIC;
q: out STD_LOGIC;
clk: in STD_LOGIC;
reset: in STD_LOGIC);
end DFF;
architecture Behavioral of DFF is
begin
process (reset, clk) begin
if (reset = '1') then
q <= '0';
elsif (rising_edge(clk)) then
q <= d;
end if;
end process;
end Behavioral;
I subsequently run simulation and synthesis. When I examine the synthesis report, in the Timing Report section, this is present:
=========================================================================
Timing constraint: Default OFFSET OUT AFTER for Clock 'clk'
Total number of paths / destination ports: 1 / 1
-------------------------------------------------------------------------
Offset: 3.597ns (Levels of Logic = 1)
Source: q (FF)
Destination: q (PAD)
Source Clock: clk rising
Data Path: q to q
Gate Net
Cell:in->out fanout Delay Delay Logical Name (Net Name)
---------------------------------------- ------------
FDC:C->Q 1 0.447 0.579 q (q_OBUF)
OBUF:I->O 2.571 q_OBUF (q)
----------------------------------------
Total 3.597ns (3.018ns logic, 0.579ns route)
(83.9% logic, 16.1% route)
=========================================================================
What does the q to q data path signify, and what does it even mean?
I'm trying to understand the following Verilog code for D-FlipFlop with asynchronous reset:
module dff ( input d, input rstn, input clk, output reg q);
always # (posedge clk or negedge rstn)
if (!rstn) q <= 0;
else q <= d;
endmodule
I think at the negative edge of rstn, the value of rstn is unstable. It can be 0 or 1 or x. Then why can we use this unstable value in the next line of code if (!rstn)?
I was wondering if its possible to directly compare 2 vectors with eachother instead of just looking at them bit by bit.
For example:
entity Comparator is
port(a,b in: std_logic_vector (2 downto 0);
out1, out2 out: std_logic);
end Comparator;
architecture behavioural of Comparator1 is
begin
if a = b then
out1 <= '1'
else if /= then
out2 <= '1'
end if;
end behaviour;
Is this possible?
The answer is yes, you can compare two array types of the same type and subtype indication directly.
However your example code isn't valid.
The result of the expression a=b is boolean. You convert that to std_logic by assigning out1 and out2. An if statement in this context has to be in a process statement. Also you don't need two outputs:
architecture foo of Comparator1 is
begin
UNLABELED:
process (a,b)
begin
if a = b then
out1 <= '1';
else
out1 <= '0';
end if;
end process;
end architecture;
Alternative a concurrent signal assignment statement, a conditional signal assignment that has an equivalent process to that above:
architecture fum of Comparator1 is
begin
UNLABELED:
out1 <= '1' when a = b else '0';
end architecture;
You can also use to_integer(unsigned(a)) and threat them as integers.
For example:
IF(to_integer(unsigned(a)) < to_integer(unsigned(b))) THEN
If I have an unsigned(MAX downto 0) containing the value 2**MAX - 1, do the VHDL (87|93|200X) standards define what happens when I increment it by one? (Or, similarly, when I decrement it by one from zero?)
Short answer:
There is no overflow handling, the overflow carry is simply lost. Thus the result is simply the integer result of your operation modulo 2^MAX.
Longer answer:
The numeric_std package is a standard package but it is not is the Core the VHDL standards (87,93,200X).
For reference : numeric_std.vhd
The + operator in the end calls the ADD_UNSIGNED (L, R : unsigned; C : std_logic) function (with C = '0'). Note that any integer/natural operand is first converted into an unsigned.
The function's definition is:
function ADD_UNSIGNED (L, R : unsigned; C : std_logic) return unsigned is
constant L_left : integer := L'length-1;
alias XL : unsigned(L_left downto 0) is L;
alias XR : unsigned(L_left downto 0) is R;
variable RESULT : unsigned(L_left downto 0);
variable CBIT : std_logic := C;
begin
for i in 0 to L_left loop
RESULT(i) := CBIT xor XL(i) xor XR(i);
CBIT := (CBIT and XL(i)) or (CBIT and XR(i)) or (XL(i) and XR(i));
end loop;
return RESULT;
end ADD_UNSIGNED;
As you can see an "overflow" occurs if CBIT='1' (carry bit) for i = L_left. The result bit RESULT(i) is calculated normally and the last carry bot value is ignored.
I've had the problem with wanting an unsigned to overflow/underflow as in C or in Verilog and here is what I came up with (result and delta are unsigned):
result <= unsigned(std_logic_vector(resize(('1' & result) - delta, result'length))); -- proper underflow
result <= unsigned(std_logic_vector(resize(('0' & result) + delta, result'length))); -- proper overflow
For overflow '0' & result makes an unsigned which is 1 bit larger to be able to correctly accommodate the value of the addition. The MSB is then removed by the resize command which yields the correct overflow value. Same for underflow.
For a value of MAX equal to 7 adding 1 to 2**7 - 1 (127) will result in the value 2**7 (128).
The maximum unsigned value is determined by the length of an unsigned array type:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity foo is
end entity;
architecture faa of foo is
constant MAX: natural := 7;
signal somename: unsigned (MAX downto 0) := (others => '1');
begin
UNLABELED:
process
begin
report "somename'length = " & integer'image(somename'length);
report "somename maximum value = " &integer'image(to_integer(somename));
wait;
end process;
end architecture;
The aggregate (others => '1') represents a '1' in each element of somename which is an unsigned array type and represents the maximum binary value possible.
This gives:
foo.vhdl:15:9:#0ms:(report note): somename'length = 8
foo.vhdl:16:9:#0ms:(report note): somename maximum value = 255
The length is 8 and the numerical value range representable by the unsigned array type is from 0 to 2**8 - 1 (255), the maximum possible value is greater than 2**7 (128) and there is no overflow.
This was noticed in a newer question VHDL modulo 2^32 addition. In the context of your accepted answer it assumes you meant length instead of the leftmost value.
The decrement from zero case does result in a value of 2**8 - 1 (255) (MAX = 7). An underflow or an overflow depending on your math religion.
Hat tip to Jonathan Drolet for pointing this out in the linked newer question.