-------------------------------------------------------------------------------
--  EE126 Basic Computer
--  From the Textbook: "Computer System Architecture" By M. Morris Mano
--  Coded by: Frank Bruno
--  For Professor Chang as part of a VHDL project towards a degree of
--  Masters of Science in Electrical Engineering at Tufts University.
-------------------------------------------------------------------------------

USE work.bv_arithmetic.ALL;

ENTITY basic_comp IS
  PORT(clock            : IN     bit;
       load             : IN     bit;
       start            : IN     bit;
       reset            : IN     bit;
       address_in       : IN     integer range 0 to 4095;
       instr            : IN     bit_vector(15 DOWNTO 0);
       inpr             : IN     bit_vector(7 DOWNTO 0);
       fgi              : IN     bit;
       ar               : BUFFER bit_vector(11 DOWNTO 0);
       ir               : BUFFER bit_vector(15 DOWNTO 0);
       tr               : BUFFER bit_vector(11 DOWNTO 0);
       dr               : BUFFER bit_vector(11 DOWNTO 0);
       i                : BUFFER bit;
       e                : BUFFER bit;
       ac               : BUFFER bit_vector(15 DOWNTO 0);
       ien              : BUFFER bit;
       outr             : BUFFER bit_vector(7 DOWNTO 0);
       fgo              : BUFFER bit
       );
       
END basic_comp;

ARCHITECTURE behave_basic OF basic_comp IS
  COMPONENT basic_mem
    PORT(ar                 : IN      bit_vector(11 DOWNTO 0);
         start              : IN      bit;
         clock              : IN      bit;
         load               : IN      bit;
         instr              : IN      bit_vector(15 DOWNTO 0);
         mem_in             : OUT      bit_vector(15 DOWNTO 0);
         address_in         : IN      integer range 0 to 4095;
         mem_out            : IN  bit_vector(15 DOWNTO 0);
         mem_load           : IN      bit
         );
  END COMPONENT;
  SIGNAL halt : bit;
  SIGNAL fgi_int : bit;
  SIGNAL pc : bit_vector(11 DOWNTO 0);
  SIGNAL mem_in : bit_vector(15 DOWNTO 0);
  SIGNAL mem_out : bit_vector(15 DOWNTO 0);
  SIGNAL mem_load : bit;
  
BEGIN  --  behave_basic 

  u1: basic_mem
  PORT MAP(ar => ar,
           start => start,
           clock => clock,
           load => load,
           instr => instr,
           mem_in => mem_in,
           address_in => address_in,
           mem_out => mem_out,
           mem_load => mem_load);
  PROCESS
    VARIABLE cycle : integer := 0;
    VARIABLE temp_add : integer;
    VARIABLE temp_pc : integer range 0 to 4095;
    VARIABLE temp_ac : integer;
    VARIABLE temp_ar : integer range 0 to 4095;
    VARIABLE temp_dr : integer range 0 to 4095;
    VARIABLE temp : bit;
    VARIABLE dr_temp : bit_vector(15 DOWNTO 0);
    VARIABLE temp_output : bit_vector(16 DOWNTO 0);
    BEGIN
      WAIT UNTIL clock'EVENT AND clock = '1';

      IF (reset = '1') THEN
        pc <= (others => '0');
        halt <= '1';
      END IF;
      
      IF (fgi = '1') THEN
        fgi_int <= '1';
      END IF;

      IF (start = '1') THEN
        halt <= '0';
        pc <= (others => '0');
      END IF;
      
      IF (halt = '0') THEN
      CASE cycle IS
        
-------------------------------------------------------------------------------
--  fetch cycles
-------------------------------------------------------------------------------
        WHEN 0 =>
          mem_load <= '0';
-------------------------------------------------------------------------------
--  Interupt routine start
-------------------------------------------------------------------------------
          IF ((ien = '1') AND (fgi_int = '1' OR fgo = '1')) THEN
            ar <= (others => '0');
            tr <= pc;
            cycle := 99;
            
-------------------------------------------------------------------------------
--  regular fetch cycle
-------------------------------------------------------------------------------
          ELSE
            ar <= pc;
            cycle := 1;
          END IF;
          
        WHEN 1 =>
          ir <= mem_in;
          temp_pc := bvtoi(pc);
          temp_pc := temp_pc + 1;
          pc <= itobv(temp_pc, 12);
          cycle := 2;
          
-------------------------------------------------------------------------------
--  Decode Cycle
-------------------------------------------------------------------------------
        WHEN 2 =>
          ar <= ir(11 DOWNTO 0);
          i <= ir(15);
          IF (ir(15 DOWNTO 12) = "0111") THEN
            cycle := 11;
          ELSIF (ir(15 DOWNTO 12) = "1111") THEN
            cycle := 12;
          ELSE
            cycle := 3;
          END IF;

        WHEN 3 =>
          
