-- Model Name : Synthesizable Behevioral - Parwan CPU -- Author : Zainalabedin Navabi -- Last Updated : 09 / 15 / 1996 -- This document is © copyrighted by the Author.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
--
LIBRARY EXEMPLAR;
USE EXEMPLAR.exemplar_1164.ALL;
--
LIBRARY parwan_s;
USE parwan_s.synthesis_parameters.ALL;
USE parwan_s.synthesis_utilities.ALL;
--
ENTITY par_central_processing_unit IS
    PORT (clk : IN std_logic;
      interrupt : IN std_logic;
      read_mem, write_mem : OUT std_logic;
      databus : INOUT byte; adbus : OUT twelve;
      halted : OUT std_logic := '0'; ready : IN std_logic
      );
END par_central_processing_unit;
--
ARCHITECTURE behavioral_synthesizable OF par_central_processing_unit IS
    SIGNAL ac, next_ac, ir, next_ir : byte;
    SIGNAL sr, next_sr : nibble;
    SIGNAL pc, next_pc, mar, next_mar : twelve;
    TYPE cpu_states IS (initial, instr_fetch, do_one_bytes, opnd_fetch,
          do_indirect, do_two_bytes, do_jsr, continue_jsr,
          do_branch);
    SIGNAL present_state, next_state : cpu_states;
