-- © IBM Corp. 2020
-- Licensed under the Apache License, Version 2.0 (the "License"), as modified by
-- the terms below; you may not use the files in this repository except in
-- compliance with the License as modified.
-- You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
--
-- Modified Terms:
--
--    1) For the purpose of the patent license granted to you in Section 3 of the
--    License, the "Work" hereby includes implementations of the work of authorship
--    in physical form.
--
--    2) Notwithstanding any terms to the contrary in the License, any licenses
--    necessary for implementation of the Work that are available from OpenPOWER
--    via the Power ISA End User License Agreement (EULA) are explicitly excluded
--    hereunder, and may be obtained from OpenPOWER under the terms and conditions
--    of the EULA.  
--
-- Unless required by applicable law or agreed to in writing, the reference design
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
-- for the specific language governing permissions and limitations under the License.
-- 
-- Additional rights, including the ability to physically implement a softcore that
-- is compliant with the required sections of the Power ISA Specification, are
-- available at no cost under the terms of the OpenPOWER Power ISA EULA, which can be
-- obtained (along with the Power ISA) here: https://openpowerfoundation.org. 

library ieee;  use ieee.std_logic_1164.all;
library support; 
                 use support.power_logic_pkg.all;
library ibm; 
             use ibm.std_ulogic_support.all ;
             use ibm.std_ulogic_function_support.all;
library tri; use tri.tri_latches_pkg.all;

entity tri_128x16_1r1w_1 is
  generic (addressable_ports : positive := 128; 
           addressbus_width : positive := 7;    
           port_bitwidth : positive := 16;      
           ways : positive := 1;                
           expand_type : integer := 1);         
port (
    vdd                          : INOUT power_logic; 
    vcs                          : INOUT power_logic; 
    gnd                          : INOUT power_logic; 
  
    nclk                         : IN clk_logic;

    rd_act                             : IN std_ulogic;
    wr_act            		       : IN std_ulogic;

    lcb_d_mode_dc                : IN std_ulogic;
    lcb_clkoff_dc_b              : IN std_ulogic;
    lcb_mpw1_dc_b                : IN std_ulogic_vector(0 TO 4);
    lcb_mpw2_dc_b                : IN std_ulogic;		
    lcb_delay_lclkr_dc           : IN std_ulogic_vector(0 TO 4);		

    ccflush_dc                   : IN  std_ulogic;
    scan_dis_dc_b                : IN  std_ulogic;		
    scan_diag_dc                 : IN  std_ulogic;
    func_scan_in         : IN std_ulogic;
    func_scan_out        : OUT std_ulogic;

    lcb_sg_0              : IN std_ulogic;
    lcb_sl_thold_0_b      : IN std_ulogic;
    lcb_time_sl_thold_0        : IN std_ulogic;
    lcb_abst_sl_thold_0        : IN std_ulogic;
    lcb_ary_nsl_thold_0        : IN std_ulogic;
    lcb_repr_sl_thold_0        : IN std_ulogic;
    time_scan_in         : IN std_ulogic;
    time_scan_out        : OUT std_ulogic;
    abst_scan_in         : IN std_ulogic;
    abst_scan_out        : OUT std_ulogic;
    repr_scan_in         : IN std_ulogic;
    repr_scan_out        : OUT std_ulogic;

    abist_di                     : IN std_ulogic_vector(0 TO 3);
    abist_bw_odd                 : IN std_ulogic;
    abist_bw_even                : IN std_ulogic;
    abist_wr_adr                 : IN std_ulogic_vector(0 TO 6);
    wr_abst_act                  : IN std_ulogic;
    abist_rd0_adr                : IN std_ulogic_vector(0 TO 6);
    rd0_abst_act                 : IN std_ulogic;
    tc_lbist_ary_wrt_thru_dc     : IN std_ulogic;
    abist_ena_1                  : IN std_ulogic;
    abist_g8t_rd0_comp_ena       : IN std_ulogic;
    abist_raw_dc_b               : IN std_ulogic;
    obs0_abist_cmp               : IN std_ulogic_vector(0 TO 3);

    lcb_bolt_sl_thold_0         : in    std_ulogic;
    pc_bo_enable_2              : in    std_ulogic; 
    pc_bo_reset                 : in    std_ulogic; 
    pc_bo_unload                : in    std_ulogic; 
    pc_bo_repair                : in    std_ulogic; 
    pc_bo_shdata                : in    std_ulogic; 
    pc_bo_select                : in    std_ulogic; 
    bo_pc_failout               : out   std_ulogic; 
    bo_pc_diagloop              : out   std_ulogic;
    tri_lcb_mpw1_dc_b           : in    std_ulogic;
    tri_lcb_mpw2_dc_b           : in    std_ulogic;
    tri_lcb_delay_lclkr_dc      : in    std_ulogic;
    tri_lcb_clkoff_dc_b         : in    std_ulogic;
    tri_lcb_act_dis_dc          : in    std_ulogic;

    bw                           : IN std_ulogic_vector( 0 TO 15 );  
    wr_adr                       : IN std_ulogic_vector( 0 TO 6 );
    rd_adr                       : IN std_ulogic_vector( 0 TO 6 );  
    di                		 : IN std_ulogic_vector( 0 TO 15 );
    do                        : OUT std_ulogic_vector( 0 TO 15 )
		
   );

  -- synopsys translate_off
  -- synopsys translate_on

