Skip to main content
Tweeted twitter.com/StackCodeReview/status/989313238075674625
edited title
Link
a_sid
  • 435
  • 6
  • 16

VHDL- CPU's Control Unit in VHDL

Source Link
a_sid
  • 435
  • 6
  • 16

VHDL- CPU's Control Unit

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?