-- CPU module -- -- Repeatedly fetches and executes instructions from memory. -- -- The snoop port allows an external module to observe the value of the -- internal registers. -- -- The proceed signal is used to pause the processor for single step -- operation. If proceed is low at the end of an instruction fetch, -- the processor waits for it to go high before proceeding to the -- instruction execution phase. library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.numeric_std.all; use IEEE.std_logic_unsigned.all; use work.commonDefs.all; entity cpu is port ( clk, reset: in std_logic; en, rw: out std_logic; aBus: out address; dBus: inout word; snoopPort: out regSet; pause: in std_logic ); end cpu; architecture cpuArch of cpu is type state_type is ( reset_state, fetch, halt, negate, mload, dload, iload, dstore, istore, branch, brZero, brPos, brNeg, add, andd ); signal state: state_type; signal tick: std_logic_vector(3 downto 0); signal pc: address; -- program counter signal iReg: word; -- instruction register signal iar: address; -- indirect address register signal acc: word; -- accumulator signal alu: word; -- alu output begin snoopPort.pc <= pc; snoopPort.iReg <= iReg; snoopPort.acc <= acc; snoopPort.iar <= iar; alu <= (not acc) + x"0001" when state = negate else acc + dbus when state = add else acc and dbus when state = andd else (alu'range => '0'); -- Controller process for events that happen on rising clock edges. controllerProccessUp: process (clk) procedure decode is begin -- Instruction decoding. case iReg(15 downto 12) is when x"0" => if iReg(11 downto 0) = x"000" then state <= halt; elsif iReg(11 downto 0) = x"001" then state <= negate; else state <= halt; end if; when x"1" => state <= mload; when x"2" => state <= dload; when x"3" => state <= iload; when x"4" => state <= dstore; when x"5" => state <= istore; when x"6" => state <= branch; when x"7" => state <= brZero; when x"8" => state <= brPos; when x"9" => state <= brNeg; when x"a" => state <= add; when x"d" => state <= andd; when others => state <= halt; end case; end procedure decode; procedure wrapup is begin -- Do this at end of every instruction state <= fetch; tick <= x"0"; end procedure wrapup; begin if rising_edge(clk) then if reset = '1' then state <= reset_state; tick <= x"0"; pc <= (others => '0'); iReg <= (others => '0'); acc <= (others => '0'); iar <= (others => '0'); en <= '0'; rw <= '1'; aBus <= (others => 'Z'); dBus <= (others => 'Z'); else tick <= tick + 1; -- advance time by default case state is when reset_state => wrapup; when fetch => case tick is when x"0" => en <= '1'; aBus <= pc; when x"1" => en <= '0'; aBus <= (others => 'Z'); when x"2" => iReg <= dBus; when x"3" => if pause = '0' then decode; pc <= pc + 1; tick <= x"0"; else tick <= x"3"; -- hold at end of fetch state end if; when others => end case; when halt => tick <= x"0"; -- do nothing when negate => acc <= alu; wrapup; -- load instructions when mload => if iReg(11) = '0' then -- sign extension acc <= x"0" & ireg(11 downto 0); else acc <= x"f" & ireg(11 downto 0); end if; wrapup; when dload => case tick is when x"0" => en <= '1'; aBus <= x"0" & iReg(11 downto 0); when x"1" => en <= '0'; aBus <= (others => 'Z'); when x"2" => acc <= dBus; wrapup; when others => end case; when iload => case tick is when x"0" => en <= '1'; aBus <= x"0" & iReg(11 downto 0); when x"1" => en <= '0'; aBus <= (others => 'Z'); when x"2" => iar <= dBus; when x"3" => en <= '1'; aBus <= iar; when x"4" => en <= '0'; aBus <= (others => 'Z'); when x"5" => acc <= dBus; wrapup; when others => end case; -- store instructions when dstore => case tick is when x"0" => en <= '1'; rw <= '0'; aBus <= x"0" & iReg(11 downto 0); dBus <= acc; when x"1" => en <= '0'; rw <= '1'; aBus <= (others => 'Z'); dBus <= (others => 'Z'); when x"2" => wrapup; when others => end case; when istore => case tick is when x"0" => en <= '1'; aBus <= x"0" & iReg(11 downto 0); when x"1" => en <= '0'; aBus <= (others => 'Z'); when x"2" => iar <= dBus; when x"3" => en <= '1'; rw <= '0'; aBus <= iar; dBus <= acc; when x"4" => en <= '0'; rw <= '1'; aBus <= (others => 'Z'); dBus <= (others => 'Z'); when x"5" => wrapup; when others => end case; -- branch instructions when branch => pc <= x"0" & iReg(11 downto 0); wrapup; when brZero => if acc = x"0000" then pc <= x"0" & iReg(11 downto 0); end if; wrapup; when brPos => if acc(15) = '0' and acc /= x"0000" then pc <= x"0" & iReg(11 downto 0); end if; wrapup; when brNeg => if acc(15) = '1' then pc <= x"0" & iReg(11 downto 0); end if; wrapup; -- arithmetic and logic instructions when add | andd => case tick is when x"0" => en <= '1'; aBus <= x"0" & iReg(11 downto 0); when x"1" => en <= '0'; aBus <= (others => 'Z'); when x"2" => acc <= alu; wrapup; when others => end case; when others => state <= halt; end case; end if; end if; end process; end cpuArch;