end entity tri_128x16_1r1w_1;

architecture tri_128x16_1r1w_1 of tri_128x16_1r1w_1 is

begin

  -- synopsys translate_off
  um: if expand_type = 0 generate

     constant rd_addr_offset       :  natural := 0;
     constant wr_addr_offset       :  natural := rd_addr_offset + addressbus_width;
     constant write_enable_offset  :  natural := wr_addr_offset + addressbus_width;
     constant data_in_offset       :  natural := write_enable_offset + port_bitwidth;
     constant data_out_offset      :  natural := data_in_offset + port_bitwidth;
     constant array_offset         :  natural := data_out_offset + port_bitwidth;
     constant scan_right           :  natural := array_offset + addressable_ports*port_bitwidth*ways - 1;

      signal tiup               : std_ulogic;
      signal tidn               : std_ulogic;

      signal rd_addr_l2            : std_ulogic_vector (0 TO addressbus_width-1);
      signal wr_addr_l2            : std_ulogic_vector (0 TO addressbus_width-1);
      signal write_enable_d     : std_ulogic_vector(0 to port_bitwidth-1);
      signal write_enable_l2    : std_ulogic_vector(0 to port_bitwidth-1);
      signal data_in_l2         : std_ulogic_vector(0 to port_bitwidth-1);
      signal data_out_d          : std_ulogic_vector(0 to port_bitwidth-1);
      signal data_out_l2         : std_ulogic_vector(0 to port_bitwidth-1);
      signal array_d            : std_ulogic_vector(0 to addressable_ports*port_bitwidth*ways-1);
      signal array_l2           : std_ulogic_vector(0 to addressable_ports*port_bitwidth*ways-1);
      signal siv                      : std_ulogic_vector(0 to scan_right);
      signal sov                      : std_ulogic_vector(0 to scan_right);
  begin
      tiup <= '1';
      tidn <= '0';

      rd_addr_latch: tri_rlmreg_p
        generic map (width => rd_adr'length, init => 0, expand_type => expand_type)
        port map (vd          => vdd,
                  gd          => gnd,
                  nclk        => nclk,
                  act         => rd_act,
                  scin        => siv(rd_addr_offset to rd_addr_offset+rd_addr_l2'length-1),
                  scout       => sov(rd_addr_offset to rd_addr_offset+rd_addr_l2'length-1),
                  din         => rd_adr,
                  dout        => rd_addr_l2 );

      wr_addr_latch: tri_rlmreg_p
        generic map (width => wr_adr'length, init => 0, expand_type => expand_type)
        port map (vd          => vdd,
                  gd          => gnd,
                  nclk        => nclk,
                  act         => wr_act,
                  scin        => siv(wr_addr_offset to wr_addr_offset+wr_addr_l2'length-1),
                  scout       => sov(wr_addr_offset to wr_addr_offset+wr_addr_l2'length-1),
                  din         => wr_adr,
                  dout        => wr_addr_l2 );



      write_enable_latch: tri_rlmreg_p
        generic map (width => port_bitwidth, init => 0, expand_type => expand_type)
        port map (vd          => vdd,
                  gd          => gnd,
                  nclk        => nclk,
                  act         => wr_act,
                  scin        => siv(write_enable_offset to write_enable_offset+write_enable_l2'length-1),
                  scout       => sov(write_enable_offset to write_enable_offset+write_enable_l2'length-1),
                  din         => write_enable_d,
                  dout        => write_enable_l2 );

      data_in_latch: tri_rlmreg_p
        generic map (width => port_bitwidth, init => 0, expand_type => expand_type)
        port map (vd          => vdd,
                  gd          => gnd,
                  nclk        => nclk,
                  act         => wr_act,
                  scin        => siv(data_in_offset to data_in_offset+data_in_l2'length-1),
                  scout       => sov(data_in_offset to data_in_offset+data_in_l2'length-1),
                  din         => di,
                  dout        => data_in_l2 );

      data_out_latch: tri_rlmreg_p
        generic map (width => port_bitwidth, init => 0, expand_type => expand_type)
        port map (vd          => vdd,
                  gd          => gnd,
                  nclk        => nclk,
                  act         => wr_act,
                  scin        => siv(data_out_offset to data_out_offset+data_out_l2'length-1),
                  scout       => sov(data_out_offset to data_out_offset+data_out_l2'length-1),
                  din         => data_out_d,
                  dout        => data_out_l2 );

      array_latch: tri_rlmreg_p
        generic map (width => addressable_ports*port_bitwidth*ways, init => 0, expand_type => expand_type)
        port map (vd          => vdd,
                  gd          => gnd,
                  nclk        => nclk,
                  act         => tiup,
                  scin        => siv(array_offset to array_offset+array_l2'length-1),
                  scout       => sov(array_offset to array_offset+array_l2'length-1),
                  din         => array_d,
                  dout        => array_l2 );

      write_enable_d <= bw when wr_act='1' else (others => '0');

      ww: for w in 0 to ways-1 generate
      begin
        wy: for y in 0 to addressable_ports-1 generate
        begin
          wx: for x in 0 to port_bitwidth-1 generate
          begin
            array_d(y*port_bitwidth*ways+w*port_bitwidth+x) <=
                   data_in_l2(x)  when ( write_enable_l2(x)='1' and wr_addr_l2 = tconv(y, addressbus_width)) 
              else array_l2(y*port_bitwidth*ways+w*port_bitwidth+x);

          end generate wx;
        end generate wy;
      end generate ww;

      data_out_d(0) <= array_l2( tconv(rd_addr_l2)*port_bitwidth);
      data_out_d(1) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+1);
      data_out_d(2) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+2);
      data_out_d(3) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+3);
      data_out_d(4) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+4);
      data_out_d(5) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+5);
      data_out_d(6) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+6);
      data_out_d(7) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+7);
      data_out_d(8) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+8);
      data_out_d(9) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+9);
      data_out_d(10) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+10);
      data_out_d(11) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+11);
      data_out_d(12) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+12);
      data_out_d(13) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+13);
      data_out_d(14) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+14);
      data_out_d(15) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+15);

      do(0) <= array_l2( tconv(rd_addr_l2)*port_bitwidth);
      do(1) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+1);
      do(2) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+2);
      do(3) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+3);
      do(4) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+4);
      do(5) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+5);
      do(6) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+6);
      do(7) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+7);
      do(8) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+8);
      do(9) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+9);
      do(10) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+10);
      do(11) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+11);
      do(12) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+12);
      do(13) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+13);
      do(14) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+14);
      do(15) <= array_l2( tconv(rd_addr_l2)*port_bitwidth+15);

  siv(0 to scan_right) <= sov(1 to scan_right) & func_scan_in;
  func_scan_out <= sov(0);
  
  time_scan_out <= time_scan_in;
  abst_scan_out <= abst_scan_in;
  repr_scan_out <= repr_scan_in;

  bo_pc_failout  <= '0';
  bo_pc_diagloop <= '0';

  end generate um;
  -- synopsys translate_on