BEGIN
    clocking : PROCESS (clk, interrupt)
    BEGIN
      IF (interrupt = '1') THEN
        present_state <= initial;
        ac <= zero_8;
        ir <= zero_8;
        sr <= "0000";
        pc <= zero_12;
        mar <= zero_12;
      ELSIF clk'EVENT AND clk = '0' THEN
        ac <= next_ac;
        ir <= next_ir;
        sr <= next_sr;
        pc <= next_pc;
        mar <= next_mar;
        present_state <= next_state;
      END IF;
    END PROCESS clocking;
    --
    sequencing : PROCESS ( present_state, interrupt, ready, databus, ac, ir, sr, pc, mar )
      VARIABLE ten_bit : std_logic_vector (9 DOWNTO 0);
    BEGIN
      next_pc <= pc;
      databus <= "ZZZZZZZZ";
      adbus <= "ZZZZZZZZZZZZ";
      read_mem <= '0';
      write_mem <= '0';
      halted <= '0';
      next_ir <= ir;
      next_ac <= ac;
      next_mar <= mar;
      next_sr <= sr;
      ten_bit := "0000000000";
      CASE present_state IS
        WHEN initial => -------------------------------------------1
          IF (interrupt = '1') THEN
            next_pc <= zero_12;
            next_state <= initial;
          ELSE
            next_mar <= pc;
            next_state <= instr_fetch;
          END IF;
        WHEN instr_fetch => ---------------------------------------2
          adbus <= mar;
          read_mem <= '1';
          IF ready = '1' THEN
            next_ir <= databus;
            next_pc <= pc + "01";
            next_state <= do_one_bytes;
          ELSE
            next_state <= instr_fetch;
          END IF;
        WHEN do_one_bytes => --------------------------------------3
          next_mar <= pc; -- prepare for next memory read
          IF (ir(7 DOWNTO 4) /= single_byte_instructions) THEN
            next_state <= opnd_fetch;
          ELSE
            CASE ir(3 DOWNTO 0) IS
              WHEN cla =>
                next_ac <= zero_8;
              WHEN cma =>
                next_sr(0) <= ac(7); --n flag
                next_sr(1) <= NOT all_or (NOT ac); --z
                next_ac <= NOT ac;
              WHEN cmc =>
                next_sr(2) <= NOT sr(2); --c flag
              WHEN asl =>
                next_sr(0) <= ac(6); --n
                next_sr(1) <= NOT all_or (ac(6 DOWNTO 0)); --z
                next_sr(2) <= ac(7); --c
                next_sr(3) <= ac(6) XOR ac(7); --v
                next_ac <= ac (6 DOWNTO 0) & '0';
              WHEN asr =>
                next_sr(0) <= ac(6); --n
                next_sr(1) <= NOT all_or (ac(7 DOWNTO 1)); --z
                next_sr(2) <= ac(7); --c
                next_sr(3) <= ac(6) XOR ac(7); --v
                next_ac <= ac (7) & ac (7 DOWNTO 1);
              WHEN hlt =>
                halted <= '1';
              WHEN OTHERS => NULL;
            END CASE;
            next_state <= instr_fetch;
          END IF;
        WHEN opnd_fetch => ----------------------------------------4
          adbus <= mar;
          read_mem <= '1';
          IF ready = '1' THEN
            next_mar(7 DOWNTO 0) <= databus;
            IF ( ir(7 DOWNTO 6) /= jsr_or_bra ) THEN
              next_mar(11 DOWNTO 8) <= ir(3 DOWNTO 0);
              IF ( ir(4) = indirect ) THEN
                next_state <= do_indirect;
              ELSE
                next_state <= do_two_bytes;
              END IF;
            ELSE --jsr or bra, do not alter mar page
              IF ( ir(5) = '0' ) THEN -- jsr
                next_state <= do_jsr;
              ELSE
                next_state <= do_branch;
              END IF;
            END IF;
            next_pc <= pc + "01";
          ELSE
            next_state <= opnd_fetch;
          END IF;
        WHEN do_indirect => ---------------------------------------5
          adbus <= mar;
          read_mem <= '1';
          IF ready = '1' THEN
            next_mar(7 DOWNTO 0) <= databus;
            next_state <= do_two_bytes;
          ELSE
            next_state <= do_indirect;
          END IF;
        WHEN do_two_bytes => --------------------------------------6
          IF ( ir(7 DOWNTO 5) = jmp ) THEN
            next_pc <= mar;
            next_state <= instr_fetch;
          ELSIF ( ir(7 DOWNTO 5) = sta ) THEN
            adbus <= mar;
            databus <= ac;
            write_mem <= '1';
            IF ready = '1' THEN
              next_state <= initial;
            ELSE
              next_state <= do_two_bytes;
            END IF;
          ELSIF ( ir(7) = '0' ) THEN ------ lda, and, add, sub
            adbus <= mar;
            read_mem <= '1';
            IF ready = '1' THEN
              IF ( ir(6) = '0' ) THEN ---- lda, and
                IF ( ir(5) = '0' ) THEN -- lda
                  ten_bit := sr (3 DOWNTO 2) & databus; --
                ELSE -- and
                  ten_bit := sr (3 DOWNTO 2) & ( ac AND databus ); --
                END IF;
              ELSE ---- add, sub
                ten_bit := addsub_cv (ac, databus, sr(2), ir(5));
              END IF;
              next_sr(0) <= ten_bit (7); --n
              next_sr(1) <= NOT all_or ( ten_bit(7 DOWNTO 0) ); --z
              next_sr(2) <= ten_bit (8); --c
              next_sr(3) <= ten_bit (9); --v
              next_ac <= ten_bit (7 DOWNTO 0);
              next_state <= initial;
            ELSE
              next_state <= do_two_bytes;
            END IF;
          ELSE
            next_state <= initial; --never happens
          END IF;
        WHEN do_jsr => --------------------------------------------7
          adbus <= mar;
          databus <= pc (7 DOWNTO 0);
          write_mem <= '1';
          IF ready = '1' THEN
            next_pc <= mar;
            next_state <= continue_jsr;
          ELSE
            next_state <= do_jsr;
          END IF;
        WHEN continue_jsr => --------------------------------------8
          next_pc <= pc + "01";
          next_state <= initial;
        WHEN do_branch => -----------------------------------------9
          IF ( all_or (sr AND ir(3 DOWNTO 0)) = '1') THEN
            next_pc <= mar;
          END IF;
          next_state <= initial;
      END CASE;
    END PROCESS;
END behavioral_synthesizable;