首页 文章

VHDL状态机问题 - 重复状态

提问于
浏览
0

我们正在为最终项目构建处理器 . 控制单元是一个状态机,但它似乎陷入状态的时间超过它应该的状态,因此它重复指令 .

我们正在使用Vivado 2015.4和Nexys4主板 .

因此,通过一行指令将值存储到加载到指令存储器中的7段中,状态变为:

Fetch =>
Fetch =>
Fetch =>
L_S_D (Load/Store Decode) =>
L_S_E (Load/Store Execute) =>
S_Mem (Store Memory Access) =>
Fetch =>
L_S_D =>
L_S_E =>
S_Mem =>
Fetch =>
L_S_D =>
L_S_E =>
Fetch (forever)

在两个完整的运行中,七段显示 . 在第三个,不完整的贯通,他们没有 .

我附加状态机(相关状态)和程序计数器相关代码,因为我认为这就是问题所在 .

状态机:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Fred is
    Port ( Inst : in STD_LOGIC_vector (31 downto 21);
           clk : in std_logic;
           rst : in std_logic;
           Reg2Loc : out std_logic;
           ALUSRC : out std_logic;
           MemtoReg : out std_logic;
           RegWrite : out std_logic;
           Branch : out std_logic;
           ALUOp : out std_logic_vector (1 downto 0);
           UnconB : out std_logic;
           en : out std_logic;
           wea : out std_logic;
           PCWrite : out std_logic;
           REGCEA : out std_logic;
           LEDCode : out std_logic_vector (4 downto 0));
end Fred;

architecture Behavioral of Fred is
    Type type_fstate is (Fetch, L_S_D, L_S_E, L_Mem, S_Mem,
        L_WB, R_I_D, I_E, R_E, I_WB, R_WB, B_E, CBZ_D, B_WB, CBZ_E,
            CBZ_WB);
    attribute enum_encoding : string;
    attribute enum_encoding of type_fstate : type is "one-hot";
    signal current_state : type_fstate;
    signal next_state : type_fstate;
begin

    clockprocess : process (clk, rst, current_state)
    begin 
        if rst = '1' then
            next_state <= Fetch;
        elsif clk'EVENT and clk = '1' then
            next_state <= current_state;
        end if;
    end process clockprocess;

    state_logic: process (next_state)
    begin
            case next_state is
                when Fetch => --00001
                    if ((Inst = "11111000010")) then --LDUR
                        current_state <= L_S_D;
                    elsif ((Inst = "11111000000")) then --STUR
                        current_state <= L_S_D;                        
                    --Additional State Logic Here
                    else
                        current_state <= Fetch;
                    end if;

                when L_S_D => --00010
                    current_state <= L_S_E;

                when L_S_E => --00011
                    if ((Inst = "11111000010")) then
                        current_state <= L_Mem;
                    elsif ((Inst = "11111000000")) then
                        current_state <= S_Mem;
                    end if;

                when S_Mem => --00110
                    current_state <= Fetch;

                --Additional States Here

                when others =>
                    current_state <= Fetch;
            end case;
    end process state_logic;

    output_logic : process (next_state)
    begin
        case next_state is
            when Fetch =>
                Reg2Loc <= '0';
                ALUSRC <= '0';
                MemtoReg <= '0';
                RegWrite <= '0';
                Branch <= '0';
                ALUOp <= "00";
                UnconB <= '0';
                en <= '0';
                wea <= '0';
                PCWrite <= '0';
                REGCEA <= '1';
                LEDCode <= "00001";
            when L_S_D =>
                Reg2Loc <= '1';
                ALUSRC <= '0';
                MemtoReg <= '0';
                RegWrite <= '0';
                Branch <= '0';
                ALUOp <= "00";
                UnconB <= '0';
                en <= '0';
                wea <= '0';
                PCWrite <= '0';
                REGCEA <= '0';
                LEDCode <= "00010";
            when L_S_E =>
                Reg2Loc <= '1';
                ALUSRC <= '1';
                MemtoReg <= '0';
                RegWrite <= '0';
                Branch <= '0';
                ALUOp <= "00";
                UnconB <= '0';
                en <= '0';
                wea <= '0';
                PCWrite <= '1';
                REGCEA <= '0';
                LEDCode <= "00011";
            when S_Mem =>
                Reg2Loc <= '1';
                ALUSRC <= '1';
                MemtoReg <= '0';
                RegWrite <= '0';
                Branch <= '0';
                ALUOp <= "00";
                UnconB <= '0';
                en <= '1';
                wea <= '1';
                PCWrite <= '0';
                REGCEA <= '0';
                LEDCode <= "00110";
            --Additional State Outputs Here                                                                                                                                                        
            when others =>
                Reg2Loc <= '0';
                ALUSRC <= '0';
                MemtoReg <= '0';
                RegWrite <= '0';
                Branch <= '0';
                ALUOp <= "00";
                UnconB <= '0';
                en <= '0';
                wea <= '0';
                PCWrite <= '0';
                REGCEA <= '0';
                LEDCode <= "00000";
        end case;
    end process output_logic;
