Skip to content

Latest commit

 

History

History
executable file
·
156 lines (118 loc) · 5.46 KB

content.asc

File metadata and controls

executable file
·
156 lines (118 loc) · 5.46 KB

Addition and subtraction, the hard way

Now that we have a firm handle on Boolean operators and signal buses, we are in a position to implement one of computing’s basic functions-- adding two numbers together.

Binary addition using Boolean operators

You don’t have to, but as a learning exercise it is worthwhile to implement binary addition using simple operators.

To do so we have to make use of our first equivalent of a 'local variable'-- a signal that is used only within the Switches_LEDs entity.

We will need four of these local signals. To declare them, the definition of the signal is added between the "architecture" and "begin" lines:

  ...
  architecture Behavioral of Switches_LEDs is
    signal x      : STD_LOGIC_VECTOR(3 downto 0);
    signal y      : STD_LOGIC_VECTOR(3 downto 0);
    signal carry  : STD_LOGIC_VECTOR(3 downto 0);
    signal result : STD_LOGIC_VECTOR(4 downto 0);
  begin
  ...

The size of ''result'' may look a little odd, but we are going to add two four-bit numbers on the switches, which gives a five-bit result (as 15+15 = 30). Let’s wire the LEDs up to the "result" signal, and set the unused LEDs to '0'.

  LEDs <= "000" & result;

We will also assign the values of X and Y to be the first and second group of four switches.

   x <= switches(3 downto 0);
   y <= switches(7 downto 4);

Here is the code for adding the first bit:

  result(0) <= x(0) XOR y(0);
  carry(0)  <= x(0) AND y(0);

Not too hard. This is a half adder-- it’s called this as it does not have a 'carry in' only a 'carry out'.

Now here’s the second bit, which is a 'full adder'-- it is a lot more complex as it has to deal with an x bit, a y bit and the carry bit from adding bit zero:

  result(1) <= x(1) XOR y(1) XOR carry(0);
  carry(1)  <= (x(1) AND y(1)) OR (carry(0) AND X(1)) OR (carry(0) AND Y(1));

It is a lot easier to understand the carry expression if you think of it as "are any two bits set?".

So here’s the code up till now:

 library IEEE;
 use IEEE.STD_LOGIC_1164.ALL;

 entity Switches_LEDs is
    Port ( switches : in  STD_LOGIC_VECTOR(7 downto 0);
           LEDs     : out STD_LOGIC_VECTOR(7 downto 0)
         );
 end Switches_LEDs;

 architecture Behavioral of Switches_LEDs is
    signal x      : STD_LOGIC_VECTOR(3 downto 0);
    signal y      : STD_LOGIC_VECTOR(3 downto 0);
    signal carry  : STD_LOGIC_VECTOR(3 downto 0);
    signal result : STD_LOGIC_VECTOR(4 downto 0);
 begin
   LEDs <= "000" & result;
   x <= switches(3 downto 0);
   y <= switches(7 downto 4);

   result(0) <= x(0) XOR y(0);
   carry(0)  <= x(0) AND y(0);

   result(1) <= x(1) XOR y(1) XOR carry(0);
   carry(1)  <= (x(1) AND y(1)) OR (carry(0) AND X(1)) OR (carry(0) AND Y(1));

 end Behavioral;

Project - Adding four bits

  • Based on the code so far, extend this to add all four bits (note-- result(4) will be the value of carry(3)). Test the design for a few values.

  • How many combinations do you have to test to fully verify that your design works properly?

  • Change the ordering of the statements in the code. Does it matter which order they are written in? Why would this be?

And now a better way to add (and subtract) numbers

Though interesting, this is a hard way to add numbers. VHDL includes standard libraries that make things a lot easier for you - STD_LOGIC_UNSIGNED allows you to treat your STD_LOGIC_VECTORs as if they are unsigned binary numbers.

To allow this, you need to add the following line to your code, just below the other "use" statement:

use IEEE.STD_LOGIC_UNSIGNED.ALL;

You can then just code the addition as:

result(4 downto 0) <= x + y;

Not requiring the ten lines or so of code.

The result of adding vectors will be only as long as the longest vector being added. In most cases this is one bit short of what is required to express the full range of results (and a warning like "Width mismatch. <result> has a width of 5 bits but assigned expression is 4-bit wide."). To ensure that I do get the full result I usually force at least one vector to be the length of the desired result:

result(4 downto 0) <= ('0' & x) + y;
Warning
It has come to my attention that using STD_LOGIC_UNSIGNED is now considered bad form. It is highly recommended that you look on the web at how to use ieee.numeric_std.all and associated conversion functions.

Project - Adding two four-bit numbers

  • Change your code to use unsigned addition. Test if it works.

  • Try it both with and without adding an extra bit to the length of the 'x' signal. Does it work as expected?

Challenges

  • Implement binary subtraction using AND, OR, XOR and NOT operators

  • Implement addition using only NOR or only NAND gates

  • Design a project to add "00000001" to the value on the switches and display it on the LEDs. If you use the full adder code you will be able to simplify the logic down to a familiar pattern…​