Search code examples
vhdldiagramwaveform

My VHDL waveform diagram is wrong


I'm currently working on some VHDL code to make a CPU using the program DesignWorks 5. My waveform diagram of my circuit isn't outputting what it should. All my code compiles fine. Is there anyway to fix this? I feel like I've missed something small and stupid. Thank you in advance for the help. (I don't have enough reputation to post 2 links!)

Here is what the waveform for the circuit should look like: imgur.com/IBtoFuO

What the waveform should look like

Here is what my waveform is showing: imgur.com/rcRTrLR

what my waveform is showing

Here is what the CPU looks like: imgur.com/Ek1G3rZ

What the CPU looks like

Here is what the state machine diagram looks like: imgur.com/AeCaPof

what the state mchine diagram looks like

I have code in separate files for each of the 3 entities. The SEQ is my state transition, the CALC is my asserted output transition, and the M is my memory which was provided.

Here is my state transition code:

library IEEE;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_1164.all;

--Finish Entity Definition
entity SEQ is
    port(clk, st, lt, eq : in std_logic;
         opc : in std_logic_vector(11 downto 9);
         rdy : in std_logic;
         new_state : out std_logic_vector(3 downto 0));  --entity transfers over
end SEQ;

architecture behav of SEQ is 
begin
--state transition process
    process is 
    variable curr_state : std_logic_vector(3 downto 0) := "1101";
    begin
    if clk = '1' then
    case curr_state is
        when "0000" => curr_state := "0001"; 
        when "0001" => curr_state := "0010";
        when "0010" => curr_state := "0011";
        when "0011" => curr_state := "0100";
        when "0100" => 
            if    opc = "000" then curr_state := "1101";
            elsif opc = "001" then curr_state := "0101";
            elsif opc = "010" then curr_state := "0110";
            elsif opc = "011" then curr_state := "0111";
            elsif opc = "100" then curr_state := "1000";
            elsif opc = "101" then curr_state := "1001";
            elsif opc = "110" then curr_state := "1010";
            elsif opc = "111" then curr_state := "1011";
            end if;
        when "0101" => curr_state := "0001"; 
        when "0110" => curr_state := "0001";
        when "0111" => curr_state := "0001";
        when "1000" => curr_state := "0001";
        when "1001" =>
            if rdy = '1' then curr_state := "0001";
            elsif rdy = '0' then curr_state := "1001";
            end if;
        when "1010" => 
            if eq = '1' then curr_state := "1100";
            elsif eq = '0' then curr_state := "0001";
            end if;
        when "1011" => 
            if lt = '1' then curr_state := "1100";
            elsif lt = '0' then curr_state := "0001";
            end if;
        when "1100" => curr_state := "0001";
        when "1101" => 
            if st = '1' then curr_state := "1101";
            elsif st = '0' then curr_state := "0000";
            end if;
    end case;
    wait on clk;
    new_state <= curr_state;
    end if;
    end process;
end behav;

Here is my asserted outputs code:

library IEEE;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_1164.all;

--Entity Definition
entity CALC is
    port( clk, cs, r, req, lt, eq : in std_logic;           
          new_state : in std_logic_vector(3 downto 0);
          opc : in std_logic_vector(11 downto 9);
          addr : in std_logic_vector(8 downto 0); -- 2^9
          d0 : in std_logic_vector(11 downto 0);
          d1 : out std_logic_vector(11 downto 0)); --ignore stuff on arrows
end CALC;

architecture behav of CALC is 
type memory is array(0 to 7) of std_logic_vector(11 downto 0);
begin
--Asserted output process
    process is
    variable curr_state : std_logic_vector(3 downto 0) := "1101";
    variable cs_val, r_val, req_val, lt_val, eq_val: std_logic;
    variable opc_val:std_logic_vector(11 downto 9);
    variable IR: std_logic_vector(11 downto 0);
    variable i, j, k, tmp1 , tmp2, value, displ : integer;
    variable R : memory;
    variable PC, addr_val : std_logic_vector(8 downto 0);
    variable dummy : std_logic_vector(5 downto 0);  --Ignore this
    begin
        case new_state is
        when "0000" => PC := "000000000";
        when "0001" => addr_val := PC; cs_val := '1'; r_val := '1';
        when "0010" => IR := d0; 
                       PC := PC + "000000001"; 
        when "0011" => opc_val := IR(11 downto 9); 
                       i := to_integer(IR(8 downto 6)); 
                       j := to_integer(IR(5 downto 3)); 
                       k := to_integer(IR(2 downto 0)); 
                       value := to_integer(IR(8 downto 3)); 
                       displ := to_integer(IR(8 downto 3))-1;
        when "0100" => if k = 1 then eq_val := '1';
                       else eq_val := '0';
                       end if;
                       if k = 2 then lt_val := '1';
                       else lt_val := '0';
                       end if;
        when "0101" => tmp1 := to_integer(R(i));
                       tmp2 := to_integer(R(j));
                       k := (tmp1 + tmp2);
        when "0110" => tmp1 := to_integer(R(i));
                       tmp2 := to_integer(R(j));
                       k := (tmp1 - tmp2);
        when "0111" => if ((i<j) and (i=j)) then k := 1;
                       else k := 0;
                       end if;
        when "1000" => d1 <=  R(k);
                       req_val := '1';
        when "1010" =>
        when "1011" =>
        when "1100" => PC := PC + displ;
        end case;
        cs <= cs_val;
        wait on new_state;
    end process;
end behav;

Solution

  • First, you should switch to using more standard logic for running SEQ on a clock edge, especially if you ever want to synthesize it. Something like "if rising_edge(clk) then" is great if you have whatever package that comes from imported (escapes my memory right now) otherwise something like "if clk'event AND clk='1' then". I'd also highly recommend named states instead of using the bit vectors to improve readability.

    In CALC, the only output signal you ever assign is cs. And you assign it the value of a variable that is only assigned in state 0001. So it will start at X and (possibly, at some point) transition to a '1' forever.

    Both blocks read opc, so unless you have some outside device driving both (which wouldn't match your diagram), that is wrong. It looks like CALC should be driving opc, but it would need to A) make that an output port, and B) actually assign something to it (I'm guessing the variable opc_val is a good candidate).

    If you've come from traditional programming languages, I can understand why you'd like variables so much, but if you try to avoid using them you'll be a lot happier. Most simulation tools provide limited support for viewing variables, and it's really easy to write VHDL that synthesizes into something terrible with variables as they allow you to accidently put long dependency chains in your logic based on the order of your statements. So, if possible, I'd get rid of as many of those variables as possible and turn them into signals. You only need variables if you want to read the value in the same delta cycle, and you are doing that almost never (if, instead of assigning a variable called cs_val and then assigning that to the signal cs, you just assigned to cs, it wouldn't change the meaning of your code at all).