Reputation: 33
As far as my understanding in vhdl, it is not possible to have port mappings to components within a process. and i was curious whether there is an alternative way to approach a conditional scenario.
here's an example of my calculator vhdl code that I am currently working on:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- OP CODE TABLE --
-- 00 : LOAD --
-- 01 : ADD/SUB --
-- 10 : Print--
-- 11 : BEQ --
-- li - RS Values --
-- 00 : R0 --
-- 01 : R1 --
-- 10 : R2 --
-- 11 : R3 --
-- // add | op, rs, rd, rt //
-- // sub | op, rs, rd, rt //
-- // li | op, rs, immediate //
-- // beq | op, rs, rd, zero //
-- // print | op, rs, zero, one //
-- Current Problems --
-- need variables?
-- dont know what to do with numInst
entity Calculator is
port (
Clock : in std_logic;
numInst : in std_logic_vector (7 downto 0);
--Max Value of PC? 8 bits
Instruction : in std_logic_vector (7 downto 0);
--8 bit instruction
PC : out std_logic_vector (7 downto 0);
--8 bit output, used to retrieve next instruction
PRINTER : out std_logic_vector (7 downto 0);
--8 bit output is set to value of register when instruction display is executed
ENABLE : in std_logic;
--when high, instruction execute, when low, hold-no instruction executed
RESET : in std_logic
--on rising edge, reset register value to 0, restart excution of calculator
);
end Calculator;
architecture Behavorial of Calculator is
component ADD is
port (
A : in std_logic_vector(7 downto 0);
B : in std_logic_vector(7 downto 0);
Carry : out std_logic;
Sum : out std_logic_vector(7 downto 0)
);
end component;
component decode is
port (
instr : in std_logic_vector (7 downto 0);
op : in std_logic_vector (1 downto 0);
rs : in std_logic_vector (1 downto 0);
rd : out std_logic_vector (1 downto 0);
rt : out std_logic_vector (1 downto 0)
);
end component;
--need variable or signal to store opcode
--maybe need variable to store values identifier of rs, rt, rd
--random comment for something else...idk
--maybe we dont need a separate register vhdl file, make variable?
signal op, rs, rt, rd: std_logic_vector(1 downto 0):=(others=>'0');
signal immediate, AddOut: std_logic_vector(7 downto 0):=(others=>'0');
signal carrybit: std_logic;
--make register signals? R0, R1, R2, R3
signal R0, R1, R2, R3: std_logic_vector (7 downto 0) := "00000000";
begin
--portmap
decode port map (Instruction, op, rs, rd, rt);
calc: process (Clock, ENABLE, RESET)
-- use variables opcode, rs, rt, rd to break up Instruction
begin
if (ENABLE = '0') then
--nothing, calculator is disabled
else --ENABLE at 1
if (rising_edge(RESET)) then
PC <= "00000000"; -- restart execution
op <= "00";
rs <= "00";
rt <= "00";
rd <= "00";
--registers go to 0
elsif (rising_edge(Clock)) then
--
elsif (Clock = '1') then
if (op = "00") then
--maybe can be used to load values into registers
if(rd(1)='1') then
immediate(7 downto 4):='1';
immediate(3 downto 2)<= rd;
immediate(1 downto 0)<= rt;
else
immediate(7 downto 4):='0';
immediate(3 downto 2)<= rd;
immediate(1 downto 0)<= rt;
end if;
--PC = PC + 1
elsif (op = "01") then --add
if(rs = "00") then
if(rt = "00") then
addi00: ADD port map(R0,R0,carrybit,AddOut);
elsif(rt = "01") then
addi01: ADD port map(R0,R1,carrybit,AddOut);
elsif(rt = "10") then
addi02: ADD port map(R0,R2,carrybit,AddOut);
else
addi03: ADD port map(R0,R3,carrybit,AddOut);
end if;
elsif(rs = "01") then
if(rt = "00") then
addi10: ADD port map(R1,R0,carrybit,AddOut);
elsif(rt = "01") then
addi11: ADD port map(R1,R1,carrybit,AddOut);
elsif(rt = "10") then
addi12: ADD port map(R1,R2,carrybit,AddOut);
else
addi13: ADD port map(R1,R3,carrybit,AddOut);
end if;
elsif(rs = "10") then
if(rt = "00") then
addi20: ADD port map(R2,R0,carrybit,AddOut);
elsif(rt = "01") then
addi21: ADD port map(R2,R1,carrybit,AddOut);
elsif(rt = "10") then
addi22: ADD port map(R2,R2,carrybit,AddOut);
else
addi23: ADD port map(R2,R3,carrybit,AddOut);
end if;
else
if(rt = "00") then
addi30: ADD port map(R3,R0,carrybit,AddOut);
elsif(rt = "01") then
addi31: ADD port map(R3,R1,carrybit,AddOut);
elsif(rt = "10") then
addi32: ADD port map(R3,R2,carrybit,AddOut);
else
addi33: ADD port map(R3,R3,carrybit,AddOut);
end if;
end if;
--use component of adder vhdl file?
--PC = PC + 1 ?
--use adder (subtractor) component
--PC = PC + 1 ?
elsif (op = "10") then
-- need rs, rt, rd, variable?
if (rs = "00") then
PRINTER <= R0;
--insert print code here
--PC = PC + 1 -- to continue to next instruction
elsif (rs = "01") then
PRINTER <= R1;
--insert print code here
--PC = PC + 1 -- to continue to next instruction
elsif (rs = "10") then
PRINTER <= R2;
--insert print code here
--PC = PC + 1 -- to continue to next instruction
else --(rs = "11") then
PRINTER <= R3;
--insert print code here
--PC = PC + 1 -- to continue to next instruction
end if;
elsif (op = "11") then --beq
--if (register1 != register2) then
--PC <= PC + 1;
--else
--PC <= PC + 2;
--end if;
end if;
end if;
elsif (falling_edge(Clock)) then
if (op = "00") then
if (rs = "00") then
R0 <= immediate;
elsif (rs = "01") then
R1 <= immediate;
elsif (rs = "10") then
R2 <= immediate;
else --rs = "11"
R3 <= immediate;
end if;
elsif (op = "01") then
if (rd = "00") then
R0 <= AddOut;--output of adder;
elsif (rd = "01") then
R1 <= AddOut;--output of adder;
elsif (rd = "10") then
R2 <= AddOut;--output of adder;
else --rd = 11
R3 <= Addout;--output of adder;
end if;
end if;
end if;
end if;
end process calc;
end architecture Behavorial;
the main problem that i can't really wrap my mind around is how to use my adder component under certain circumstances (the if/else conditions).
Upvotes: 2
Views: 8929
Reputation: 13967
As @BrianDrummond says, you can't make hardware magically appear and disappear at will. You cannot decide whether a lump of hardware exists and doesn't exist based on some inputs to the hardware. So, instead, you need to instantiate the hardware once and then control what is being input to it:
signal L, R : std_logic_vector (7 downto 0);
-- snip
addi: ADD port map(L,R,carrybit,AddOut); -- here is the ADD instance
calc: process (Clock, ENABLE, RESET)
-- snip
--PC = PC + 1
elsif (op = "01") then --add
if(rs = "00") then
if(rt = "00") then
L <= R0; R <= R0;
elsif(rt = "01") then
L <= R0; R <= R1;
elsif(rt = "10") then
L <= R0; R <= R2;
else
L <= R0; R <= R3;
end if;
elsif(rs = "01") then
if(rt = "00") then
L <= R0; R <= R0;
elsif(rt = "01") then
L <= R1; R <= R1;
elsif(rt = "10") then
L <= R1 R <= R2;
else
L <= R1; R <= R3;
end if;
elsif(rs = "10") then
if(rt = "00") then
L <= R2; R <= R0;
elsif(rt = "01") then
L <= R2; R <= R1;
elsif(rt = "10") then
L <= R2; R <= R2;
else
L <= R3; R <= R3;
end if;
else
if(rt = "00") then
L <= R3; R <= R0;
elsif(rt = "01") then
L <= R3; R <= R1;
elsif(rt = "10") then
L <= R3; R <= R2;
else
L <= R3; R <= R3;
end if;
end if;
--use component of adder vhdl file?
So, you can see I have declared two new signals L
and R
and I am using your process to control what is driving them. The ADD
block will then add some combination of R0
, R1
, R2
and R3
.
I have answered you question below, but I see many other problems in your code, even though there's quite a lot of it and I only gave it a quick glance. In order they appear, not in order of seriousness:
i) signal R0, R1, R2, R3: std_logic_vector (7 downto 0) := "00000000";
Think very carefully why you are initialising these signals. This might work in an FPGA, but (coming from an IC design background) it seems dangerous to rely on initialising signals.
ii) You are missing the instance name (strictly a label) for your decoder:
decode port map (Instruction, op, rs, rd, rt);
It should be something like:
deci : decode port map (Instruction, op, rs, rd, rt);
iii) You really ought to use named assoication in your port maps. Instead of:
deci : decode port map (Instruction, op, rs, rd, rt);
do:
deci : decode port map (instr => Instruction, op => op, rs => rs, rd = rd, rt => rt);
iv) Your process doesn't fit any template for a synthesisable sequential process:
calc: process (Clock, ENABLE, RESET)
begin
if (ENABLE = '0') then
else --ENABLE at 1
if (rising_edge(RESET)) then
elsif (rising_edge(Clock)) then
elsif (Clock = '1') then
Here is a template for a sequential process with an asynchronous reset:
process(clock, async_reset) -- nothing else should go in the sensitivity list
begin
-- never put anything here
if async_reset ='1' then -- or '0' for an active low reset
-- set/reset the flip-flops here
-- ie drive the signals to their initial values
elsif rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
So, ENABLE
should not be in your sensitivity list; the first line of your process should be:
calc: process (Clock, RESET)
You should test the ENABLE
signal after the test for rising_edge(Clock)
:
elsif (rising_edge(Clock)) then
if (ENABLE = '0') then
You should test the absolute value of reset, not look for a rising edge. And you don't need all those parentheses. ie Not this:
if (rising_edge(RESET)) then
this:
if RESET = '1' then
This line is redundant:
elsif (Clock = '1') then
v) You should not be testing both edges of the clock. This is not synchronous design. You cannot test both edges in a single process. That is not even synthesisable. This needs to go:
elsif (falling_edge(Clock)) then
vi) I am concerned that you are driving R0
to R3
earlier in the process and then using their values later. It is difficult to see your design intent exactly, but I suspect this will not work:
In VHDL signals are not updated until a process suspends. If you try to use a signal assigned earlier in a process, you will get the previously assigned value.
General
I suggest you break your design into many smaller processes. Have a clear idea for each what kind of hardware you expect for each. Have each perform a specific function, eg multiplexing the inputs to the ADD block
. For example, consider:
Is the process sequential or combinational logic?
is the reset asynchronous or synchronous?
What are the inputs?
What are the outputs?
And then pick the appropriate template. I have given one for a sequential process with an asynchronous reset. Here is one for a sequential process without an asynchronous reset:
process(clock) -- nothing else should go in the sensitivity list
begin
-- never put anything here
if rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
Upvotes: 5