a : if expand_type = 1 generate

component RAMB16_S36_S36
-- pragma translate_off
	generic(
		SIM_COLLISION_CHECK : string := "none"); 
-- pragma translate_on
	port(
		DOA : out std_logic_vector(31 downto 0);
		DOB : out std_logic_vector(31 downto 0);
		DOPA : out std_logic_vector(3 downto 0);
		DOPB : out std_logic_vector(3 downto 0);
		ADDRA : in std_logic_vector(8 downto 0);
		ADDRB : in std_logic_vector(8 downto 0);
		CLKA : in std_ulogic;
		CLKB : in std_ulogic;
		DIA : in std_logic_vector(31 downto 0);
		DIB : in std_logic_vector(31 downto 0);
		DIPA : in std_logic_vector(3 downto 0);
		DIPB : in std_logic_vector(3 downto 0);
		ENA : in std_ulogic;
		ENB : in std_ulogic;
		SSRA : in std_ulogic;
		SSRB : in std_ulogic;
		WEA : in std_ulogic;
		WEB : in std_ulogic);
end component;



-- pragma translate_off
-- pragma translate_on



signal clk,clk2x                          : std_ulogic;
signal b0addra,         b0addrb           : std_ulogic_vector(0 to 8);
signal wea,             web               : std_ulogic;
signal wren_a              : std_ulogic;
signal reset_q                            : std_ulogic;
signal gate_fq,         gate_d            : std_ulogic;
signal r_data_out_1_d,  r_data_out_1_fq   : std_ulogic_vector(0 to 35);
signal w_data_in_0                        : std_ulogic_vector(0 to 35);