end Behavioral;

数据路径:

entity Datapath is
    Port (BTNClock : in STD_LOGIC;
          clock : in STD_LOGIC;
          UncondBranch : in STD_LOGIC;
          CondBranch : in STD_LOGIC;
          RRtwoSelect : in STD_LOGIC;
          RegWriteSelect : in STD_LOGIC;
          ALUSource : in STD_LOGIC;
          ALUOpCode : in STD_LOGIC_VECTOR(1 downto 0);
          WriteSelect : in STD_LOGIC;
          MemWrite : in STD_LOGIC;
          REGCEA : in STD_LOGIC;
          PCWrite : in STD_LOGIC;
          seg_select : out STD_LOGIC_vector(6 downto 0);
          anode_select : out STD_LOGIC_vector(7 downto 0);
          ins_out : out STD_LOGIC_VECTOR(31 downto 0);
          RAMSelect : in STD_LOGIC;
          ALUEleven : out STD_LOGIC;
          REGEleven : out STD_LOGIC;
          SwitchReset : in STD_LOGIC);
end Datapath;

architecture Behavioral of Datapath is

    signal PC : STD_LOGIC_VECTOR(9 downto 0);
    signal instruction : STD_LOGIC_VECTOR(31 downto 0);
    signal BranchSelect : STD_LOGIC;
    signal ZeroBranch : STD_LOGIC;
    signal RRtwo : STD_LOGIC_VECTOR(4 downto 0);
    signal RegDataOut1 : STD_LOGIC_VECTOR(63 downto 0);
    signal RegDataOut2 : STD_LOGIC_VECTOR(63 downto 0);
    signal ALUMuxOut : STD_LOGIC_VECTOR(63 downto 0);
    signal SignExtendOut : STD_LOGIC_VECTOR(63 downto 0);
    signal BranchExtend : STD_LOGIC_VECTOR(9 downto 0);
    signal ALUOut : STD_LOGIC_VECTOR(63 downto 0);
    signal ALUZero : STD_LOGIC;
    signal MemoryOut : STD_LOGIC_VECTOR(63 downto 0);
    signal WriteMuxOut : STD_LOGIC_VECTOR(63 downto 0);
    signal Branch : STD_LOGIC_VECTOR(9 downto 0);
    signal PCNext : STD_LOGIC_VECTOR(9 downto 0);
    signal PCIncrement : STD_LOGIC_VECTOR(9 downto 0);
    signal ALUCommand : STD_LOGIC_VECTOR(3 downto 0);
    signal InstEn : STD_LOGIC := '1';
    signal OnlySeven : STD_LOGIC_VECTOR(0 downto 0);
    signal SevSegReset : STD_LOGIC := '0';

begin

    OnlySeven(0) <= MemWrite and not ALUOut(11);
    BranchSelect <= UncondBranch or ZeroBranch;
    ZeroBranch <= CondBranch and ALUZero;
    ins_out <= instruction;
    ALUEleven <= ALUout(11);
    REGEleven <= RegDataOut1(11);

    --Program Counter
    PCReg : PCounter port map ( clk => BTNClock,
               wea => PCWrite,
               newaddress => PCNext,
               thisaddress => PC);

    --Incremental adder
    IncAddr : B_adder port map ( a => PC,
               x => PCIncrement);

    --Branch Adder
    BranchAddr : In_adder port map ( a => PC,
                   b => BranchExtend,
                   x => Branch);

    --Next Instruction Address Mux
    NextPCMux : nine_mux port map ( s => BranchSelect,
                   in1 => PCIncrement,
                   in2 => Branch,
                   output => PCNext);

 --Additional Datapath Elements Here
 end Behavioral;

程序计数器:

entity PCounter is
    Port ( clk : in STD_LOGIC; --clock
           wea : in STD_LOGIC; --write enable
           newaddress : in STD_LOGIC_VECTOR (9 downto 0); --new address coming in
           thisaddress : out STD_LOGIC_VECTOR (9 downto 0) --current address to be executed
           );
end PCounter;

architecture Behavioral of PCounter is
    signal reg: std_logic_vector(9 downto 0); --internal register storage

