Calculating the Overflow Flag in an ALU - logic

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.

Related

vhdl signed and unsigned type endianess

I am writing a code in vhdl quite full of algebraic operations and I declared some signed variables (I know that there are better types, but I needed to reduce the bits used). I was wondering if it is better to declare them as
variable foo1 := signed (7 downto 0);
or
variable foo2 := signed (0 to 7);
I know it is related to endianess, but I am fairly confused. For example, if I declare
variable foo3 := signed (0 to 7) := "01100100";
Will it be interpreted as 100 or 38 in decimal? And if I have a condition on foo3 as
if (foo3(1) = '1') then
-- whatever you want
endif;
Will foo3(1) = '1' be true or false?
For consistency across VHDL's math packages, it is better to use downto.
variable foo1 : signed (7 downto 0);
This has nothing to do with numeric_std package. As with the numeric_std package, the leftmost element is always the most significant element, independent of whether you use downto or to. Also interesting with numeric_std, the value is in no way dependent on the indices - so (15 downto 8) works the same as (7 downto 0).
On the other hand, with VHDL-2008's fixed point and floating point packages, the only direction supported is downto. The actual range has meaning. With fixed point, the indices have weight. Negative indices are the fractional part.
variable foo4 : sfixed(7 downto -2) ; -- 8 bits of integer, 2 bits of fraction
variable foo5 : sfixed(7 downto 1) ; -- even numbers only.
For more on fixed and floating point, see:
https://synthworks.com/papers/vhdl_fixedfloat_lewis_bishop_date_2007.pdf
For more on unsigned / signed, see:
https://synthworks.com/papers/vhdl_math_tricks_mapld_2003.pdf
In IEEE Standard VHDL Synthesis Packages:
The type UNSIGNED represents an unsigned binary integer with the most
significant bit on the left, while the type SIGNED represents a
two’s-complement binary integer with the most significant bit on the
left. In particular, a one-element SIGNED vector represents the
integer values –1 and 0.
So the number will be interpreted as 100, regardless the range direction. However, accessing or assigning a single element will match with the to range, i.e. foo3(1) = '1'.

understanding of vhdl code and flow of 4 bit ALU?

I am making 4 bit ALU here i have declared entities
entity ALU is
Port ( a : in STD_LOGIC_VECTOR (3 downto 0););
end ALU;
can you please explain that how logic vector array works there i mean syntax of
a : in STD_LOGIC_VECTOR (3 downto 0);
and also
the operator =>
2- what is difference between sequential design and combinatorial design AND hierarchical design and tell me ALU CPU is coded in all of them?
can you please explain that how logic vector array works there i mean
syntax of
a : in STD_LOGIC_VECTOR (3 downto 0);
this is a port declaration, consisting of
a - the name of the port
in - its direction - it supplies a signal into this entity
STD_LOGIC_VECTOR - its type (roughly, an array of bits)
(3 downto 0) its index type (4 integers in a descending range)
; - a separator before the next declaration.
It's not clear from the question, what you don't understand.
the operator =>
Is not really an operator, you can't overload it for example - it's an association, associating (in a case statement) the case value on the left with the case action on the right.
You'll also see it associating parameter names with parameter values in argument lists, port maps, etc.
2- what is difference between 4 bit behavioral alu and 4 bit verdict
multiplier
One can add, the other can multiply. Though I've never heard of a "verdict" multiplier.

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.

VHDL multidimensionsal Array

I am trying to get partial sums of 18*18 multiplication. I want to save these in a multidimensional array(18*36) where each index of array contains a partial sum.
i tried using an array of std_logic_vector. But I got no results. I even tried array of bit_vector and also also of bits.
Here is my VHDL code.
entity partial is
port(
A : in bit_vector(17 downto 0);
B : in bit_vector(17 downto 0);
C : out bit_vector(35 downto 0);
D : out bit
);
end partial;
architecture Behavioral of partial is
type partial_sums is array (17 downto 0, 35 downto 0) of bit;
signal sums : partial_sums;
begin
process (A,B)
begin
--sums <= (others=> (others=>'0'));
--for j in 0 to 17 loop
-- sums(j)<="000000000000000000000000000000000000";
--end loop;
for i in B'low to B'high loop
if ( B(i)='1') then
for p in A'low to A'high loop
sums(i,p) <= A(p);
end loop;
end if;
end loop;
D <= sums(0,0);
end process;
end Behavioral;
I am always getting 0 in D no matter what indices use in sums array.
Please help me.
You are assigning sums to D in a combinatorial process, but sums is not in the process sensitivity list.
Probably the best way to go here is to move the assignment of D outside of the process.
A word of warning: Xilinx ISE including verison 14 has problems with multidimensional arrays and vector assignments. You cannot use three-dimensional arrays and you cannot use unconstrained arrays of arrays. Also, using multidimensional arrays, assignment is somewhat flaky at best. When I used ISE last, it often would complain about legal assignments not having the desired width even when ModelSim would compile and simulate fine.
Your actual problem is likely that you only assign the lower 18 bits of each entry in sums, where the entry is actually 36 bits wide.
For better readability you should probably define
type partial_sums is array (natural range <>) of bit_vector(35 downto 0);
and then use direct bit_vector assignments without loops.
Your fixed values in D are likely due to either B having no bits set to '1' (where you should get U because you lack a default value) or because A's bits are always '0', where you should get all '0' in the lower 18 bits and all 'U' in the upper 18 bis.
EDIT: However, bit is resolved logic, so you will only see '0' or '1' in there. IMO you should use std_logic.
Actually, it works fine, loading appropriate test data into the partial product array.
You just aren't waking the process up again to collect the result on D.
Add "sums" to the sensitivity list of process "partial" to do so.
Or better, make it a clocked process (as you will have to, to get any sensible results when you get to synthesis).
See this Q/A on how signal assignments work.
Is process in VHDL reentrant?

What is this VHDL code setting max and min to? An explanation of fixed point representation would be helpful

constant MAX : unsigned(18 downto 0) := "100" & x"0000";
constant MIN : unsigned(18 downto 0) := "001" & x"0000";
What is this VHDL code setting max and min to? An explanation of fixed point representation would be helpful.
The & operator concatenates the two bit vectors "100" and x"0000" (e.g. "00" & "11" would be equivalent to "0011").
The X"012345689ABCDEF" syntax means that the following vector should be interpreted as a hex number (e.g. X"0" actually is "0000", X"F" would be "1111" or X"0F" would be "00001111"). This allows you to write a bit vector in a more compact way.
For the interpretation of a bit vector check e.g. http://en.wikipedia.org/wiki/Binary_numeral_system
For representation of hexdecimal numbers check e.g. http://en.wikipedia.org/wiki/Hexadecimal
Edit for clarification: I assume you are using the unsigned type from the numeric_std package. From the header of that package
This package defines numeric types and arithmetic functions
for use with synthesis tools. Two numeric types are defined:
-- > UNSIGNED: represents UNSIGNED number in vector form
-- > SIGNED: represents a SIGNED number in vector form
The base element type is type STD_LOGIC.
The leftmost bit is treated as the most significant bit.
Signed vectors are represented in two's complement form.
So your MAX is set to 2^18 and your MIN to 2^16.

Resources