Search code examples
vhdlquartusalu

Make an arithmetic logic unit in vhdl


I need to make an arithmetic logic unit in VHDL for the pic16f684. So the instructions for the ALU can be found in the datasheet of the pic16f684.

The instructions I need to make are the following:

These are the instructions

This is my code so far, but I get, which is quite logic, the error that a std_logic_vector can't have a character in the vector, but I don't know how to do it in a other way..

LIBRARY IEEE;
USE  IEEE.STD_LOGIC_1164.all;
USE  IEEE.STD_LOGIC_ARITH.all;
USE  IEEE.STD_LOGIC_UNSIGNED.all;

ENTITY AluPIC IS

   PORT(    -- Input Signals    
        Op_code     : in std_logic_vector(6 DOWNTO 0);
        win, fin        : in std_logic_vector(7 DOWNTO 0);
         -- Output Signals
        d,z : out std_logic;
        ALU_output  : out std_logic_vector(7 DOWNTO 0));


END AluPIC;

ARCHITECTURE behavior OF AluPIC IS
        -- declare signal(s) internal to module here
SIGNAL temp_output,wout,fout: std_logic_vector(7 DOWNTO 0);

BEGIN
  PROCESS (Op_code, win, fin)
    BEGIN
        -- Select Arithmetic/Logical Operation
    CASE Op_Code (6 DOWNTO 0) IS
        WHEN "000111d" =>
            if d ='0' then
                wout <= win + fin;
                temp_output <=wout;
            else
                fout <= win + fin;
                temp_output <= fout;
            end if;

        WHEN "000101d" =>
            if d ='0' then
                wout <= win and fin;
                temp_output <= wout;
            else
                fout <= win and fin;
                temp_output <= fout;
            end if;

        WHEN "000001l" =>
             fout <= fin;
             fout <= "00000000";
             z <= '1';
             temp_output <= fout;

        WHEN "001010d" =>
            fout <= fin+1;
             if d = '0' then
                wout <= fout;
                temp_output <=wout;
             else
                fout <= fout;
                temp_output <=fout;
            end if;

        WHEN "001000d" =>
        if d = '0' then
            wout  <= fin;
            temp_output <= wout;
            z <= '1';
        else
            fout <= fin;
            temp_output <= fout;
            z <= '1';
        end if;

        WHEN "0101bbb" =>
            fout <= fin;
             temp_output <= fout;
        WHEN OTHERS =>
            temp_output <= "00000000";
    END CASE;
            -- Select Shift Operation
    IF Op_Code(0) = '1' THEN
            -- Shift bits left with zero fill using concatination operator
            -- can also use VHDL 1076-1993 shift operator such as SLL 
        Alu_output <= temp_output(6 DOWNTO 0) & '0';
    ELSE 
        Alu_output <= temp_output;
    END IF;
  END PROCESS;
END behavior;

Thanks for your time guys!


Solution

  • Lines like WHEN "000111d" => or WHEN "0101bbb" => are not valid, because your case statement uses an std_logic_vector, but "000111d" is a string.

    It is not clear what you are trying to achieve with your d and b characters, but your various when lines should compare against a valid std_logic_vector of the correct length, for example WHEN "0000111" =>.

    Looking at your op code image, it shows a table with lines containing operations, for example 'ADDWF'. In these operations, only the most significant 6 bits seem to select the operation, with the least significant bit being labelled b or d. This least significant bit is actually a parameter for the operation, not part of the opcode. The table does not show what effect d has on the operation, but you seem to have worked this out. Using ADDWF as an example, I would change your code like this:

    CASE Op_Code (6 DOWNTO 1) IS
      WHEN "000111" =>
        if Op_Code(0) ='0' then
          wout <= win + fin;
          temp_output <=wout;
        else
          fout <= win + fin;
          temp_output <= fout;
        end if;
      -- ...
    end case;
    

    The 'BSF' operation is the exception, as it uses the least significant 3 bits as a parameter. You can write this either using a matching case statement, or by listing all the possibilities in one case:

    Matching case, requiring VHDL2008:

    CASE? Op_Code (6 DOWNTO 1) IS
      WHEN "0101--" =>
        -- Set a bit based on `op_code (2 downto 0)`
    end case?;
    

    List all possibilities:

    CASE Op_Code (6 DOWNTO 1) IS
      WHEN "010100" | "010101" | "010110" | "010111" =>
        -- Set a bit based on `op_code (2 downto 0)`
    end case;