----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Jim Plusquellic
-- 
-- Create Date:    16:04:58 09/23/2009 
-- Design Name: 
-- Module Name:    Scan Emulation
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;

-- Instr_In_Reg is the instruction to be processed. This routine is activated when go_scan_emulation
-- is pulsed. Once pulsed, scan_en is asserted and each bit of the Instr_In_Reg is placed on scan in 
-- (low order bits first). After all bits are scanned, the load_sig is pulse to save the 
-- instruction into the BRAM (in InstrMemUnit) and the PC is incremented. 
entity ScanEmulation is
   Port ( 
      clk : in std_logic;
      reset : in std_logic;
      Instr_In_Reg : in std_logic_vector(11 downto 0);
      go_scan_emulation : in std_logic;
      scan_in, scan_en, load_sig : out std_logic;
      PC : out std_logic_vector(7 downto 0)
   );
end ScanEmulation;

architecture beh of ScanEmulation is
   constant INSTR_WIDTH : natural := 12;
   type state_type is (idle, scan, pulse_se, load, inc_PC);
   signal state_reg, state_next: state_type;

   signal PC_reg, PC_next : unsigned(7 downto 0);

-- Instr_In_Reg is 12 bits -- need at least 4 bits to count to 12
   signal cnt_reg, cnt_next : integer range 0 to 15;

   begin

-- Registers
   process (clk, reset)
      begin
      if ( reset = '1' ) then
         state_reg <= idle;
         PC_reg <= (others => '0');
         cnt_reg <= 0;
      elsif (clk'event and clk = '1') then
         state_reg <= state_next;
         PC_reg <= PC_next;
         cnt_reg <= cnt_next;
      end if;
   end process;

-- next state logic
   process (state_reg, Instr_In_Reg, PC_reg, cnt_reg, go_scan_emulation)
      begin
      state_next <= state_reg;
      cnt_next <= cnt_reg;
      PC_next <= PC_reg;
      scan_en <= '0';
      scan_in <= '0';
      load_sig <= '0';

      case state_reg is

-- Waiting for go_scan_emulation to assert
         when idle =>
            if (go_scan_emulation = '1') then
               cnt_next <= 0;
               state_next <= scan;
            end if;

-- Scan each bit in 
         when scan =>
            scan_en <= '1';
            scan_in <= Instr_In_Reg(cnt_reg);
            cnt_next <= cnt_reg + 1;

-- If we are transferring the last bit, go to the load state
            if ( cnt_reg = INSTR_WIDTH - 1) then
               state_next <= load;
            end if;

-- Pulse the load_sig to allow the BRAM to save the instruction now in
-- the scan in register in InstrMemUnit to be saved at the current value
-- of PC
         when load =>
            load_sig <= '1';
            state_next <= inc_PC;

-- Finally, increment the PC by 1 and return to idle
         when inc_PC =>
            PC_next <= PC_reg + 1;
            state_next <= idle;

         when others =>
            state_next <= idle;
      end case;
   end process;

   PC <= std_logic_vector(PC_reg);
end beh;

