8
\$\begingroup\$

I have designed the Control Unit of the CPU in VHDL. It works properly and produces the expected simulation waveforms. Nevertheless, I feel that my existing code can be improved considerably.

My control unit essentially consists of three processes: operation decoder (this is the lengthiest process. I explicitly specified the control signals for every one of 25 instructions here), state machine (it describes how the circuit should transition from one state to another) and data-memory controller (it describes how the enable/write-enable signals should be asserted for load/store operations).

My code for the control unit is as follows:

library ieee;
use ieee.std_logic_1164.ALL;

ENTITY ControlUnit IS
PORT(
    clk, mclk : IN STD_LOGIC;
    enable : IN STD_LOGIC;
    statusC, statusZ : IN STD_LOGIC;
    INST : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
    A_Mux, B_Mux : OUT STD_LOGIC;
    IM_MUX1, REG_Mux : OUT STD_LOGIC;
    IM_MUX2, DATA_Mux : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
    ALU_op : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
    inc_PC, ld_PC : OUT STD_LOGIC;
    clr_IR : OUT STD_LOGIC;
    ld_IR : OUT STD_LOGIC;
    clr_A, clr_B, clr_C, clr_Z : OUT STD_LOGIC;
    ld_A, ld_B, ld_C, ld_Z : OUT STD_LOGIC;
    T : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
    wen, en : OUT STD_LOGIC);
END ControlUnit;

ARCHITECTURE description OF ControlUnit IS
    TYPE STATETYPE IS (state_0, state_1, state_2);
    SIGNAL present_state: STATETYPE;
BEGIN
-------- OPERATION DECODER ---------
PROCESS (present_state, INST, statusC, statusZ, enable)
    BEGIN