signal r_data_out_0_bram                  : std_logic_vector(0 to 35);
signal r_data_out_1_bram                  : std_logic_vector(0 to 35);

signal toggle_d     : std_ulogic;
signal toggle_q     : std_ulogic;
signal toggle2x_d   : std_ulogic;
signal toggle2x_q   : std_ulogic;

signal unused             : std_ulogic;
-- synopsys translate_off
-- synopsys translate_on

begin

clk   <= nclk.clk;
clk2x <= nclk.clk2x;

rlatch: process (clk) begin
    if(rising_edge(clk)) then
      reset_q              <= nclk.sreset;
    end if;
end process;


tlatch: process (nclk.clk,reset_q)
begin
   if(rising_edge(nclk.clk)) then
      if (reset_q = '1') then
         toggle_q  <= '1';
      else
         toggle_q  <= toggle_d;
      end if;
    end if;
end process;

flatch: process (nclk.clk2x)
begin
   if(rising_edge(nclk.clk2x)) then
      toggle2x_q <= toggle2x_d;
      gate_fq  <= gate_d;
      r_data_out_1_fq   <= r_data_out_1_d;
   end if;
end process;

toggle_d   <= not toggle_q;
toggle2x_d <= toggle_q;

gate_d <= not(toggle_q xor toggle2x_q);





b0addra(2 to 8)   <= wr_adr;
b0addrb(2 to 8)   <= rd_adr;

b0addra(0 to 1) <= "00";
b0addrb(0 to 1) <= "00";