begin
    process(clk) --nothing happens if this register isn't selected
    begin
        if clk'EVENT and clk = '1' then
                thisaddress <= reg; --send out currently saved address
            if wea = '1' then    
                reg <= newaddress; --and set register to next address
            end if;
            else
                reg <= reg; --otherwise, maintain current value
        end if;
    end process; 
end Behavioral;

此加法器只为PC中当前的值添加一个:

entity B_adder is
    Port ( a : in STD_LOGIC_VECTOR (9 downto 0);
           x : out STD_LOGIC_VECTOR (9 downto 0));
end B_adder;

architecture Behavioral of B_adder is

begin

            x <= a + 1;

end Behavioral;

这个小多路复用器将选择下一个地址是来自分支加法器(此处未包含)还是来自上面的增量加法器:

entity nine_mux is
    Port ( s : in STD_LOGIC;
           in1 : in STD_LOGIC_VECTOR (9 downto 0);
           in2 : in STD_LOGIC_VECTOR (9 downto 0);
           output : out STD_LOGIC_VECTOR (9 downto 0));
end nine_mux;

architecture Behavioral of nine_mux is

begin

            with s select
                output <= in1 when '0',
                    in2 when others;


end Behavioral;

这就是控制单元映射到数据路径的方式:

entity WholeThing is
    Port ( BTNClock : in STD_LOGIC;
           BTNReset : in STD_LOGIC;
           SwitchReset : in STD_LOGIC;
           clock : in STD_Logic;
           LEDs : out STD_LOGIC_VECTOR(4 downto 0);
           seg : out STD_LOGIC_vector(6 downto 0);
           an : out STD_LOGIC_vector(7 downto 0);
           alu11 : out STD_LOGIC;
           reg11 : out STD_LOGIC
           );
end WholeThing;

architecture Behavioral of WholeThing is

    signal instruction : STD_LOGIC_VECTOR(31 downto 0);
    signal Reg2Loc : STD_LOGIC;
    signal ALUSRC : std_logic;
    signal MemtoReg : std_logic;
    signal RegWrite : std_logic;
    signal Branch : std_logic;
    signal ALUOp : std_logic_vector (1 downto 0);
    signal UnconB : std_logic;
    signal en : std_logic;
    signal wea : std_logic;
    signal PCWrite : std_logic;
    signal REGCEA : std_logic;
    signal SwRst : STD_LOGIC;

begin

    --SwitchReset <= SwRst;

    --Control Unit
    CU : Fred port map ( Inst => instruction(31 downto 21),
           clk => BTNClock,
           rst => BTNReset,
           Reg2Loc => Reg2Loc,
           ALUSRC => ALUSRC,
           MemtoReg => MemtoReg,
           RegWrite =>RegWrite,
           Branch => Branch,
           ALUOp => ALUOp,
           UnconB => UnconB,
           en => en,
           wea => wea,
           PCWrite => PCWrite,
           REGCEA => REGCEA,
           LEDCode => LEDs);

    --Datapath
    DP : Datapath port map (BTNClock => BTNClock,
           clock => clock,
           UncondBranch => UnconB,
           CondBranch => Branch,
           RRtwoSelect => Reg2Loc,
           RegWriteSelect => RegWrite,
           ALUSource => ALUSRC,
           ALUOpCode => ALUOp,
           WriteSelect => MemtoReg,
           MemWrite => wea,
           REGCEA => REGCEA,
           PCWrite => PCWrite,
           seg_select => seg,
           anode_select => an,
           ins_out => instruction,
           RAMSelect => en,
           ALUEleven => alu11,
           REGEleven => reg11,
           SwitchReset => SwitchReset
           );


end Behavioral;

