------------------------------------------------------------------------------- -- 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;