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:
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!
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;