wren_a <= '1' when bw /= "0000000000000000" else '0';
wea         <= wren_a and not(gate_fq); 
web         <= '0';
w_data_in_0(0) <= di(0) when bw(0)='1' else r_data_out_0_bram(0);
w_data_in_0(1) <= di(1) when bw(1)='1' else r_data_out_0_bram(1);
w_data_in_0(2) <= di(2) when bw(2)='1' else r_data_out_0_bram(2);
w_data_in_0(3) <= di(3) when bw(3)='1' else r_data_out_0_bram(3);
w_data_in_0(4) <= di(4) when bw(4)='1' else r_data_out_0_bram(4);
w_data_in_0(5) <= di(5) when bw(5)='1' else r_data_out_0_bram(5);
w_data_in_0(6) <= di(6) when bw(6)='1' else r_data_out_0_bram(6);
w_data_in_0(7) <= di(7) when bw(7)='1' else r_data_out_0_bram(7);
w_data_in_0(8) <= di(8) when bw(8)='1' else r_data_out_0_bram(8);
w_data_in_0(9) <= di(9) when bw(9)='1' else r_data_out_0_bram(9);
w_data_in_0(10) <= di(10) when bw(10)='1' else r_data_out_0_bram(10);
w_data_in_0(11) <= di(11) when bw(11)='1' else r_data_out_0_bram(11);
w_data_in_0(12) <= di(12) when bw(12)='1' else r_data_out_0_bram(12);
w_data_in_0(13) <= di(13) when bw(13)='1' else r_data_out_0_bram(13);
w_data_in_0(14) <= di(14) when bw(14)='1' else r_data_out_0_bram(14);
w_data_in_0(15) <= di(15) when bw(15)='1' else r_data_out_0_bram(15);
w_data_in_0(16 to 35) <= (others => '0');

r_data_out_1_d <= std_ulogic_vector(r_data_out_1_bram);

bram0a : ramb16_s36_s36
-- pragma translate_off
generic map(
   sim_collision_check => "none")
-- pragma translate_on
port map(
                       clka  => clk2x,
	               clkb  => clk2x,
	               ssra  => reset_q,
	               ssrb  => reset_q,
	               addra => std_logic_vector(b0addra),
	               addrb => std_logic_vector(b0addrb),
	               dia   => std_logic_vector(w_data_in_0(0 to 31)),
	               dib   => (others => '0'),
                       doa   => r_data_out_0_bram(0 to 31),
                       dob   => r_data_out_1_bram(0 to 31),
                       dopa  => r_data_out_0_bram(32 to 35),
                       dopb  => r_data_out_1_bram(32 to 35),
	               dipa  => std_logic_vector(w_data_in_0(32 to 35)),
	               dipb  => (others => '0'),
	               ena   => '1',
	               enb   => '1',
	               wea   => wea,
	               web   => web
	               );


do   <= r_data_out_1_fq(0 to 15);

func_scan_out <= func_scan_in;
time_scan_out <= time_scan_in;
abst_scan_out <= abst_scan_in;
repr_scan_out <= repr_scan_in;

bo_pc_failout  <= '0';
bo_pc_diagloop <= '0';

unused <= or_reduce( std_ulogic_vector(r_data_out_0_bram(16 to 35)) & rd_act & wr_act
                       & lcb_d_mode_dc & lcb_clkoff_dc_b & lcb_mpw1_dc_b & lcb_mpw2_dc_b
                       & lcb_delay_lclkr_dc & ccflush_dc & scan_dis_dc_b & scan_diag_dc
                       & lcb_sg_0 & lcb_sl_thold_0_b & lcb_time_sl_thold_0 & lcb_abst_sl_thold_0
                       & lcb_ary_nsl_thold_0 & lcb_repr_sl_thold_0 & abist_di & abist_bw_odd
                       & abist_bw_even & abist_wr_adr & wr_abst_act & abist_rd0_adr & rd0_abst_act
                       & tc_lbist_ary_wrt_thru_dc & abist_ena_1 & abist_g8t_rd0_comp_ena
                       & abist_raw_dc_b & obs0_abist_cmp & lcb_bolt_sl_thold_0 & pc_bo_enable_2
                       & pc_bo_reset & pc_bo_unload & pc_bo_repair & pc_bo_shdata & pc_bo_select
                       & tri_lcb_mpw1_dc_b & tri_lcb_mpw2_dc_b & tri_lcb_delay_lclkr_dc
                       & tri_lcb_clkoff_dc_b & tri_lcb_act_dis_dc );

end generate a;


end architecture tri_128x16_1r1w_1;


