VHDL Source Code for Simple 8-bit CPU

 

Taken from http://instruct1.cit.cornell.edu/ee475/

 

 

 

 

 

-- Design for lab 4 of ee475 for spring 1998
 -- The mica cpu + ken's shell
 
 LIBRARY ieee;
 USE ieee.std_logic_1164.all;
 USE ieee.std_logic_unsigned.all;
 
 ENTITY shell IS
      PORT (
            rxdat : IN     std_logic;
            xclk  : IN     std_logic;
            rxstb : IN     std_logic;
            txstb : IN     std_logic;
            txdat : OUT    std_logic;
           
            clk   : IN     std_logic;
            addr  : BUFFER std_logic_vector(15 DOWNTO 0);
            data  : INOUT  std_logic_vector(7 DOWNTO 0);
            rd    : BUFFER std_logic;
            wr    : BUFFER std_logic;
            ramcs : OUT    std_logic;
            sevseg: OUT    std_logic_vector(6 DOWNTO 0)
      );
 END shell;
 
 ARCHITECTURE one OF shell IS
 
       COMPONENT cpu PORT (
                 clk   : IN     std_logic;
                 addr  : BUFFER std_logic_vector(15 DOWNTO 0);
                 data  : INOUT  std_logic_vector(7 DOWNTO 0);
                 rd    : BUFFER std_logic;
                 wr    : BUFFER std_logic;
                 --ramcs : OUT    std_logic;
                 sevseg: OUT    std_logic_vector(6 DOWNTO 0);
                
                 din   : IN     std_logic_vector(15 DOWNTO 0);
                 dout  : OUT    std_logic_vector(7 DOWNTO 0);
                 dsel  : IN     std_logic_vector(1 DOWNTO 0)
      );
      END COMPONENT;
 
         SIGNAL din        : std_logic_vector(15 DOWNTO 0);
         SIGNAL clksel     : std_logic_vector(4 DOWNTO 0);
         SIGNAL dsel       : std_logic_vector(1 DOWNTO 0);
         SIGNAL dout       : std_logic_vector(7 DOWNTO 0);
         SIGNAL txshift    : std_logic_vector(7 DOWNTO 0);
         SIGNAL txshiftnext: std_logic_vector(7 DOWNTO 0);
         SIGNAL rxshift    : std_logic_vector(22 DOWNTO 0);
         SIGNAL clkdiv     : std_logic_vector(23 DOWNTO 0);
         SIGNAL cpuclk     : std_logic;
 BEGIN
      u1: cpu PORT MAP (
            clk    => cpuclk,
            addr   => addr,
            data   => data,
            rd     => rd,
            wr     => wr,
            --ramcs  => ramcs,
            sevseg => sevseg,
 
            din    => din,
            dout   => dout,
            dsel   => dsel
      );
 
 -- select ram
      ramcs <='0';
 -- Drive serial interface
      WITH txstb SELECT
            txshiftnext <= txshift(6 DOWNTO 0)&'0' WHEN '0',
                        dout WHEN OTHERS;
      txrx: PROCESS
      BEGIN
            WAIT UNTIL (xclk'event AND xclk='0');
            rxshift <= rxshift(21 DOWNTO 0)&(NOT rxdat);
            txshift <= txshiftnext;
      END PROCESS txrx;
           
      rx: PROCESS
      BEGIN
            WAIT UNTIL (rxstb'event AND rxstb='1');
            din    <= rxshift(15 DOWNTO 0);
            dsel   <= rxshift(17 DOWNTO 16);
            clksel <= rxshift(22 DOWNTO 18);
      END PROCESS rx;
      txdat <=  txshift(7);
 
 -- Run clock divider
       PROCESS
      BEGIN
            WAIT UNTIL (clk'event AND clk='1');
            clkdiv <= clkdiv + 1;
      END PROCESS;
      WITH clksel SELECT
            cpuclk <= clk WHEN "00000",
                      clkdiv(0) WHEN "00001",
                      clkdiv(1) WHEN "00010",
                      clkdiv(2) WHEN "00011",
                      clkdiv(3) WHEN "00100",
                      clkdiv(4) WHEN "00101",
                      clkdiv(5) WHEN "00110",
                      clkdiv(6) WHEN "00111",
                      clkdiv(7) WHEN "01000",
                      clkdiv(8) WHEN "01001",
                      clkdiv(9) WHEN "01010",
                      clkdiv(10) WHEN "01011",
                      clkdiv(11) WHEN "01100",
                      clkdiv(12) WHEN "01101",
                      clkdiv(13) WHEN "01110",
                      clkdiv(14) WHEN "01111",
                      clkdiv(15) WHEN "10000",
                      clkdiv(16) WHEN "10001",
                      clkdiv(17) WHEN "10010",
                      clkdiv(18) WHEN "10011",
                      clkdiv(19) WHEN "10100",
                      clkdiv(20) WHEN "10101",
                      clkdiv(21) WHEN "10110",
                      clkdiv(22) WHEN "10111",
                      clkdiv(23) WHEN "11000",
                      '0'        WHEN "11110",
                      '1'        WHEN "11111",
                      '0'        WHEN OTHERS;                           
 END one;
 
 ---------------------------------------------------------------------------
 
 
 -- Design based on the MICA architecture from Notre Dame.
 -- CPU is a four register, 8 bit data/instruction, load/store machine.
 LIBRARY ieee;
 USE ieee.std_logic_1164.all;    -- standard logic
 USE ieee.std_logic_unsigned.all; -- arithmetic stuff
 
 ENTITY cpu IS
      PORT(
       clk: IN std_logic;              -- 50% duty cycle clock
       rd: BUFFER std_logic;              -- mem read cntl
       wr: BUFFER std_logic;              -- mem write cntl
       addr: BUFFER std_logic_vector(15 downto 0);-- the address bus
       data: INOUT std_logic_vector(7 downto 0); -- the data bus
       sevseg: OUT std_logic_vector(6 downto 0); -- segven segment display
       
       din   : IN     std_logic_vector(15 DOWNTO 0); -- shell data in
      dout  : OUT    std_logic_vector(7 DOWNTO 0); -- shell data out
      dsel  : IN     std_logic_vector(1 DOWNTO 0)  -- shell data out select
      );
 END cpu;
 
 ARCHITECTURE one OF cpu IS
 
      -- reset signal
      SIGNAL reset: std_logic;
     
      -- cpu state
      SIGNAL fetch, exec: std_logic;
     
      --opcodes
      SIGNAL ld, st, addi, add, inand, isll, inot: std_logic;
      SIGNAL clr, jal, skipn, skipz, br: std_logic;
 
      -- IR, PC
      SIGNAL ir:  std_logic_vector(7 downto 0);       
      --instruction register
      SIGNAL pc:  std_logic_vector(7 downto 0);       
      --program counter
      SIGNAL PCinSel:  std_logic;
      --selects PC load source 0=PC_incrementer 1=Aout
      SIGNAL PCload:  std_logic;
      --gates the PC load
      SIGNAL PCaddSel:  std_logic_vector(1 downto 0);
      --selects PC increment 0=1 1=2 3=displacement
      SIGNAL PCinc:  std_logic_vector(7 downto 0);
      --increment value
      SIGNAL PCin:  std_logic_vector(7 downto 0);
      --PC update
      SIGNAL PCnew:  std_logic_vector(7 downto 0);
      --incrmented PC
     
      -- DATA from IR
      SIGNAL DataImm:  std_logic_vector(7 downto 0);       
      -- 4 bits from IR extended
      SIGNAL disp:  std_logic_vector(2 downto 0);             
      --offset for reg indirect data addr from IR so addr<= disp+Bout
      SIGNAL displacement:  std_logic_vector(7 downto 0);       
      --offset for PC jump from IR so PC <= PC+displacement
 
      -- MEMORY interface
      SIGNAL MASel:  std_logic; 
      --memory address select: 0=PC, 1=disp+(B)
      SIGNAL dataAddr:  std_logic_vector(7 downto 0); 
      --memory data address  1=disp+(B)
      SIGNAL AtoBus:  std_logic;
      --gates the A bus output onto the memory data bus
 
      -- DATA registers
      SIGNAL r0, r1, r2, r3: std_logic_vector(7 downto 0);
      SIGNAL rdata:  std_logic_vector(7 downto 0);
      -- register outputs
      SIGNAL Aout, Bout: std_logic_vector(7 downto 0);
      --register input bus
      SIGNAL RegDSel:  std_logic_vector(1 downto 0);
      --data source for rdata reg write: 0=0 1=PC 2=ALUout 3=data
      SIGNAL ALUBSel:  std_logic_vector(1 downto 0);
      --data source for ALU b input: 0=Bout 1=0 2=1 3=DataImm
      SIGNAL ASel:  std_logic_vector(1 downto 0);
      --selects A register output
      SIGNAL BSel:  std_logic_vector(1 downto 0);
      --selects B register output
      SIGNAL we:  std_logic;
      --enables a register load
 
      -- ALU
      SIGNAL Bin: std_logic_vector(7 downto 0);
      SIGNAL ALUop:  std_logic_vector(1 downto 0);
      --selects ALU function
      SIGNAL ALUout:  std_logic_vector(7 downto 0);
      --ALU result
      SIGNAL zne:  std_logic;
      --gates the Z and N register loads
      SIGNAL z, n:  std_logic;
      --the Z and N registers
 
 
      BEGIN
     
            -- ***********************************
            --debugger shell interface
           
            reset <= din(0);
           
            WITH dsel  SELECT
                     dout <= addr(7 downto 0) WHEN "00" ,
                             data             WHEN "01",          
                         pc                    WHEN "10",    
                         ir               WHEN "11" ,
                         "11111111"       WHEN OTHERS  ;
                         
               -- ***********************************               
            -- 7-seg decoder
            WITH r3(3 downto 0) SELECT
                  sevseg <= "0111111" WHEN "0000",
                          "0000110" WHEN "0001",
                          "1011011" WHEN "0010",
                          "1001111" WHEN "0011",
                          "1100110" WHEN "0100",
                          "1101101" WHEN "0101",
                          "1111101" WHEN "0110",
                          "0000111" WHEN "0111",
                          "1111111" WHEN "1000",
                          "1101111" WHEN "1001",
                          "1110111" WHEN "1010",
                          "1111100" WHEN "1011",
                          "0111001" WHEN "1100",
                          "1011110" WHEN "1101",
                          "1111001" WHEN "1110",
                          "1110001" WHEN OTHERS;
         
            -- ***********************************
            -- OPcode decoder
            ld <= '1' WHEN ir(7 downto 6)="00" ELSE '0'; -- load
           
            st <= '1' WHEN ir(7 downto 6)="01" ELSE '0'; --store
           
            addi <= '1' WHEN ir(7 downto 6)="10" ELSE '0'; --add immediate
           
            add <= '1' WHEN (ir(7 downto 6)="11"
                              AND ir(1 downto 0)="00") ELSE '0'; --add
                             
            inand <= '1' WHEN  (ir(7 downto 6)="11"
                              AND ir(1 downto 0)="01") ELSE '0'; -- nand 
                             
            isll <= '1' WHEN  (ir(7 downto 6)="11"
                              AND ir(3 downto 0)="0010") ELSE '0'; -- shift left 
                             
            inot <= '1' WHEN  (ir(7 downto 6)="11"
                              AND ir(3 downto 0)="0110") ELSE '0'; -- not
 
            clr <= '1' WHEN  (ir(7 downto 6)="11"
                              AND ir(3 downto 0)="1010") ELSE '0'; -- clear reg
                             
            jal <= '1' WHEN  ir(7 downto 0)="11011110" ELSE '0'; -- jump and link 
           
            skipn <= '1' WHEN ir(7 downto 0)="11101110" ELSE '0'; --skip on neg  
                       
            skipz <= '1' WHEN ir(7 downto 0)="11111110" ELSE '0'; -- skip on zero
           
            br       <= '1' WHEN  (ir(7 downto 6)="11"
                              AND ir(1 downto 0)="11") ELSE '0'; -- branch     
                                                                                               
                             
            -- ***********************************
            -- compute memory address
            disp <= ir(2 downto 0);
            dataAddr <= "00000"&disp + Bout;
           
            MASel <= '1' WHEN exec='1' ELSE '0';  
                              
            WITH MASel SELECT
                  addr <= "00000000" & pc       WHEN '0', -- during fetch phase
                         "00000000" & dataAddr    WHEN '1', -- during exec phase
                        "00000000" & pc             WHEN OTHERS;
 
            -- ***********************************
            -- memory read/write control
            rd <= '0' WHEN (ld='1' AND exec='1' AND clk='0' ) -- load data
                                 OR (fetch='1' AND clk='0')         -- fetch inst
                        ELSE '1'; 
                 
            wr <= '0' WHEN (st='1' AND exec='1' AND clk='0')  -- store data
                       ELSE       '1';     
 
            -- A bus to memory
            data <= Aout WHEN wr='0' ELSE "ZZZZZZZZ";  -- floats the bus
                 
 
            -- ***********************************
            -- Program Counter control
           
            PCaddSel <= '0'&n WHEN skipn='1' ELSE -- add 2
                          '0'&z WHEN skipz='1' ELSE -- add 2
                          "10"  WHEN br='1'    ELSE -- add displacment
                          "00";  -- increment when not a branch or skip
                         
            -- sign extend the displacement field
            displacement <= ir(5) & ir(5) & ir(5) & ir(5) & ir(5 downto 2);
 
            WITH PCaddSel SELECT
                  PCinc <= "00000001"   WHEN "00",
                             "00000010"   WHEN "01",
                             displacement WHEN "10",
                             "00000001"   WHEN OTHERS;
           
            PCnew <= pc + PCinc; -- the updated verion of the PC
                         
            PCinSel <= '1' WHEN jal='1' ELSE  '0';
                                 
            WITH PCinSel SELECT
                  PCin <= PCnew   WHEN '0',
                            Aout    WHEN '1',
                            Aout    WHEN OTHERS;
 
            -- ***********************************
            -- register controls
           
            -- set up register data select
            RegDSel <= "11" WHEN ld='1'  ELSE
                         "01" WHEN jal='1' ELSE
                         "00" WHEN clr='1' ELSE
                         "10" ; -- feedback from alu
 
            -- route the input data
            WITH RegDSel SELECT
                  rdata <= "00000000" WHEN "00",
                             pcnew      WHEN "01",
                             ALUout     WHEN "10",
                             data       WHEN "11",
                            "00000000" WHEN OTHERS;
                             
            -- choose a register for output A, jal always loads r2
            ASel <= "10" WHEN jal='1' ELSE ir(5 downto 4) ;             
                 
            -- choose a register for output B, r2 or r3 used for ld/st disp
            BSel <= '1'&ir(3) WHEN (ld='1' OR st='1') ELSE ir(3 downto 2) ;
           
            -- write enable for registers disable for 4 opcodes
            we <= '0' WHEN  st='1' OR br='1' OR skipn='1' OR skipz='1' ELSE '1' ;
 
            -- A output
            WITH ASel SELECT      
                  Aout <= r0 WHEN "00",
                            r1 WHEN "01",
                            r2 WHEN "10",
                            r3 WHEN OTHERS;
 
            -- B output
            WITH BSel SELECT      
                  Bout <= r0 WHEN "00",
                            r1 WHEN "01",
                            r2 WHEN "10",
                            r3 WHEN OTHERS;
 
            -- ***********************************
            -- ALU controls
 
            -- control the B input to the ALU
            ALUbSel <= "11" WHEN addi='1' ELSE -- DataImm
                         "10" WHEN inot='1' ELSE -- const=1
                         "00" ; --Bout
     
            DataImm <= "0000"&ir(3 downto 0);
 
            -- ALU B input
            WITH ALUbSel SELECT           
                  Bin <= Bout       WHEN "00",
                         "00000000" WHEN "01",
                         "11111111" WHEN "10",
                         DataImm    WHEN OTHERS;
           
            -- ALU function control
            ALUop <= "00" WHEN addi='1'  OR add='1' ELSE
                       "01" WHEN inand='1' OR inot='1' ELSE
                       "10" ;-- shift left
 
            -- ALU
            WITH ALUop SELECT
                  ALUout <= Aout + Bin           WHEN "00", -- add and addi
                              NOT (Aout AND Bin)   WHEN "01", -- nand and not
                              Aout(6 downto 0)&'0' WHEN OTHERS; --shift
 
            -- zero and neg flag control
            zne <= '1' WHEN addi='1' OR add='1' OR inand='1'
                                    OR isll='1' OR inot='1' ELSE
                     '0' ;
 
            -- ***********************************
            -- Timing, reset, and register updates
 
            PROCESS (clk, reset) BEGIN
                 
                  IF reset='1' THEN
                        pc <= "00000000"; -- reset to address zero
                        ir <= "00000000"; -- inst is equiv to clear reg 0
                        r3 <= "11111111"; -- for testing
                        fetch <= '1';
                        exec <= '0';
                       
                  ELSIF (clk='1' AND clk'event) THEN
                 
                        IF fetch='1' THEN
                              ir <= data;
                              fetch <= '0';
                              exec <= '1';                      
                        ELSE
                              pc <= PCin;
                              fetch <= '1';
                              exec <= '0';
                              IF we='1' THEN
                                    CASE ASel IS
                                          WHEN "00" => r0 <= rdata;
                                          WHEN "01" => r1 <= rdata;
                                          WHEN "10" => r2 <= rdata;
                                          WHEN "11" => r3 <= rdata;
                                          WHEN OTHERS => NULL;
                                    END CASE;
                              END IF;
                             
                              IF zne='1' THEN
                                    n <= aluout(7);                               
                                    IF aluout=0 THEN
                                          z <= '1';
                                    ELSE
                                          z <= '0';
                                    END IF;
                              END IF;
                        END IF;
                  END IF;
                       
            END PROCESS;
           
      END one;
 
 
 
 

 

Hosted by www.Geocities.ws

1