----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Jim Plusquellic
-- 
-- Create Date:    16:04:58 09/23/2009 
-- Design Name: 
-- Module Name:    Instruction Memory (uses BRAM from Core Generator)
-- 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;

-- PC is the program counter register. scan_in is the serial input 
-- to the scan register. scan_en is used to switch from normal mode to scan mode of operation. 
-- load_sig is used to enable the BRAM write operation. IR_reg is the instruction register and 
-- scan_out is the serial output path from the scan register.
entity InstrMemory is
   Port ( 
      clk : in std_logic;
      reset : in std_logic;
      PC : in std_logic_vector(7 downto 0);
      scan_in, scan_en, load_sig : in std_logic;
      IR_reg : out std_logic_vector(11 downto 0);
      scan_out : out std_logic;

-- DEBUG
      scan_reg_out : out std_logic_vector(11 downto 0)
   );
end InstrMemory;

architecture beh of InstrMemory is
   signal scan_reg, scan_next : std_logic_vector(11 downto 0); 
   signal IR_bus : std_logic_vector(11 downto 0); 
   signal tmp : std_logic_vector(0 downto 0);

   component InstrMem
      port (
        clka: IN std_logic;
        dina: IN std_logic_VECTOR(11 downto 0);
        addra: IN std_logic_VECTOR(7 downto 0);
        wea: IN std_logic_VECTOR(0 downto 0);
        douta: OUT std_logic_VECTOR(11 downto 0));
   end component;

   begin

-- register logic
   process(clk, reset)
      begin
      if (reset = '1') then
         scan_reg <= (others => '0');
      elsif (clk'event and clk = '1') then
         scan_reg <= scan_next;
      end if; 
   end process;

-- Create the scan register -- when scan_en is '1', use serial path, otherwise keep
-- loading the instruction output from the BRAM.
   with scan_en select
      scan_next <= scan_in & scan_reg(11 downto 1) when '1',
                   IR_bus when others;

   scan_out <= scan_reg(0);

-- Instantiate the BRAM memory -- NOTE: BRAM takes TWO cycles to complete the read
-- for a new PC address
   tmp(0) <= load_sig;
   InstrBRAMUnit : InstrMem
      port map (clka=>clk, dina=>scan_reg, addra=>PC, wea=>tmp, douta=>IR_bus);

   IR_reg <= IR_bus;
   scan_reg_out <= scan_reg;

end beh;
