BCD adder in Verilog (with gates) - logic

My goal is coding a BCD adder in Verilog with gates. I have some issues:
1- How can I select bits from first "four bit adders" outputs. My sum is S. After I used S in first adder, can I select bits like S[0] or is there another way?
2- How can I specify inputs, especially if I have a module for four_bit_adder and it takes one element like A (4 bits)? I tried to specify some bits, but I couldn't handle it.
For example, A[3] and A[1] needed to be 0 or 1 regarding the some situations, but my module takes one element.
My trial is below:
`include "four_bit_adder.v"
module bcd_adder(S,A,B,Cin);
input [3:0]A,B;
input Cin;
output [3:0]S;
wire [2:0]connectors;
//four_bit_adder(S,Cout,A,B,Cin);
four_bit_adder F_A1(S,Cout,A,B,Cin);
and(connectors[0],S[3],S[2]);
and(connectors[1],S[3],S[1]);
or(connectors[2],connectors[1],connectors[0],Cout);
//four_bit_adder F_A2();
endmodule

I added a Cout output to your bcd_adder, driven by your or gate. I changed connectors to [1:0].
I created a wire for the binary sum (sumb), driven by your 1st 4-bit adder. This is different from your BCD sum S. sumb is connected to the A input of the 2nd 4-bit adder.
For the B input to the 2nd adder, I concatenate 4 bits like this:
{1'b0,Cout,Cout,1'b0}
Here is the completed module:
module bcd_adder(S,Cout,A,B,Cin);
input [3:0]A,B;
input Cin;
output [3:0]S;
output Cout;
wire [1:0]connectors;
wire [3:0]sumb;
wire coutb;
wire cout2; // floating
four_bit_adder F_A1 (sumb,coutb,A,B,Cin);
four_bit_adder F_A2 (S,cout2,sumb,{1'b0,Cout,Cout,1'b0},1'b0);
and(connectors[0],sumb[3],sumb[2]);
and(connectors[1],sumb[3],sumb[1]);
or (Cout,connectors[1],connectors[0],coutb);
endmodule

Related

Assigning values to parametrized arrays in Verilog

Suppose I have the following module definition,
module foo(b)
input b;
parameter length = 8;
reg [length-1:0] dummy ;
Now, I want to assign values to this dummy array. For instance I want to make it all 1s. If the length was not parameterized, I could do this,
always #(posedge b)
dummy <= 8'hFF;
But when the length is parameterized, I would hope to do this,
always #(posedge b)
dummy <= length'hFFFF //won't even compile. even if it did, how many F's should there be?
How can I assign ones (or zeroes) to an entire array whose length is parameterized? Or more generally, how can I assign values while specifing the length of a parameterized array?
You can do bit extension:
always # (posedge b)
dummy <= {length{1'b1}};
What is inside the {} is extended by "parameter-1", would be the same as having:
always # (posedge b)
dummy <= {1'b1,1'b1,1'b1,1'b1....};
You can write
always #(posedge b)
dummy <= ~1'b0;
This takes advantage of the fact that Verilog extends operands before applying operators when they are in context-determined expressions.
In SystemVerilog, you can write
always #(posedge b)
dummy <= '1;

VHDL/Verilog - Does a math operation in a range statement get snythesized?

Say you have the following code,
signal a : std_logic_vector( N - 1 downto 0 );
Or,
for i in 0 to N - 1
...
Does the N-1 part get synthesized into actual logic, or does the FPGA software (e.g. Quartus) do the math before creating the logic?
Example use case, say generic N represents the number of desired bits. Is it better to have a generic Nm1 which holds the subtraction, or can I get by using N-1 as above without it creating additional logic?
As N is a generic parameter, it is considered as a constant at synthesis time. Your logic synthesizer, as all logic synthesizers I know, will propagate constants before inferring any piece of hardware. The synthesizer will compute the N-1 expression before synthesis and this operation will not cost you any single transistor. It would be the same with a much more complex operation on constants like, for instance, calling a function. Example:
function log2_up(x: positive) return natural is
begin
if x = 1 then
return 0;
else
return log2_up((x+1)/2) + 1;
end if;
end function log2_up;
...
constant word_width: positive := 64;
constant write_byte_enable_width: positive := log2_up(64 / 8);
is synthesizable by all logic synthesizers I know and computing write_byte_enable_width does not cost a single transistor; it is computed beforehand by the synthesizer during the constant propagation phase.
In both of these cases, the value of N would have to be calculated at compile time. It isn't -- and cannot be! -- generated in logic.
Keep in mind that any HDL code ultimately has to be able to synthesize to physical hardware. Changing the number of bits in a signal, or changing the number of times some logic is instantiated, isn't something that can be done electronically.

Calculating the Overflow Flag in an ALU

First of all, forgive me if this isn't the right place to post this question, but I wasn't sure where it should go. I am currently working on simulating an ALU in Xilinx with VHDL. The ALU has the following inputs and outputs:
Inputs
A and B: two 8-bit operands
Ci: single-bit carry in
Op: 4-bit opcode for the multiplexers
Outputs
Y: 8-bit output operands
Co: single-bit carry out
V: overflow flag (1 if there is overflow, 0 otherwise)
Z: zero flag (1 if zero, 0 otherwise)
S: sign flag (1 if -ve, 0 if +ve)
The ALU performs the operations detailed in the table below:
I have implemented it using multiplexers and an adder, as illustrated in the diagram below:
My question is:
How do I calculate the value of the overflow flag, V?
I am aware that:
If adding a positive to a negative, overflow will not occur
If there is no carry/borrow, then the overflow can be calculated by evaluating the expression
(not A(7) and not B(7) and Y(7)) or (A(7) and B(7) and not Y(7))
where A(7), B(7) and Y(7) are the 8th bit of A, B and Y respectively.
In the case of a carry/borrow, There is an overflow if and only if the carry-in and carry-out of the most significant bit are different.
I don't know how to implement this logically in VHDL code however - especially in the case of a carry.
The solution you have posted
v <= (not A(7) and not B(7) and Y(7)) or (A(7) and B(7) and not Y(7))
is correct for addition of signed operands and independent of the carry.
EDIT To use this also for your substraction, you have to use the actual adder inputs instead, i.e.:
v <= (not add_A(7) and not add_B(7) and Y(7)) or (add_A(7) and add_B(7) and not Y(7))
The above will work both for addition and substraction is independent of carry or borrow. (By the way, for the real implementation you should use add_Y instead of Y to shorten critical paths.)
If you want to implement it by XOR'ing the carry-in and carry-out of the most-signifcant sum bit, then you have to calculate a partial sum of the lowest 7 bit first. This gives you access to carry-out of bit 6 which is the carry-in of bit 7. Then just append a full-adder to get bit 7 and the carry-out. Here is the code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity adder_overflow is
port (
a : in unsigned(7 downto 0);
b : in unsigned(7 downto 0);
y : out unsigned(7 downto 0);
v : out std_logic;
co : out std_logic);
end;
architecture rtl of adder_overflow is
signal psum : unsigned(7 downto 0); -- partial sum
signal c7_in : std_logic;
signal c7_out : std_logic;
begin
-- add lowest 7 bits together
psum <= ("0" & a(6 downto 0)) + b(6 downto 0);
-- psum(7) is the carry-out of bit 6 and will be the carry-in of bit 7
c7_in <= psum(7);
y(6 downto 0) <= psum(6 downto 0);
-- add most-signifcant operand bits and carry-in from above together using a full-adder
y(7) <= a(7) xor b(7) xor c7_in;
c7_out <= ((a(7) xor b(7)) and c7_in) or a(7);
-- carry and overflow
co <= c7_out;
v <= c7_in xor c7_out;
end rtl;
Your solution
(not A(7) and not B(7) and Y(7)) or (A(7) and B(7) and not Y(7))
and the text below it only apply to signed addition; it's not correct for subtraction. The two rules are:
Signed integer overflow of the expression x+y+c (where c is 0 or 1) occurs if and only if x and y have the same sign and the result has sign opposite to that of the operands (this is your equation), and
Signed integer overflow of the expression x-y-c (where c is again 0 or 1) occurs if and only if x and y have opposite signs, and the sign of the result is opposite to that of x (or, equivalently, the same as that of y).
Note that these are true whatever the value of the carry/borrow. You can see that the first rule doesn't apply for subtraction with a simple 4-bit example: 4 minus (-4), for example, must overflow because the answer should be +8, which isn't representable in 4 bits. In binary, this is 0100 - 1100 = 1000. This is an overflow acording to (2), but not (1).
The good news is that xor-ing the carry into the sign bit and the carry out of the sign bit always works - it's correct for addition and subtraction, and whether or not there's a carry- or a borrow-in, so you can use Martin's code.
You should get a copy of Henry Warren's Hacker's Delight if you're going to do much arithmetic. He covers all this, and much more.
Overflow occurs if the addition of two positive numbers gives a negative number and if the addition of two negative numbers gives a positive. That is, you need to compare the MSB of the operands and the answer. If the sign of the operands and the sign of the answer don't match, the overflow flag is turned on.
Edit: This only applies to situations where there is no carry. I need help too when it comes to additions with carry.

Confusion between Behavioural and Dataflow model Programs in VHDL

I'm using the textbook "VHDL: Programming By Example" by Douglas L Perry, Fourth Edition. He gave an example of the Dataflow programming model in page 4:
Code I:
ENTITY mux IS
PORT ( a, b, c, d : IN BIT;
s0, s1 : IN BIT;
x, : OUT BIT);
END mux;
ARCHITECTURE dataflow OF mux IS
SIGNAL select : INTEGER;
BEGIN
select <= 0 WHEN s0 = ‘0’ AND s1 = ‘0’ ELSE
1 WHEN s0 = ‘1’ AND s1 = ‘0’ ELSE
2 WHEN s0 = ‘0’ AND s1 = ‘1’ ELSE
3;
x <= a AFTER 0.5 NS WHEN select = 0 ELSE
b AFTER 0.5 NS WHEN select = 1 ELSE
c AFTER 0.5 NS WHEN select = 2 ELSE
d AFTER 0.5 NS;
END dataflow;
Now in page 17,
Code II
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY mux4 IS
PORT ( i0, i1, i2, i3, a, b : IN std_logic;
PORT ( i0, i1, i2, i3, a, q : OUT std_logic);
END mux4;
ARCHITECTURE mux4 OF mux4 IS
SIGNAL sel: INTEGER;
BEGIN
WITH sel SELECT
q <= i0 AFTER 10 ns WHEN 0,
q <= i1 AFTER 10 ns WHEN 1,
q <= i2 AFTER 10 ns WHEN 2,
q <= i3 AFTER 10 ns WHEN 3,
q <= ‘X’ AFTER 10 ns WHEN OTHERS;
sel <= 0 WHEN a = ‘0’ AND b = ‘0’ ELSE
1 WHEN a = ‘1’ AND b = ‘0’ ELSE
2 WHEN a = ‘0’ AND b = ‘1’ ELSE
3 WHEN a = ‘1’ AND b = ‘1’ ELSE
4;
END mux4;
This is supposed to be a behavioural model, as per the same textbook. Aside from the differences in variable name, the only major difference I see here is that there is an extra statement
WITH sel SELECT
in the second case, and small syntax differences. This Code II is concurrent. But from other sources in the internet(listed below), I've seen that a behavioural model is supposed to be sequential. Which one should I believe?
Now from some other sources of the internet, the definition of these models are as follows:
Behavioral – Circuit is described as an i/o relationship using sequential statements inside a process.
Dataflow – Circuit is described using concurrent statements
-San Jose State university
Behavioral – describes how the output is derived from the inputs using structured
statements.
Dataflow – describes how the data flows.
-University of Akron College of Engineering
Here I do not understand what structured statements mean.
in Behaviour level, process keyword is present
in dataflow level , concurrent statement (<=) is present
This was seen in an online forum.
Is process statement compulsory for Behavioural model?
What is the actual difference between codes I and II? According to the author, they have different models, dataflow and behavioural. I cannot see how this is possible. What should I believe?
Lastly, in Perry D L, Page 45, 46:
LIBRARY IEEE;
USE IEEE.std_logic_1164ALL;
ENTITY mux IS
PORT (i0, i1, i2, i3, a, b : IN std_logic;
PORT (q : OUT std_logic);
END mux;
ARCHITECTURE better OF mux IS
BEGIN
PROCESS ( i0, i1, i2, i3, a, b )
VARIABLE muxval : INTEGER;
BEGIN
muxval := 0;
IF (a = ‘1’) THEN
muxval := muxval + 1;
END IF;
IF (b = ‘1’) THEN
muxval := muxval + 2;
END IF;
CASE muxval IS
WHEN 0 =>
q <= I0 AFTER 10 ns;
WHEN 1 =>
q <= I1 AFTER 10 ns;
WHEN 2 =>
q <= I2 AFTER 10 ns;
WHEN 3 =>
q <= I3 AFTER 10 ns;
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS;
END better;
This is a sequential version of MUX. According to the other definitions, this is supposed to be behavioural, but the author does not state so. Could you clear up my confusion regarding these models?
Don't look for a mathematically rigorous description of these terms; they are a lot vaguer than that, loose classifications that can overlap.
"Dataflow" I think is fairly clear here; it DOES describe the flow of data, and it describes it in terms of concurrent statements. But I would add that each concurrent statement is woken by changes on its inputs and delivers its outputs; therefore (the important bit:) there is no correspondence between the order of things happening and the order of elements in the source code. In that respect it has a lot in common with functional programming. And both the first two models are dataflow; in (I) the elements are in logical order while (II) is not.
"Behavioural" SHOULD be fairly clear too - it simply describes a circuit in terms of its behaviour.
But it is not in general opposed to dataflow - though your San Jose quote is somewhat correct - behavioural descriptions are commonly sequential simply because the sequential paradigm (inside a VHDL process) is common and familiar to programmers. Even so, the behaviour of several such processes interacting with each other is ... dataflow.
Behavioral then is NOT correctly opposed to dataflow. It is more correctly opposed to RTL (Register Transfer Level) and structural which have fairly clear meanings.
A structural description consists of a number of building block (gates, multiplexers, entire CPUs) and the signals interconnecting them : a textual block diagram (perhaps auto-generated from a graphical one). As such it can be either the lowest level (see frequent questions here about making an adder out of gates!) or the highest level (connecting CPU to memory, peripherals, etc).
An RTL description is fairly low level; it describes the transfer and operations on data between storage elements (registers) and is common inside a process; it is rather like an assembly language listing from a (behavioural) C program.
Lastly - too many descriptions and too many extraneous details get in the way of doing a proper design job. Look at the task in hand, extract its essence, and implement that.
A multiplexer selects one of a collection of input elements according to the index of the element you want. The most natural form of index is usually an integer type, rarely including negative indices, and the most natural form of collection in VHDL is ... an array.
So why not write
ENTITY mux IS
PORT ( a, b, c, d : in BIT;
sel : in natural range 0 to 3;
x : out BIT);
END mux;
ARCHITECTURE simple OF mux IS
SIGNAL values : array (0 to 3) of BIT;
BEGIN
values <= a & b & c & d;
x <= values(sel); -- after 0.5 ns; if you need to model timing!
END simple;
or better, make "values" an input port...
There's a distinction between behavioral and structural implementations that isn't well explained in this particular book. Dataflow can be a poorly applied description to hardware based on who is trying to convey what.
I'd suspect this: Switching & Logic Laboratory Spring 2008 jeg 1 Lab 2 – Behavioral and Dataflow VHDL (PDF, 66KB, 12 pages) was provided to overcome confusion of those readers of the book like yourself:
Within VHDL we can describe the logic in three different manners.
These three different architectures are:
Behavioral – describes how the output is derived from the inputs using structured statements.
Dataflow – describes how the data flows from the inputs to the output most often using NOT, AND and OR operations.
Structural – describes how gates are interconnected similar to schematic approach.
Dataflow can imply concurrency, while neither behavioral or structural preclude either sequential or concurrent descriptions. All concurrent descriptions are converted to sequential processes for VHDL simulation, counting on delta simulation cycles to synchronize signal assignments emulating concurrency.
There's this concept of a design network in the simulator that reflects the design hierarchy like a schematic can be represented by a flat net list.
There are good reasons to use what's called Dataflow here, in that describing logic behavior with say 9 level logic (MVL9, used by package std_logic_1164) results in the propagation of unknowns ('X's) and uniintialized values ('U's). It brings closure between behavioral and structural models without hand waving around visible values you can't reconcile between the levels of abstraction, other than by exception. The stimulus and expected results are the same between Dataflow behavioral description and a structural implementation.
Speaking from experience, it's a lot easier up front to get the different levels of abstraction to match than to hear back from a foundry wanting to delay first silicon waiting on you to approve exceptions to the stimulus you provided, plus at least historically, the number of exceptions you could make on an IC tester was rather limited. You could think of real silicon on an IC tester as another level of abstraction.
For simulation different levels of abstraction in VHDL you basically write a behavioral model that behaves more closely to what a structural model would. A
I found the above PDF by googling for 'VHDL dataflow', which reveals many more sources of information.
Behavioral – describes how the output is derived from the inputs using
structured statements.
Dataflow – describes how the data flows.
-University of Akron College of Engineering
A dataflow model requires that you have a clear understanding of the dataflow(i.e. the physical circuit). However, when using a behavioral model, you only need to pay attention to the main behavior of the design. So a behavioral model is easier to understand and maintain. For example, to implement a parallel multiplier
dataflow model
You will need components like registers, FAUs, multiplexers, etc. And you are supposed to implement them all by yourself. That's terrible especilally when the input numbers are 16-bit or more.
behavioral model
All you need is to write down a statement like this:
p <= a * b;
Whether a model is a dataflow one or a behavioral one is determined by how you model the design. Sequential statements or concurrent statements? That doesn't matter.

binary number comparison

If I have a 32 bit two's complement number and I want to know what is the easiest way to know of two numbers are equal... what would be the fastest bitwise operator to know this? I know xor'ing both numbers and check if the results are zero works well... any other one's?
how about if a number is greater than 0?? I can check the 31'st bit to see if it's greater or equal to 0..but how about bgtz?
Contrary to your comments, '==' is part of Verilog, and unless my memory is a lot worse than usual tonight, it should synthesize just fine. Just for example, you could write something like:
// warning: untested, incomplete and utterly useless in any case.
// It's been a while since I wrote much Verilog, so my syntax is probably a bit off
// anyway (might well be more like VHDL than it should be).
//
module add_when_equal(clock, a, b, x, y, z);
input clock;
input [31:0] a, b, x, y;
output [31:0] z;
reg [31:0] a, b, x, y, z;
always begin: main
#(posedge clock);
if (a == b)
z <= x + y;
end
endmodule;
Verilog also supports the other comparison operators you'd normally expect (!=, <=, etc.). Synthesizers are fairly "smart", so something like x != 0 will normally synthesize to an N-input OR gate instead of a comparator.
// this should work as comparator for Equality
wire [31:0] Cmp1, Cmp2;
wire Equal;
assign Equal = &{Cmp1 ~^ Cmp2}; // using XNOR
assign Equal = ~|{Cmp1 ^ Cmp2}; // using XOR
if you can xor and then compare the result with zero then you can compare a result with some value and if you can compare something to a value then you can just compare the two values without using an xor and a 32 bit zero.

Resources