-------------------------------------------------------------------------------
--  Indirect Cycle if i = 1
-------------------------------------------------------------------------------
          IF (i = '1') THEN              --  indirect op
            ar <= mem_in(11 DOWNTO 0);
          END IF;
          cycle := 4;

-------------------------------------------------------------------------------
--  Memory Reference Instructions
-------------------------------------------------------------------------------
        WHEN 4 =>
          CASE ir(14 DOWNTO 12) IS
            
-------------------------------------------------------------------------------
--  AND
-------------------------------------------------------------------------------
            WHEN "000" =>
              dr <= mem_in(11 DOWNTO 0);
              cycle := 5;
              
-------------------------------------------------------------------------------
--  ADD
-------------------------------------------------------------------------------
            WHEN "001" =>
              dr <= mem_in(11 DOWNTO 0);
              cycle := 6;

-------------------------------------------------------------------------------
--  LDA
-------------------------------------------------------------------------------
            WHEN "010" =>
              dr <= mem_in(11 DOWNTO 0);
              cycle := 7;

-------------------------------------------------------------------------------
--  STA
-------------------------------------------------------------------------------
            WHEN "011" =>
              mem_load <= '1';
              mem_out <= ac;
              cycle := 0;

-------------------------------------------------------------------------------
--  BUN
-------------------------------------------------------------------------------
            WHEN "100" =>
              pc <= ir(11 DOWNTO 0);
              cycle := 0;
              
-------------------------------------------------------------------------------
--  BSA
-------------------------------------------------------------------------------
            WHEN "101" =>
              mem_load <= '1';
              mem_out(11 DOWNTO 0) <= pc;
              temp_ar := bvtoi(ar);
              temp_add := temp_ar + 1;
              ar <= itobv(temp_ar, 12);
              cycle := 8;

-------------------------------------------------------------------------------
--  ISZ
-------------------------------------------------------------------------------
            WHEN "110" =>
              dr <= mem_in(11 DOWNTO 0);
              cycle := 9;
            WHEN others => 
          END CASE;                      --  ir(14 DOWNTO 12)

-------------------------------------------------------------------------------
--  AND Cycle continued
-------------------------------------------------------------------------------
        WHEN 5 =>
          dr_temp(11 DOWNTO 0) := dr;
          ac <= ac AND dr_temp;
          cycle := 0;

-------------------------------------------------------------------------------
--  ADD Continued
-------------------------------------------------------------------------------
        WHEN 6 =>
          temp_ac := sbvtoi(ac);
          temp_dr := sbvtoi(dr);
          temp_add := temp_ac + temp_dr;
          temp_output := ac + dr;
          ac <= ac + dr;
          e <= temp_output(16);
          cycle := 0;

-------------------------------------------------------------------------------
--  LDA continued
-------------------------------------------------------------------------------
        WHEN 7 =>
          ac(11 DOWNTO 0) <= dr;
          ac(15 DOWNTO 12)  <= (others => '0');
          cycle := 0;

-------------------------------------------------------------------------------
--  BUN continued
-------------------------------------------------------------------------------
        WHEN 8 =>
          pc <= ar;
          mem_load <= '0';
          cycle := 0;

-------------------------------------------------------------------------------
--  ISZ continued
-------------------------------------------------------------------------------
        WHEN 9 =>
          --temp_dr := bvtoi(dr);
          --temp_add := temp_dr + 1;
          --dr <= itobv(temp_dr, 11);
          dr <= dr + "000000000001";
          cycle := 10;
        WHEN 10 =>
          mem_load <= '1';
          mem_out(11 downto 0) <= dr;
          IF (dr = "000000000000") THEN
            pc <= pc + "000000000001";
          END IF;
          cycle := 0;

-------------------------------------------------------------------------------
--  Register reference instructions
-------------------------------------------------------------------------------
        WHEN 11 =>
          CASE ir(11 DOWNTO 0) IS
            
-------------------------------------------------------------------------------
--  CLA
-------------------------------------------------------------------------------
            WHEN "100000000000" =>
              ac <= (others => '0');
              
-------------------------------------------------------------------------------
--  CLE
-------------------------------------------------------------------------------
            WHEN "010000000000" =>
              e <= '0';
              
-------------------------------------------------------------------------------
--  CMA
-------------------------------------------------------------------------------
            WHEN "001000000000" =>
              ac <= NOT(ac);
              
-------------------------------------------------------------------------------
--  CME
-------------------------------------------------------------------------------
            WHEN "000100000000" =>
              e <= NOT(e);
              
-------------------------------------------------------------------------------
--  CIR
-------------------------------------------------------------------------------
            WHEN "000010000000" =>
              temp := ac(0);
              FOR i IN 0 to 14 LOOP
                ac(i) <= ac(i+1);
              END LOOP;                  --  i
              ac(15) <= e;
              e <= temp;
              