-------- YOU FILL IN WHAT GOES IN HERE (DON'T FORGET TO CHECK FOR ENABLE)
-------- OUTPUT ASSIGNMENTS
                                    -- STATE T0
        IF (enable = '1') THEN
            IF (present_state = state_0) THEN --IR <= M[INST]
                clr_IR <= '0';
                ld_IR <= '1';
                ld_PC <= '0';
                inc_PC <= '0';
                clr_A <= '0';
                ld_A <= '0';
                clr_B <= '0';
                ld_B <= '0';
                clr_C <= '0';
                ld_C <= '0';
                clr_Z <= '0';
                ld_Z <= '0';
                ALU_op <= "000";
                A_Mux <= 'X';
                B_Mux <= 'X';
                REG_Mux <= 'X';
                DATA_Mux <= "00";
                IM_MUX1 <= '0';
                IM_MUX2 <= "00";
                                    -- STATE T1


                                                -- STATE T2
            ELSIF(present_state = state_1) THEN

            if (INST(31 DOWNTO 28)="0000") then --LDAI
                            clr_IR <= '0';
                            ld_IR <= '0';
                            --ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";
                            A_Mux <= '1';
                            REG_Mux <= 'X';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                            elsif (INST(31 DOWNTO 28)="0001") then
                    --LDBI
                            B_Mux <= '1';
                            clr_IR <= '0';
                            ld_IR <= '0';
                            --ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '1';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";
                            A_Mux <= '0';
                            B_Mux <= '1';
                            B_Mux <= '1';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                            elsif (INST(31 DOWNTO 28)="0010") then --STA
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';

                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";                            
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                            elsif (INST(31 DOWNTO 28)="0011") then --STB
                            clr_IR <= '0';
                            ld_IR <= '0';
                            --ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";                            
                            A_Mux <= '0';
                            REG_Mux <= '1';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
    IM_MUX2 <= "00";
                        end if;
                        inc_PC <= '1';
                        ld_PC <= '1';
            ELSIF(present_state = state_2) THEN
                B_Mux <= '1';
                inc_PC <= '0';
                CASE INST(31 DOWNTO 24) IS
                    WHEN "01110000" => --ADD
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "010";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01110001" => --ADDI
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "010";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "01";
                        WHEN "01110010" => --SUB
    clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "110";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01110011" => --INCA
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "010";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "10";
            WHEN "01110100" => --ROL
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "100";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01110101" => --CLRA
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '1';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01110110" => --CLRB
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '1';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01110111" => --CLRC
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '0';
            clr_C <= '1';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01111000" => --CLRZ
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '1';
                            ld_Z <= '0';
                            ALU_op <= "000";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01111001" => --ANDI
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "000";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "01";
                    WHEN "01111011" => --AND
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "000";
                            A_Mux <= '0';
            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "01111010" => --Checks for zero flag
                            IF (statusZ = '1') THEN
                                clr_IR <= '0';
                                ld_IR <= '0';
                                ld_PC <= '0';
                                inc_PC <= '1';
                                clr_A <= '0';
                                ld_A <= '0';
                                clr_B <= '0';
                                ld_B <= '0';
                                clr_C <= '0';
                                ld_C <= '0';
                                clr_Z <= '0';
                                ld_Z <= '0';
                                ALU_op <= "000";
                                A_Mux <= '0';
                                REG_Mux <= '0';
                                DATA_Mux <= "00";
                                IM_MUX1 <= '0';
                                IM_MUX2 <= "00";
                            END IF;
                        WHEN "01111100" => --Checks for carry flag
                            IF (statusC = '1') THEN
                                clr_IR <= '0';
                                ld_IR <= '0';
                                ld_PC <= '0';
                                inc_PC <= '1';
                                clr_A <= '0';
                                ld_A <= '0';
                                clr_B <= '0';
                                ld_B <= '0';
                                clr_C <= '0';
                                ld_C <= '0';
                                clr_Z <= '0';
                                ld_Z <= '0';
                                ALU_op <= "000";

                                A_Mux <= '0';
                                REG_Mux <= '0';
                                DATA_Mux <= "00";
                                IM_MUX1 <= '0';
                                IM_MUX2 <= "00";
                            END IF;
                        WHEN "01111101" => --ORI
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "001";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "01";
                        WHEN "01111110" => --DECA
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "110";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "10";
                        WHEN "01111111" => --ROR
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '1';
                            clr_Z <= '0';
                            ld_Z <= '1';
                            ALU_op <= "111";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                    WHEN OTHERS =>
                            NULL;
                END CASE;

                    CASE INST(31 DOWNTO 28) IS
                        WHEN "0100" => --LUI
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '1';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "001";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "10";
                            IM_MUX1 <= '1';
                            IM_MUX2 <= "00";
                        WHEN "0101" => --JMP
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '1';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";

                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "00";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN "0110" => --BEQ
                            IF (statusZ = '1') THEN
        clr_IR <= '0';
                                ld_IR <= '0';
                                ld_PC <= '1';
                                clr_A <= '0';
                                ld_A <= '0';
                                clr_B <= '0';
                                ld_B <= '0';
                                clr_C <= '0';
                                ld_C <= '0';
                                clr_Z <= '0';
                                ld_Z <= '0';
                                ALU_op <= "000";

                                A_Mux <= '0';
                                REG_Mux <= '0';
                                DATA_Mux <= "00";
                                IM_MUX1 <= '0';
                                IM_MUX2 <= "00";
                            ELSE
                                clr_IR <= '0';
                                ld_IR <= '0';
                                ld_PC <= '0';
                                clr_A <= '0';
                                ld_A <= '0';
                                clr_B <= '0';
                                ld_B <= '0';
                                clr_C <= '0';
                                ld_C <= '0';
                                clr_Z <= '0';
                                ld_Z <= '0';
                                ALU_op <= "000";

                                A_Mux <= '0';
                                REG_Mux <= '0';
                                DATA_Mux <= "00";
                                IM_MUX1 <= '0';
                                IM_MUX2 <= "00";
                            END IF;
                        WHEN "1000" => --BNE
                            IF (statusZ = '0') THEN
                                clr_IR <= '0';
                                ld_IR <= '0';
                                ld_PC <= '1';
                                clr_A <= '0';
                                ld_A <= '0';
                                clr_B <= '0';
                                ld_B <= '0';
                                clr_C <= '0';
                                ld_C <= '0';
                                clr_Z <= '0';
                                ld_Z <= '0';
                                ALU_op <= "000";
                                A_Mux <= '0';
                                REG_Mux <= '0';
                                DATA_Mux <= "00";
                                IM_MUX1 <= '0';
                                IM_MUX2 <= "00";
                            ELSE
                                clr_IR <= '0';
                                ld_IR <= '0';
                                ld_PC <= '0';
                                clr_A <= '0';
                                ld_A <= '0';
                                clr_B <= '0';
                                ld_B <= '0';
                                clr_C <= '0';
                                ld_C <= '0';
                                clr_Z <= '0';
                                ld_Z <= '0';
                                ALU_op <= "000";

                                A_Mux <= '0';
                                REG_Mux <= '0';
                                DATA_Mux <= "00";
                                IM_MUX1 <= '0';
                                IM_MUX2 <= "00";
                            END IF;
                        WHEN "1001" => --LDA
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '1';
                            clr_B <= '0';
                            ld_B <= '0';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";
                            A_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "01";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                    WHEN "1010" => --LDB
                            clr_IR <= '0';
                            ld_IR <= '0';
                            ld_PC <= '0';
                            clr_A <= '0';
                            ld_A <= '0';
                            clr_B <= '0';
                            ld_B <= '1';
                            clr_C <= '0';
                            ld_C <= '0';
                            clr_Z <= '0';
                            ld_Z <= '0';
                            ALU_op <= "000";
                            A_Mux <= '0';
                            B_Mux <= '0';
                            REG_Mux <= '0';
                            DATA_Mux <= "01";
                            IM_MUX1 <= '0';
                            IM_MUX2 <= "00";
                        WHEN OTHERS =>
                            NULL;
                END CASE;
                ld_IR <= '0';
            END IF;
        END IF;
END process;
-------- STATE MACHINE ---------
PROCESS (clk, enable)
    begin
        IF (clk'EVENT AND clk='1' AND enable='1') THEN
            CASE present_state IS
                WHEN state_0 =>
                    T <= "010";
                    present_state <= state_1;
                WHEN state_1 =>
                    T <= "100";
                    present_state <= state_2;
                WHEN state_2 =>
                    T <= "001";
                    present_state <= state_0;
            END CASE;
        ELSIF (clk='1' AND clk'EVENT) THEN
            T <= "001";
            present_state <= state_0;
        END IF;
END process;
-------- DATA MEMORY INSTRUCTIONS ---------
PROCESS (mclk, clk, INST)
BEGIN
    IF(mclk'EVENT and mclk = '0') THEN
        IF(present_state = state_1 AND clk = '0') THEN
            CASE INST(31 DOWNTO 28) IS
            -- LDA and LDB Signals
                WHEN "1001" =>
                    en <= '1';
                    wen <= '0';
                WHEN "1010" =>
                    en <= '1';
                    wen <= '0';
            -- STA and STB Signals
                WHEN "0010" =>
                    en <= '1';
                    wen <= '1';
                WHEN "0011" =>
                    en <= '1';
                    wen <= '1';
            -- Default Case Signals
                WHEN OTHERS =>
                    en <= '0';
                    wen <= '0';
            END CASE;
        ELSIF(present_state = state_2 AND clk = '1') THEN
            -- LDA and LDB
            -- STA and STB
            CASE INST(31 DOWNTO 28) IS
            -- LDA and LDB Signals
                WHEN "1001" =>
                    en <= '1';
                    wen <= '0';
                WHEN "1010" =>
                    en <= '1';
                    wen <= '0';
            -- STA and STB Signals
                WHEN "0010" =>
                    en <= '1';
                    wen <= '1';
                WHEN "0011" =>
                    en <= '1';
                    wen <= '1';
    -- Default Case
            WHEN OTHERS =>
                    en  <= '0';
                    wen <= '0';
            END CASE;
        ELSIF(present_state = state_1) THEN -- or alternatively just an ELSE statement
-- fill in
                    en  <= '0';
                    wen <= '0';
        END IF;
    END IF;
END process;
END description;

Being a beginner in VHDL, I am struggling to see how exactly I can further improve this code.

Can you suggest any improvements for the VHDL program I have posted here?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ This is impossible to read: just A LOT of signals being set. We need lots of comments explaining what is happening. Why are you doing everything in one process? And post a complete example, including test bench. \$\endgroup\$ – JHBonarius Jun 4 '18 at 18:20
  • 1
    \$\begingroup\$ please see my updated answer, I've added some tips on operation decoding. so you don't have to use "1001" etc any more, but use names. This is optional, but give much more readable code. p.s. I didn't use it everywhere. Just for the arithmetic for example. \$\endgroup\$ – JHBonarius Jun 5 '18 at 8:40
4
\$\begingroup\$

Well, this is quite decent VHDL for a beginner compared to much of the code I see at StackOverflow. But:

  • your code's not commented
  • you're not using default assignment
  • your state names are non descriptive
  • try to stay consistent with using when or if for decoding.
  • Never(!) assign 'X' to a signal. 'X' means "error, cannot be resolved" or "short circuit". Only assign '0', '1', or 'Z' (for tristate).

This is a somewhat cleaned code:

library ieee;
use ieee.std_logic_1164.all;

entity controlunit is
    port(
        clk, mclk : in std_logic;
        enable : in std_logic;
        statusc, statusz : in std_logic;
        inst : in std_logic_vector(31 downto 0);
        a_mux, b_mux : out std_logic;
        im_mux1, reg_mux : out std_logic;
        im_mux2, data_mux : out std_logic_vector(1 downto 0);
        alu_op : out std_logic_vector(2 downto 0);
        inc_pc, ld_pc : out std_logic;
        clr_ir : out std_logic;
        ld_ir : out std_logic;
        clr_a, clr_b, clr_c, clr_z : out std_logic;
        ld_a, ld_b, ld_c, ld_z : out std_logic;
        t : out std_logic_vector(2 downto 0);
        wen, en : out std_logic);
end entity;

architecture description of controlunit is
    type state_type is (state_0, state_1, state_2);
    signal present_state: state_type := state_0;

    subtype slv4 is std_logic_vector(3 downto 0);
    alias mem_inst: slv4 is inst(31 downto 28);
    constant do_arith : slv4 := "0111";
    alias arith_inst: slv4 is inst(27 downto 24);
    type arith_type is ( op_add, op_addi, op_sub, op_inca, op_rol, op_clra, op_clrb, op_clrc, op_clrz,
        op_andi, op_and, op_checkz, op_checkc, op_ori, op_deca, op_ror );
    signal arith_op: arith_type;
    use ieee.numeric_std.all;
begin
    arith_op <= arith_type'val(to_integer(unsigned(arith_inst)));
    -------- operation decoder ---------
    op_decoder: process (present_state, inst, statusc, statusz, enable) begin
        -- default assignment
        clr_ir <= '0';
        ld_ir <= '0';
        ld_pc <= '0';
        clr_a <= '0';
        ld_a <= '0';
        clr_b <= '0';
        ld_b <= '0';
        clr_c <= '0';
        ld_c <= '0';
        clr_z <= '0';
        ld_z <= '0';
        alu_op <= (others => '0');
        a_mux <= '0';
        b_mux <= '0';
        reg_mux <= '0';
        data_mux <= (others => '0');
        im_mux1 <= '0';
        im_mux2 <= (others => '0');

        -------- you fill in what goes in here (don't forget to check for enable)
        -------- output assignments
        if enable = '1' then
            case present_state is
                -- state t0
                when state_0 => --ir <= m[inst]
                    ld_ir <= '1';
                    --a_mux <= 'X'; -- what is this!!?!??!? never assign 'X'!
                    --b_mux <= 'X';
                    --reg_mux <= 'X';
                -- state t1
                when state_1 =>
                    case mem_inst is
                        when "0000" => --ldai
                            ld_a <= '1';
                            a_mux <= '1';
                            --reg_mux <= 'X';
                        when "0001" => --ldbi
                            b_mux <= '1';
                            ld_b <= '1';
                            b_mux <= '1';
                            b_mux <= '1';
                        --when "0010" => --sta
                        --    null;
                        when "0011" => --stb
                            reg_mux <= '1';
                        when others =>
                            null;
                    end case;
                    inc_pc <= '1';
                    ld_pc <= '1';
                -- state t2
                when state_2 =>
                    b_mux <= '1';
                    case mem_inst is
                        when "0100" => --lui
                            ld_a <= '1';
                            clr_b <= '1';
                            alu_op <= "001";
                            data_mux <= "10";
                            im_mux1 <= '1';
                        when "0101" => --jmp
                            ld_pc <= '1';
                        when "0110" => --beq
                            if (statusz = '1') then
                                ld_pc <= '1';
                            end if;
                        when do_arith => -- arithmetic
                            case arith_op is
                                when op_add =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "010";
                                    data_mux <= "10";
                                when op_addi =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "010";
                                    data_mux <= "10";
                                    im_mux2 <= "01";
                                when op_sub =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "110";
                                    data_mux <= "10";
                                when op_inca =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "010";
                                    data_mux <= "10";
                                    im_mux2 <= "10";
                                when op_rol =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "100";
                                    data_mux <= "10";
                                when op_clra =>
                                    clr_a <= '1';
                                when op_clrb =>
                                    clr_b <= '1';
                                when op_clrc =>
                                    clr_c <= '1';
                                when op_clrz =>
                                    clr_z <= '1';
                                when op_andi =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    data_mux <= "10";
                                    im_mux2 <= "01";
                                when op_and =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    data_mux <= "10";
                                when op_checkz =>
                                    if (statusz = '1') then
                                        inc_pc <= '1';
                                    end if;
                                when op_checkc =>
                                    if (statusc = '1') then
                                        inc_pc <= '1';
                                    end if;
                                when op_ori =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "001";
                                    data_mux <= "10";
                                    im_mux2 <= "01";
                                when op_deca =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "110";
                                    data_mux <= "10";
                                    im_mux2 <= "10";
                                when op_ror =>
                                    ld_a <= '1';
                                    ld_c <= '1';
                                    ld_z <= '1';
                                    alu_op <= "111";
                                    data_mux <= "10";
                                when others =>
                                    null;
                            end case;
                        when "1000" => --bne
                            if (statusz = '0') then
                                ld_pc <= '1';
                            end if;
                        when "1001" => --lda
                            ld_a <= '1';
                            data_mux <= "01";
                        when "1010" => --ldb
                            ld_b <= '1';
                            data_mux <= "01";
                        when others =>
                            null;
                    end case;
            end case;
        end if;
    end process;

    -------- state machine ---------
    state_machine: process (clk) begin
        if rising_edge(clk) then
            if enable = '1' then
                case present_state is
                    when state_0 =>
                        present_state <= state_1;
                    when state_1 =>
                        present_state <= state_2;
                    when state_2 =>
                        present_state <= state_0;
                    when others =>
                        present_state <= state_0;
                end case;
            else
                present_state <= state_0;
            end if;
        end if;
    end process;

    -- t seems to be directly related to the state
    assign_t: process (present_state) begin
        t <= (others => '0');
        t(state_type'pos(present_state) + 1) <= '1';
    end process;

    -------- data memory instructions ---------
    data_mem_inst: process (mclk) begin
        if rising_edge(mclk) then
            if (present_state = state_1 and clk = '0') or
               (present_state = state_2 and clk = '1') then
                case mem_inst is
                -- lda and ldb signals
                    when "1001" | "1010" =>
                        en <= '1';
                        wen <= '0';
                -- sta and stb signals
                    when "0010" | "0011" =>
                        en <= '1';
                        wen <= '1';
                -- default case signals
                    when others =>
                        en <= '0';
                        wen <= '0';
                end case;
            elsif present_state = state_1 then -- or alternatively just an else statement
    -- fill in
                en  <= '0';
                wen <= '0';
            end if;
        end if;
    end process;
end architecture;
\$\endgroup\$
6
  • \$\begingroup\$ Thank you for this answer. It has enhanced my knowledge of VHDL. \$\endgroup\$ – a_sid Jun 6 '18 at 8:42
  • 1
    \$\begingroup\$ @a_sid I'm a bit worried about your "data memory instructions" process: you seem to use two clocks. Unless mclk is much fasted then clk and clk is edge-synchronized to mclk you could be asking for problems here... \$\endgroup\$ – JHBonarius Jun 6 '18 at 9:29
  • \$\begingroup\$ It is indeed faster than clk. \$\endgroup\$ – a_sid Jun 6 '18 at 12:42
  • \$\begingroup\$ inst: in std_logic_vector (31 downto 24); \$\endgroup\$ – user71246 May 17 '19 at 20:42
  • \$\begingroup\$ @user71246 I wouldn't do that, as you can easily make the mistake of connecting e.g. (3 downto 0) to (31 downto 24). Keep the 32-bit interfaces and let the tooling do the optimizations. \$\endgroup\$ – JHBonarius May 18 '19 at 20:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.