1 回答

  • 1

    FSM - 主要问题

    您的第二个流程应该实现默认分配,以便在您定义FSM图形的自我边缘时备用大量不必要的其他分支 . 因为你错过了,你的FSM为信号 current_state 创建了额外的锁存器!检查综合报告以获取闩锁警告,您可能会发现其中的多个 .

    同一文件中的其他错误

    • 你混淆了 current_statenext_state . 信号的含义并不反映您的代码!您的case语句需要打开 current_state .

    • 不要使用3过程模式来描述FSM . 这是代码可读性和维护的噩梦!一个人可以阅读并验证此FSM表单的行为 .

    • 您以错误的方式使用属性enum_encoding:

    • 定义FSM编码,将 fsm_encoding 应用于状态信号

    • 定义用户定义的编码,将 fsm_encodinguser 应用于状态信号,并将 enum_encoding 与空格分隔的二进制值列表一起应用于您的状态类型 .

    • 不要使用异步复位 . 同步,时钟进程在灵敏度列表中只有一个信号!

    • 组合过程需要列出灵敏度列表中的所有读取信号!

    • 你不应该使用 clk'EVENT and clk = '1' . 请改用 rising_edge(clk) .

    • 如果多次打开相同的信号,请使用case语句,但不能使用if-elsif构造!

    • 你的眼睛,也许你的LED也不会快到足以看到和显示 LEDCode .

    Corrected code:

    architecture Behavioral of Fred is
      attribute fsm_encoding : string;
    
      type type_fstate is (
        Fetch, L_S_D, L_S_E, L_Mem, S_Mem,
        L_WB, R_I_D, I_E, R_E, I_WB, R_WB, B_E, CBZ_D, B_WB, CBZ_E,
        CBZ_WB);
    
      signal current_state : type_fstate := Fetch;
      signal next_state    : type_fstate;
      attribute fsm_encoding of current_state : signal is "one-hot";
    begin
      clockprocess : process(clk)
      begin 
        if rising_edge(clk) then
          if rst = '1' then
            current_state <= Fetch;
          else
            current_state <= next_state;
          end if;
        end if;
      end process;
    
      state_logic: process (current_state, Inst)
      begin
        next_state <= current_state;
    
        Reg2Loc  <= '0';
        ALUSRC   <= '0';
        MemtoReg <= '0';
        RegWrite <= '0';
        Branch   <= '0';
        ALUOp    <= "00";
        UnconB   <= '0';
        en       <= '0';
        wea      <= '0';
        PCWrite  <= '0';
        REGCEA   <= '0';
        LEDCode  <= "00000";
    
        case current_state is
          when Fetch => --00001
            REGCEA  <= '1';
            LEDCode <= "00001";
    
            case Inst is
              when "11111000010" => --LDUR
                next_state <= L_S_D;
              when "11111000000" => --STUR
                next_state <= L_S_D;                        
    
              --Additional State Logic Here
              when others =>
                next_state <= Fetch;
            end case;
    
          when L_S_D => --00010
            Reg2Loc <= '1';
            LEDCode <= "00010";
    
            next_state <= L_S_E;
    
          when L_S_E => --00011
            Reg2Loc <= '1';
            ALUSRC  <= '1';
            PCWrite <= '1';
            LEDCode <= "00011";
    
            case Inst is
              when "11111000010" =>
                next_state <= L_Mem;
              when "11111000000" =>
                next_state <= S_Mem;
              when others =>
                -- ???
            end case;
    
          when S_Mem => --00110
            Reg2Loc <= '1';
            ALUSRC  <= '1';
            en      <= '1';
            wea     <= '1';
            LEDCode <= "00110";
    
            next_state <= Fetch;
    
          --Additional States Here
    
          when others =>
            next_state <= Fetch;
        end case;
      end process;
    
    end architecture;
    

    PC中的错误:

    • 永远不要在VHDL中分配这样的 reg <= reg

    • 你在类型 std_logic_vector 上使用算术 . 此操作是:

    • 没有为该类型定义,或

    • 你正在使用像 synopsys.std_logic_unsigned 这样的非IEEE软件包,根本不应该使用它 . 如果需要算术运算,请使用包 ieee.numeric_std 并输入 signed / unsigned .

    • 您的程序计数器(PC)不计(但是?) . 基于单一责任原则,您的PC应该能够:

    • 加载新的指令指针

    • 递增指令指针

    • 输出当前指令指针

    • 您的PC为输出 thisaddress 分配一个延迟周期 . 通常,这将破坏任何CPU功能......

    • 当您要在FPGA器件上实现您的设计时,请确保使用适当的初始值初始化所有转换为存储器的信号(例如寄存器) .

    Improved Code:

    architecture Behavioral of PCounter is
      signal reg: unsigned(9 downto 0) := (others => '0');
    begin
    
      process(clk)
      begin
        if rising_edge(clk) then
          if wea = '1' then    
            reg <= unsigned(newaddress);
          end if;
        end if;
      end process; 
    
      thisaddress <= reg;
    end architecture;
    

    你的加法器B_adder

    在消耗9行代码的实体中实现单行是明智的吗?
    此外,您的代码描述的是增量器,而不是加法器 .

    描述多路复用器

    未使用 with ... select 语句描述多路复用器 . 这将创建一个优先级逻辑,如if-elseif分支链 .

    output <= in1 when (s = '0') else in2;
    

    由于这是一个与尺寸无关的单行,因此拧紧了nine_mux实体 .

相关问题