-------------------------------------------------------------------------------
--  CIL
-------------------------------------------------------------------------------
            WHEN "000001000000" =>
              temp := ac(15);
              FOR i IN 14 DOWNTO 0 LOOP
                ac(i+1) <= ac(i);
              END LOOP;                  --  i
              ac(0) <= e;
              e <= ac(15);
              
-------------------------------------------------------------------------------
--  INC
-------------------------------------------------------------------------------
            WHEN "000000100000" =>
              temp_ac := bvtoi(ac);
              temp_add := temp_ac + 1;
              ac <= itobv(temp_add, 15);
              
-------------------------------------------------------------------------------
--  SPA
-------------------------------------------------------------------------------
            WHEN "000000010000" =>
              IF (ac(15) = '0') THEN
                temp_pc := bvtoi(pc);
                temp_add := temp_pc + 1;
                pc <= itobv(temp_add, 11);
              END IF;
              
-------------------------------------------------------------------------------
--  SNA
-------------------------------------------------------------------------------
            WHEN "000000001000" =>
              IF (ac(15) = '1') THEN
                temp_pc := bvtoi(pc);
                temp_add := temp_pc + 1;
                pc <= itobv(temp_add, 11);
              END IF;
              
-------------------------------------------------------------------------------
--  SZA
-------------------------------------------------------------------------------
            WHEN "000000000100" =>
              IF (ac = "0000000000000000") THEN
                temp_pc := bvtoi(pc);
                temp_add := temp_pc + 1;
                pc <= itobv(temp_add, 11);                
              END IF;
              
-------------------------------------------------------------------------------
--  SZE
-------------------------------------------------------------------------------
            WHEN "000000000010" =>
              IF (e = '0') THEN
                --temp_pc := bvtoi(pc);
                --temp_add := temp_pc + 1;
                --pc <= itobv(temp_add, 11);
                pc <= pc + "000000000001";
              END IF;
              
-------------------------------------------------------------------------------
--  HLT
-------------------------------------------------------------------------------
            WHEN "000000000001" =>
              halt <= '1';
            WHEN others  => 
          END CASE;                      --  ir(11 DOWNTO 0)
          cycle := 0;
 
-------------------------------------------------------------------------------
--  Input-Output Functions
-------------------------------------------------------------------------------
        WHEN 12 =>
          CASE ir(11 DOWNTO 0) IS
            
-------------------------------------------------------------------------------
--  INP
-------------------------------------------------------------------------------
            WHEN "100000000000" =>
              ac(7 DOWNTO 0) <= inpr;
              fgi_int <= '0';
              
-------------------------------------------------------------------------------
--  OUT
-------------------------------------------------------------------------------
            WHEN "010000000000" =>
              outr <= ac(7 DOWNTO 0);
              fgo <= '0';
              
-------------------------------------------------------------------------------
--  SKI
-------------------------------------------------------------------------------
            WHEN "001000000000" =>
              IF (fgi_int = '1') THEN
                temp_pc := bvtoi(pc);
                temp_add := temp_pc + 1;
                pc <= itobv(temp_add, 11);                                
              END IF;
              
-------------------------------------------------------------------------------
--  SKO
-------------------------------------------------------------------------------
            WHEN "000100000000" =>
              IF (fgo = '0') THEN
                temp_pc := bvtoi(pc);
                temp_add := temp_pc + 1;
                pc <= itobv(temp_add, 11);                                
              END IF;
              
-------------------------------------------------------------------------------
--  ION
-------------------------------------------------------------------------------
            WHEN "000010000000" =>
              ien <= '1';
              
-------------------------------------------------------------------------------
--  IOF
-------------------------------------------------------------------------------
            WHEN "000001000000" =>
              ien <= '0';

            WHEN others =>
              
          END CASE;                      --  ir(11 DOWNTO 0)
          cycle := 0;
         
-------------------------------------------------------------------------------
--  Interrupt
-------------------------------------------------------------------------------
        WHEN 13 =>
          mem_load <= '1';
          mem_out(11 downto 0) <= pc;
          pc <= (others  => '0');
          cycle := 14;

        WHEN 14 =>
          mem_load <= '0';
          temp_pc := bvtoi(pc);
          temp_add := temp_pc + 1;
          pc <= itobv(temp_add, 11);
          ien <= '0';
          cycle := 0;
          
        WHEN others =>
          
      END CASE;                          --  cycle
    ELSE
      cycle := 0;
    END IF;
  END PROCESS;
END behave_basic;

CONFIGURATION basic_config OF basic_comp IS
  FOR behave_basic
    FOR u1: basic_mem
      USE ENTITY work.basic_mem;
    END FOR;
  END FOR;
END basic_config;

<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>