FSM,乘积计数之和
FSM, sum of products count
我的 VHDL 项目有一个问题。代码如下:
注册模块:
library ieee;
use ieee.std_logic_1164.all;
entity reg is
port(
clk, rst : in std_logic;
d : in std_logic_vector(23 downto 0);
q : out std_logic_vector(23 downto 0)
);
end reg;
architecture arch of reg is
signal q_reg, q_next : std_logic_vector(23 downto 0);
begin
process(clk, rst)
begin
if (rst ='1') then
q_reg <= (others => '0');
elsif rising_edge(clk) then
q_reg <= q_next;
end if;
end process;
q_next <= d;
q <= q_reg;
end arch;
多个模块:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mul is
port (
a : in std_logic_vector(7 downto 0);
b : in std_logic_vector(15 downto 0);
r : out std_logic_vector(23 downto 0)
);
end mul;
architecture arch of mul is
signal result : signed (23 downto 0);
begin
result <= signed(a) * signed(b);
r <= std_logic_vector(result);
end arch;
加法器模块:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity add is
port (
a,b : in std_logic_vector(23 downto 0);
s : out std_logic_vector(23 downto 0)
);
end add;
architecture arch of add is
signal result : signed(23 downto 0);
begin
result <= signed(a) + signed(b);
s <= std_logic_vector(result);
end arch;
ALU模块:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity alu is
port (
clk, rst : in std_logic;
data : in std_logic_vector(7 downto 0);
cof : in std_logic_vector(15 downto 0);
y : out std_logic_vector(23 downto 0)
);
end alu;
architecture arch of alu is
signal mul_in_a : std_logic_vector(7 downto 0);
signal mul_in_b : std_logic_vector(15 downto 0);
signal mul_out : std_logic_vector(23 downto 0);
signal add_in_a, add_in_b : std_logic_vector(23 downto 0);
signal add_out : std_logic_vector(23 downto 0);
signal reg_in, reg_out : std_logic_vector(23 downto 0);
component mul
port(
a : in std_logic_vector(7 downto 0);
b : in std_logic_vector(15 downto 0);
r : out std_logic_vector(23 downto 0)
);
end component;
component add
port(
a : in std_logic_vector(23 downto 0);
b : in std_logic_vector(23 downto 0);
s : out std_logic_vector(23 downto 0)
);
end component;
component reg
port(
clk : in std_logic;
rst : in std_logic;
d : in std_logic_vector(23 downto 0);
q : out std_logic_vector(23 downto 0)
);
end component;
begin
b1:mul port map(
a => mul_in_a,
b => mul_in_b,
r => mul_out
);
b2:add port map (
a => add_in_a,
b => add_in_b,
s => add_out
);
b3:reg port map (
clk => clk,
rst => rst,
d => reg_in,
q => reg_out
);
mul_in_a <= data;
mul_in_b <= cof;
add_in_a <= mul_out;
add_in_b <= reg_out;
reg_in <= add_out;
y <= reg_out;
end arch;
顶级模块,带 fsm:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity top is
port(
clk : in std_logic;
rst : in std_logic;
rst_a : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_out: out std_logic_vector(23 downto 0);
Yacc : out unsigned(3 downto 0)
);
end top;
architecture arch of top is
type STYPE is (load,count,result);
signal cof_alu_reg, cof_alu_next : std_logic_vector(15 downto 0);
signal dt_in_alu_reg,dt_in_alu_next : std_logic_vector(7 downto 0);
signal datao : std_logic_vector(23 downto 0);
signal state_reg, state_next : STYPE;
signal adress_reg, adress_next :unsigned(3 downto 0);
signal data_out_reg, data_out_next : std_logic_vector(23 downto 0);
type cof_table is array ( 8 downto 0) of std_logic_vector( 15 downto 0);
type data_table is array ( 8 downto 0) of std_logic_vector(7 downto 0);
signal Yacc_reg, Yacc_next : unsigned(3 downto 0);
signal clr : std_logic;
signal datat : data_table;
signal coft : cof_table;
component alu
port(
clk, rst : in std_logic;
data : in std_logic_vector(7 downto 0);
cof : in std_logic_vector(15 downto 0);
y : out std_logic_vector(23 downto 0)
);
end component;
begin
a1:alu port map (
clk => clk,
rst => clr,
cof => cof_alu_reg,
data => dt_in_alu_reg,
y => datao
);
process(rst, clk)
begin
if rst = '1' then
state_reg <= load;
elsif rising_edge(clk) then
state_reg <= state_next;
end if;
end process;
process(rst, clk)
begin
if rst = '1' then
cof_alu_reg <= (others => '0');
dt_in_alu_reg <= (others => '0');
adress_reg <= "0000";
data_out_reg <= (others => '0');
Yacc_reg <= "0000";
elsif rising_edge(clk) then
cof_alu_reg <= cof_alu_next;
dt_in_alu_reg <= dt_in_alu_next;
adress_reg <= adress_next;
data_out_reg <= data_out_next;
Yacc_reg <= Yacc_next;
end if;
end process;
process(state_reg, cof_alu_reg,dt_in_alu_reg,adress_reg,Yacc_reg,datao,clr)
begin
state_next <= state_reg;
cof_alu_next <= cof_alu_reg;
dt_in_alu_next <= dt_in_alu_reg;
adress_next <= adress_reg;
data_out_next <= data_out_reg;
Yacc_next <= Yacc_reg;
coft(0) <= "0000000001101110";
coft(1) <= "1111111110111011";
coft(2) <= "1111111011000000";
coft(3) <= "0000010001000101";
coft(4) <= "0000100110100110";
coft(5) <= "0000010001000101";
coft(6) <= "1111111011000000";
coft(7) <= "1111111110111011";
coft(8) <= "0000000001101110";
Yacc <= Yacc_reg;
case state_reg is
when load =>
if adress_reg < "1001" then
datat(to_integer(adress_reg)-1) <= data_in;
Yacc_next <= adress_reg;
adress_next <= adress_reg + "0001";
state_next <= load;
elsif adress_reg = "1001" then
datat(to_integer(adress_reg)-1) <= data_in;
Yacc_next <= adress_reg;
adress_next <= "0000";
state_next <= count;
end if;
when count =>
if adress_reg < "1001" then
dt_in_alu_next <= datat(to_integer(adress_reg)-1);
cof_alu_next <= coft(to_integer(adress_reg)-1);
Yacc_next <= adress_reg;
adress_next <= adress_reg + "0001";
state_next <= count;
elsif adress_reg = "1001" then
dt_in_alu_next <= datat(to_integer(adress_reg-1));
cof_alu_next <= coft(to_integer(adress_reg)-1);
state_next <= result;
adress_next <= "0000";
Yacc_next <= adress_reg;
end if;
when result =>
data_out_next <= datao;
Yacc_next <= adress_reg;
adress_next <= adress_reg + "0001";
state_next <= load;
when others =>
state_next <= load;
end case;
end process;
data_out <= data_out_reg;
end arch;
这个简单的系统计算产品总和。在前九个时钟节拍期间,我从输入中获取样本,我使用地址来增加下一个位置以保存样本。我的问题是当系统进入九个时钟节拍时,样本不会保存到内存中,从而减少了最终结果。有人知道错误在哪里吗?
这是我的建议。
改进:
- 减少异步重置
- 从 FSM 中提取数据流
- 为正确的重置传播引入了状态空闲
- 更正地址计算 -> 没有 -1
- 将系数定义为常量
- 删除了冗余寄存器
编辑 1:
忘了alu有1个周期的延迟。所以你可以在状态计数中计数到 9 或在计数和结果之间插入一个 nop 状态。
为什么datat索引计算错误?
- 上电后和每次复位后,adress_reg
为零,state
为负载。
-> if adress_reg < "1001" then
是当前状态(负载)下的活动分支
-> data_in
写入索引 to_integer("0000")-1)
=> 这是 -1
=> 模拟应该给出一个超出范围的错误
为什么 cof_alu_reg
和 dt_in_alu_reg
上的附加寄存器是错误的?
- FSM 为状态计数中的 alu 选择适当的系数和输入。
- 这些值已注册(1 个周期延迟)
- alu模块以另一个延迟周期执行计算
=> 因此,在为 alu 分配最后一个输入值之后,在 data_out_reg 捕获结果之前必须有 2 个周期的延迟。
修改源码(未模拟):
architecture arch of top is
type STYPE is (idle,load,count,nop,result);
signal state_reg : STYPE := idle;
signal state_next : STYPE;
signal address_rst : std_logic;
signal address_reg : unsigned(3 downto 0) := (others => '0');
type cof_table is array (8 downto 0) of std_logic_vector(15 downto 0);
type data_table is array (8 downto 0) of std_logic_vector(7 downto 0);
signal datat_en : std_logic;
signal datat : data_table;
signal cof_alu_next : std_logic_vector(15 downto 0);
signal dt_in_alu_next : std_logic_vector(7 downto 0);
signal data_out_next : std_logic_vector(23 downto 0);
signal data_out_en : std_logic;
signal data_out_reg : std_logic_vector(23 downto 0) := (others => '0');
constant coft : cof_table := (
0 => "0000000001101110",
1 => "1111111110111011",
2 => "1111111011000000",
3 => "0000010001000101",
4 => "0000100110100110",
5 => "0000010001000101",
6 => "1111111011000000",
7 => "1111111110111011",
8 => "0000000001101110"
);
begin
# no registers needed, because oft is constant and datat is already registered
cof_alu_next <= coft(to_integer(address_reg));
dt_in_alu_next <= datat(to_integer(address_reg));
a1:alu port map (
clk => clk,
rst => clr,
cof => cof_alu_next,
data => dt_in_alu_next,
y => data_out_next
);
process(rst, clk)
begin
if rst = '1' then
state_reg <= idle;
elsif rising_edge(clk) then
state_reg <= state_next;
end if;
end process;
# rewritten to synchronous registers
process(clk)
begin
if rising_edge(clk) then
# address counter
# count if reset is low
if (address_rst = '1') then
address_reg <= (others => '0');
else
address_reg <= address_reg + 1;
end if;
# datatable
# store data if enabled
if (datat_en = '1') then
datat(to_integer(address_reg)) <= data_in;
end if;
# result register
if (data_out_en = '1') then
data_out_reg <= data_out_next;
end if;
end if;
end process;
process(state_reg, address_reg)
begin
state_next <= state_reg;
address_rst <= '0';
datat_en <= '0';
data_out_en <= '0';
case state_reg is
when idle =>
address_rst <= '1';
state_next <= load; # add a condition if needed
when load =>
datat_en <= '1';
Yacc_next <= address_reg;
if (address_reg = datat'high) then
address_rst <= '1';
state_next <= count;
end if;
when count =>
if (address_reg = datat'high) then
address_rst <= '1';
state_next <= nop;
end if;
when nop =>
state_next <= result;
when result =>
data_out_en <= '1';
state_next <= idle; # if you want to go to count: assert address_rst in this state
when others =>
state_next <= load;
end case;
end process;
# outputs
Yacc <= address_reg when rising_edge(clk); # delay Yacc output by one cycle (short form)
data_out <= data_out_reg;
end arch;
我的 VHDL 项目有一个问题。代码如下:
注册模块:
library ieee;
use ieee.std_logic_1164.all;
entity reg is
port(
clk, rst : in std_logic;
d : in std_logic_vector(23 downto 0);
q : out std_logic_vector(23 downto 0)
);
end reg;
architecture arch of reg is
signal q_reg, q_next : std_logic_vector(23 downto 0);
begin
process(clk, rst)
begin
if (rst ='1') then
q_reg <= (others => '0');
elsif rising_edge(clk) then
q_reg <= q_next;
end if;
end process;
q_next <= d;
q <= q_reg;
end arch;
多个模块:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mul is
port (
a : in std_logic_vector(7 downto 0);
b : in std_logic_vector(15 downto 0);
r : out std_logic_vector(23 downto 0)
);
end mul;
architecture arch of mul is
signal result : signed (23 downto 0);
begin
result <= signed(a) * signed(b);
r <= std_logic_vector(result);
end arch;
加法器模块:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity add is
port (
a,b : in std_logic_vector(23 downto 0);
s : out std_logic_vector(23 downto 0)
);
end add;
architecture arch of add is
signal result : signed(23 downto 0);
begin
result <= signed(a) + signed(b);
s <= std_logic_vector(result);
end arch;
ALU模块:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity alu is
port (
clk, rst : in std_logic;
data : in std_logic_vector(7 downto 0);
cof : in std_logic_vector(15 downto 0);
y : out std_logic_vector(23 downto 0)
);
end alu;
architecture arch of alu is
signal mul_in_a : std_logic_vector(7 downto 0);
signal mul_in_b : std_logic_vector(15 downto 0);
signal mul_out : std_logic_vector(23 downto 0);
signal add_in_a, add_in_b : std_logic_vector(23 downto 0);
signal add_out : std_logic_vector(23 downto 0);
signal reg_in, reg_out : std_logic_vector(23 downto 0);
component mul
port(
a : in std_logic_vector(7 downto 0);
b : in std_logic_vector(15 downto 0);
r : out std_logic_vector(23 downto 0)
);
end component;
component add
port(
a : in std_logic_vector(23 downto 0);
b : in std_logic_vector(23 downto 0);
s : out std_logic_vector(23 downto 0)
);
end component;
component reg
port(
clk : in std_logic;
rst : in std_logic;
d : in std_logic_vector(23 downto 0);
q : out std_logic_vector(23 downto 0)
);
end component;
begin
b1:mul port map(
a => mul_in_a,
b => mul_in_b,
r => mul_out
);
b2:add port map (
a => add_in_a,
b => add_in_b,
s => add_out
);
b3:reg port map (
clk => clk,
rst => rst,
d => reg_in,
q => reg_out
);
mul_in_a <= data;
mul_in_b <= cof;
add_in_a <= mul_out;
add_in_b <= reg_out;
reg_in <= add_out;
y <= reg_out;
end arch;
顶级模块,带 fsm:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity top is
port(
clk : in std_logic;
rst : in std_logic;
rst_a : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_out: out std_logic_vector(23 downto 0);
Yacc : out unsigned(3 downto 0)
);
end top;
architecture arch of top is
type STYPE is (load,count,result);
signal cof_alu_reg, cof_alu_next : std_logic_vector(15 downto 0);
signal dt_in_alu_reg,dt_in_alu_next : std_logic_vector(7 downto 0);
signal datao : std_logic_vector(23 downto 0);
signal state_reg, state_next : STYPE;
signal adress_reg, adress_next :unsigned(3 downto 0);
signal data_out_reg, data_out_next : std_logic_vector(23 downto 0);
type cof_table is array ( 8 downto 0) of std_logic_vector( 15 downto 0);
type data_table is array ( 8 downto 0) of std_logic_vector(7 downto 0);
signal Yacc_reg, Yacc_next : unsigned(3 downto 0);
signal clr : std_logic;
signal datat : data_table;
signal coft : cof_table;
component alu
port(
clk, rst : in std_logic;
data : in std_logic_vector(7 downto 0);
cof : in std_logic_vector(15 downto 0);
y : out std_logic_vector(23 downto 0)
);
end component;
begin
a1:alu port map (
clk => clk,
rst => clr,
cof => cof_alu_reg,
data => dt_in_alu_reg,
y => datao
);
process(rst, clk)
begin
if rst = '1' then
state_reg <= load;
elsif rising_edge(clk) then
state_reg <= state_next;
end if;
end process;
process(rst, clk)
begin
if rst = '1' then
cof_alu_reg <= (others => '0');
dt_in_alu_reg <= (others => '0');
adress_reg <= "0000";
data_out_reg <= (others => '0');
Yacc_reg <= "0000";
elsif rising_edge(clk) then
cof_alu_reg <= cof_alu_next;
dt_in_alu_reg <= dt_in_alu_next;
adress_reg <= adress_next;
data_out_reg <= data_out_next;
Yacc_reg <= Yacc_next;
end if;
end process;
process(state_reg, cof_alu_reg,dt_in_alu_reg,adress_reg,Yacc_reg,datao,clr)
begin
state_next <= state_reg;
cof_alu_next <= cof_alu_reg;
dt_in_alu_next <= dt_in_alu_reg;
adress_next <= adress_reg;
data_out_next <= data_out_reg;
Yacc_next <= Yacc_reg;
coft(0) <= "0000000001101110";
coft(1) <= "1111111110111011";
coft(2) <= "1111111011000000";
coft(3) <= "0000010001000101";
coft(4) <= "0000100110100110";
coft(5) <= "0000010001000101";
coft(6) <= "1111111011000000";
coft(7) <= "1111111110111011";
coft(8) <= "0000000001101110";
Yacc <= Yacc_reg;
case state_reg is
when load =>
if adress_reg < "1001" then
datat(to_integer(adress_reg)-1) <= data_in;
Yacc_next <= adress_reg;
adress_next <= adress_reg + "0001";
state_next <= load;
elsif adress_reg = "1001" then
datat(to_integer(adress_reg)-1) <= data_in;
Yacc_next <= adress_reg;
adress_next <= "0000";
state_next <= count;
end if;
when count =>
if adress_reg < "1001" then
dt_in_alu_next <= datat(to_integer(adress_reg)-1);
cof_alu_next <= coft(to_integer(adress_reg)-1);
Yacc_next <= adress_reg;
adress_next <= adress_reg + "0001";
state_next <= count;
elsif adress_reg = "1001" then
dt_in_alu_next <= datat(to_integer(adress_reg-1));
cof_alu_next <= coft(to_integer(adress_reg)-1);
state_next <= result;
adress_next <= "0000";
Yacc_next <= adress_reg;
end if;
when result =>
data_out_next <= datao;
Yacc_next <= adress_reg;
adress_next <= adress_reg + "0001";
state_next <= load;
when others =>
state_next <= load;
end case;
end process;
data_out <= data_out_reg;
end arch;
这个简单的系统计算产品总和。在前九个时钟节拍期间,我从输入中获取样本,我使用地址来增加下一个位置以保存样本。我的问题是当系统进入九个时钟节拍时,样本不会保存到内存中,从而减少了最终结果。有人知道错误在哪里吗?
这是我的建议。
改进:
- 减少异步重置
- 从 FSM 中提取数据流
- 为正确的重置传播引入了状态空闲
- 更正地址计算 -> 没有 -1
- 将系数定义为常量
- 删除了冗余寄存器
编辑 1:
忘了alu有1个周期的延迟。所以你可以在状态计数中计数到 9 或在计数和结果之间插入一个 nop 状态。
为什么datat索引计算错误?
- 上电后和每次复位后,adress_reg
为零,state
为负载。
-> if adress_reg < "1001" then
是当前状态(负载)下的活动分支
-> data_in
写入索引 to_integer("0000")-1)
=> 这是 -1
=> 模拟应该给出一个超出范围的错误
为什么 cof_alu_reg
和 dt_in_alu_reg
上的附加寄存器是错误的?
- FSM 为状态计数中的 alu 选择适当的系数和输入。
- 这些值已注册(1 个周期延迟)
- alu模块以另一个延迟周期执行计算
=> 因此,在为 alu 分配最后一个输入值之后,在 data_out_reg 捕获结果之前必须有 2 个周期的延迟。
修改源码(未模拟):
architecture arch of top is
type STYPE is (idle,load,count,nop,result);
signal state_reg : STYPE := idle;
signal state_next : STYPE;
signal address_rst : std_logic;
signal address_reg : unsigned(3 downto 0) := (others => '0');
type cof_table is array (8 downto 0) of std_logic_vector(15 downto 0);
type data_table is array (8 downto 0) of std_logic_vector(7 downto 0);
signal datat_en : std_logic;
signal datat : data_table;
signal cof_alu_next : std_logic_vector(15 downto 0);
signal dt_in_alu_next : std_logic_vector(7 downto 0);
signal data_out_next : std_logic_vector(23 downto 0);
signal data_out_en : std_logic;
signal data_out_reg : std_logic_vector(23 downto 0) := (others => '0');
constant coft : cof_table := (
0 => "0000000001101110",
1 => "1111111110111011",
2 => "1111111011000000",
3 => "0000010001000101",
4 => "0000100110100110",
5 => "0000010001000101",
6 => "1111111011000000",
7 => "1111111110111011",
8 => "0000000001101110"
);
begin
# no registers needed, because oft is constant and datat is already registered
cof_alu_next <= coft(to_integer(address_reg));
dt_in_alu_next <= datat(to_integer(address_reg));
a1:alu port map (
clk => clk,
rst => clr,
cof => cof_alu_next,
data => dt_in_alu_next,
y => data_out_next
);
process(rst, clk)
begin
if rst = '1' then
state_reg <= idle;
elsif rising_edge(clk) then
state_reg <= state_next;
end if;
end process;
# rewritten to synchronous registers
process(clk)
begin
if rising_edge(clk) then
# address counter
# count if reset is low
if (address_rst = '1') then
address_reg <= (others => '0');
else
address_reg <= address_reg + 1;
end if;
# datatable
# store data if enabled
if (datat_en = '1') then
datat(to_integer(address_reg)) <= data_in;
end if;
# result register
if (data_out_en = '1') then
data_out_reg <= data_out_next;
end if;
end if;
end process;
process(state_reg, address_reg)
begin
state_next <= state_reg;
address_rst <= '0';
datat_en <= '0';
data_out_en <= '0';
case state_reg is
when idle =>
address_rst <= '1';
state_next <= load; # add a condition if needed
when load =>
datat_en <= '1';
Yacc_next <= address_reg;
if (address_reg = datat'high) then
address_rst <= '1';
state_next <= count;
end if;
when count =>
if (address_reg = datat'high) then
address_rst <= '1';
state_next <= nop;
end if;
when nop =>
state_next <= result;
when result =>
data_out_en <= '1';
state_next <= idle; # if you want to go to count: assert address_rst in this state
when others =>
state_next <= load;
end case;
end process;
# outputs
Yacc <= address_reg when rising_edge(clk); # delay Yacc output by one cycle (short form)
data_out <= data_out_reg;
end arch;