进程中端口映射的替代方法?
Alternate way for port map in process?
据我对 vhdl 的理解,不可能将端口映射到进程中的组件。我很好奇是否有另一种方法来处理有条件的场景。
这是我目前正在处理的计算器 vhdl 代码示例:
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;
我无法真正解决的主要问题是如何在特定情况下(if/else 条件)使用我的加法器组件。
正如@BrianDrummond 所说,您不能让硬件神奇地随意出现和消失。您无法根据对硬件的某些输入来决定硬件块是否存在或不存在。因此,相反,您需要实例化硬件一次,然后控制输入给它的内容:
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?
因此,您可以看到我已经声明了两个新信号 L
和 R
,并且我正在使用您的流程来控制驱动它们的因素。 ADD
块将添加一些 R0
、R1
、R2
和 R3
的组合。
我已经在下面回答了你的问题,但我在你的代码中看到了很多其他问题,尽管问题很多而且我只是快速浏览了一下。它们出现的顺序,而不是严肃的顺序:
i) signal R0, R1, R2, R3: std_logic_vector (7 downto 0) := "00000000";
仔细想想你为什么要初始化这些信号。这可能适用于 FPGA,但(来自 IC 设计背景)依赖初始化信号似乎很危险。
ii) 您缺少解码器的实例名称(严格来说是 标签):
decode port map (Instruction, op, rs, rd, rt);
应该是这样的:
deci : decode port map (Instruction, op, rs, rd, rt);
iii) 你真的应该在你的端口映射中使用命名关联。而不是:
deci : decode port map (Instruction, op, rs, rd, rt);
做:
deci : decode port map (instr => Instruction, op => op, rs => rs, rd = rd, rt => rt);
iv) 您的流程不适合可合成顺序流程的任何模板:
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
这是一个用于异步重置的顺序过程的模板:
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;
因此,ENABLE
不应出现在您的敏感列表中;您的流程的第一行应该是:
calc: process (Clock, RESET)
你应该在 rising_edge(Clock)
测试后测试 ENABLE
信号:
elsif (rising_edge(Clock)) then
if (ENABLE = '0') then
您应该测试复位的绝对值,而不是寻找上升沿。而且您不需要所有这些括号。即不是这个:
if (rising_edge(RESET)) then
这个:
if RESET = '1' then
这一行是多余的:
elsif (Clock = '1') then
v) 您不应该 测试时钟的两个边沿。这不是同步设计。您不能 在一个进程中测试两个边缘。那甚至是不可合成的。这需要去:
elsif (falling_edge(Clock)) then
vi) 我担心您在此过程中较早地将 R0
驱动到 R3
,然后稍后使用它们的值。很难准确看出您的设计意图,但我怀疑这不会起作用:
在 VHDL 中 信号 直到进程 挂起 才会更新。如果您尝试使用在流程中较早分配的信号,您将获得先前分配的值。
一般
我建议您将设计分解为许多较小的过程。清楚地了解您希望每种硬件使用哪种硬件。让每个执行特定功能,例如将输入多路复用到 ADD block
。例如,考虑:
流程是顺序逻辑还是组合逻辑?
重置是异步的还是同步的?
输入是什么?
输出是什么?
然后选择合适的模板。我已经给出了一个用于异步重置的顺序过程。这是一个没有异步重置的顺序过程:
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;
据我对 vhdl 的理解,不可能将端口映射到进程中的组件。我很好奇是否有另一种方法来处理有条件的场景。
这是我目前正在处理的计算器 vhdl 代码示例:
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;
我无法真正解决的主要问题是如何在特定情况下(if/else 条件)使用我的加法器组件。
正如@BrianDrummond 所说,您不能让硬件神奇地随意出现和消失。您无法根据对硬件的某些输入来决定硬件块是否存在或不存在。因此,相反,您需要实例化硬件一次,然后控制输入给它的内容:
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?
因此,您可以看到我已经声明了两个新信号 L
和 R
,并且我正在使用您的流程来控制驱动它们的因素。 ADD
块将添加一些 R0
、R1
、R2
和 R3
的组合。
我已经在下面回答了你的问题,但我在你的代码中看到了很多其他问题,尽管问题很多而且我只是快速浏览了一下。它们出现的顺序,而不是严肃的顺序:
i) signal R0, R1, R2, R3: std_logic_vector (7 downto 0) := "00000000";
仔细想想你为什么要初始化这些信号。这可能适用于 FPGA,但(来自 IC 设计背景)依赖初始化信号似乎很危险。
ii) 您缺少解码器的实例名称(严格来说是 标签):
decode port map (Instruction, op, rs, rd, rt);
应该是这样的:
deci : decode port map (Instruction, op, rs, rd, rt);
iii) 你真的应该在你的端口映射中使用命名关联。而不是:
deci : decode port map (Instruction, op, rs, rd, rt);
做:
deci : decode port map (instr => Instruction, op => op, rs => rs, rd = rd, rt => rt);
iv) 您的流程不适合可合成顺序流程的任何模板:
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
这是一个用于异步重置的顺序过程的模板:
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;
因此,ENABLE
不应出现在您的敏感列表中;您的流程的第一行应该是:
calc: process (Clock, RESET)
你应该在 rising_edge(Clock)
测试后测试 ENABLE
信号:
elsif (rising_edge(Clock)) then
if (ENABLE = '0') then
您应该测试复位的绝对值,而不是寻找上升沿。而且您不需要所有这些括号。即不是这个:
if (rising_edge(RESET)) then
这个:
if RESET = '1' then
这一行是多余的:
elsif (Clock = '1') then
v) 您不应该 测试时钟的两个边沿。这不是同步设计。您不能 在一个进程中测试两个边缘。那甚至是不可合成的。这需要去:
elsif (falling_edge(Clock)) then
vi) 我担心您在此过程中较早地将 R0
驱动到 R3
,然后稍后使用它们的值。很难准确看出您的设计意图,但我怀疑这不会起作用:
在 VHDL 中 信号 直到进程 挂起 才会更新。如果您尝试使用在流程中较早分配的信号,您将获得先前分配的值。
一般
我建议您将设计分解为许多较小的过程。清楚地了解您希望每种硬件使用哪种硬件。让每个执行特定功能,例如将输入多路复用到 ADD block
。例如,考虑:
流程是顺序逻辑还是组合逻辑?
重置是异步的还是同步的?
输入是什么?
输出是什么?
然后选择合适的模板。我已经给出了一个用于异步重置的顺序过程。这是一个没有异步重置的顺序过程:
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;