From: hadeshyp Date: Fri, 14 Sep 2007 11:40:06 +0000 (+0000) Subject: first version of 16Bit multiplexer, simulation ok, Jan X-Git-Tag: oldGBE~705 X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=e6b1ff2b6225d11ab6aad64f91ec9e606cf78f8f;p=trbnet.git first version of 16Bit multiplexer, simulation ok, Jan --- diff --git a/trb_net16_io_multiplexer.vhd b/trb_net16_io_multiplexer.vhd new file mode 100644 index 0000000..845a7a2 --- /dev/null +++ b/trb_net16_io_multiplexer.vhd @@ -0,0 +1,310 @@ +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.STD_LOGIC_ARITH.ALL; +USE IEEE.STD_LOGIC_UNSIGNED.ALL; + +use work.trb_net_std.all; + + +entity trb_net16_io_multiplexer is + + generic (BUS_WIDTH : integer := 16; + MULT_WIDTH : integer range 1 to 5 := 1); + + port( + -- Misc + CLK : in std_logic; + RESET : in std_logic; + CLK_EN : in std_logic; + + -- Media direction port + MED_DATAREADY_IN: in STD_LOGIC; + MED_DATA_IN: in STD_LOGIC_VECTOR (BUS_WIDTH-1 downto 0); + MED_PACKET_NUM_IN: in STD_LOGIC_VECTOR (1 downto 0); + MED_READ_OUT: out STD_LOGIC; + + MED_DATAREADY_OUT: out STD_LOGIC; + MED_DATA_OUT: out STD_LOGIC_VECTOR (BUS_WIDTH-1 downto 0); + MED_PACKET_NUM_OUT: out STD_LOGIC_VECTOR (1 downto 0); + MED_READ_IN: in STD_LOGIC; + + -- Internal direction port + INT_DATAREADY_OUT: out STD_LOGIC_VECTOR (2**MULT_WIDTH-1 downto 0); + INT_DATA_OUT: out STD_LOGIC_VECTOR ((BUS_WIDTH)*(2**MULT_WIDTH)-1 downto 0); + INT_PACKET_NUM_OUT: out STD_LOGIC_VECTOR (2*(2**MULT_WIDTH)-1 downto 0); + INT_READ_IN: in STD_LOGIC_VECTOR (2**MULT_WIDTH-1 downto 0); + + INT_DATAREADY_IN: in STD_LOGIC_VECTOR (2**MULT_WIDTH-1 downto 0); + INT_DATA_IN: in STD_LOGIC_VECTOR ((BUS_WIDTH)*(2**MULT_WIDTH)-1 downto 0); + INT_PACKET_NUM_IN: in STD_LOGIC_VECTOR (2*(2**MULT_WIDTH)-1 downto 0); + INT_READ_OUT: out STD_LOGIC_VECTOR (2**MULT_WIDTH-1 downto 0); + + -- Status and control port + CTRL: in STD_LOGIC_VECTOR (31 downto 0); + STAT: out STD_LOGIC_VECTOR (31 downto 0) + ); +end trb_net16_io_multiplexer; + + + +architecture trb_net16_io_multiplexer_arch of trb_net16_io_multiplexer is + + component trb_net_pattern_gen is + generic (MULT_WIDTH : integer := 1); + port( + INPUT_IN : in STD_LOGIC_VECTOR (MULT_WIDTH-1 downto 0); + RESULT_OUT: out STD_LOGIC_VECTOR (2**MULT_WIDTH-1 downto 0) + ); + end component; + + component trb_net_sbuf is + generic (DATA_WIDTH : integer := 18; + VERSION: integer := 0); + port( + -- Misc + CLK : in std_logic; + RESET : in std_logic; + CLK_EN : in std_logic; + -- port to combinatorial logic + COMB_DATAREADY_IN: in STD_LOGIC; --comb logic provides data word + COMB_next_READ_OUT: out STD_LOGIC; --sbuf can read in NEXT cycle + COMB_READ_IN: in STD_LOGIC; --comb logic IS reading + COMB_DATA_IN: in STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0); -- Data word + -- Port to synchronous output. + SYN_DATAREADY_OUT: out STD_LOGIC; + SYN_DATA_OUT: out STD_LOGIC_VECTOR (DATA_WIDTH-1 downto 0); -- Data word + SYN_READ_IN: in STD_LOGIC; + -- Status and control port + STAT_BUFFER: out STD_LOGIC + ); + end component; + + component trb_net_priority_arbiter is + generic (WIDTH : integer := 16); + port( + -- Misc + CLK : in std_logic; + RESET : in std_logic; + CLK_EN : in std_logic; + INPUT_IN : in STD_LOGIC_VECTOR (WIDTH-1 downto 0); + RESULT_OUT: out STD_LOGIC_VECTOR (WIDTH-1 downto 0); + ENABLE : in std_logic; + CTRL: in STD_LOGIC_VECTOR (31 downto 0) + ); + end component; + + signal MUX_SBUF_data_out : std_logic_vector(BUS_WIDTH+1 downto 0); + signal demux_next_READ, current_demux_READ : STD_LOGIC_VECTOR ((2**MULT_WIDTH)-1 downto 0); + signal next_demux_dr, next_demux_dr_tmp, demux_dr_tmp: STD_LOGIC_VECTOR ((2**MULT_WIDTH)-1 downto 0); + signal current_MED_READ_OUT, next_MED_READ_OUT: STD_LOGIC; + signal tmp_INT_READ_OUT, final_INT_READ_OUT: STD_LOGIC_VECTOR ((2**MULT_WIDTH)-1 downto 0); + --signal tmp_tmp_INT_READ_OUT: STD_LOGIC_VECTOR ((2**MULT_WIDTH)-1 downto 0); + signal mux_read, mux_enable, mux_next_READ: STD_LOGIC; + signal current_mux_buffer: STD_LOGIC_VECTOR (BUS_WIDTH+2-1 downto 0); + signal endpoint_locked, next_endpoint_locked: std_logic; + signal demux_sbuf_data_in : std_logic_vector((BUS_WIDTH+2)-1 downto 0); + signal demux_sbuf_data_out: std_logic_vector((BUS_WIDTH+2)*(2**MULT_WIDTH)-1 downto 0); +begin +------------------------------------------------------------------------------- +-- DEMUX +------------------------------------------------------------------------------ + + demux_sbuf_data_in(BUS_WIDTH-1 downto 0) <= MED_DATA_IN (BUS_WIDTH-1 downto 0); + demux_sbuf_data_in(BUS_WIDTH+1 downto BUS_WIDTH) <= MED_PACKET_NUM_IN; + + G1: for i in 0 to 2**MULT_WIDTH-1 generate + DEMUX_SBUF: trb_net_sbuf + generic map (DATA_WIDTH => BUS_WIDTH+2, VERSION => 0) + port map ( + CLK => CLK, + RESET => RESET, + CLK_EN => CLK_EN, + COMB_DATAREADY_IN => next_demux_dr(i), + COMB_next_READ_OUT => demux_next_READ(i), + COMB_READ_IN => current_demux_READ(i), + COMB_DATA_IN => demux_sbuf_data_in((BUS_WIDTH+2)-1 downto 0), + SYN_DATAREADY_OUT => INT_DATAREADY_OUT(i), + SYN_DATA_OUT => demux_sbuf_data_out((BUS_WIDTH+2)*(i+1)-1 downto (BUS_WIDTH+2)*(i)), + SYN_READ_IN => INT_READ_IN(i) + ); + INT_DATA_OUT ((BUS_WIDTH)*(i+1)-1 downto (BUS_WIDTH)*(i)) <= demux_sbuf_data_out((BUS_WIDTH+2)*(i+1)-3 downto (BUS_WIDTH+2)*i); + INT_PACKET_NUM_OUT(2*(i+1)-1 downto 2*i) <= demux_sbuf_data_out((BUS_WIDTH+2)*(i+1)-1 downto (BUS_WIDTH+2)*(i+1)-2); + end generate; + + MED_READ_OUT <= current_MED_READ_OUT; + + comb_demux : process (next_demux_dr_tmp, demux_next_READ, INT_READ_IN, + MED_DATAREADY_IN, current_MED_READ_OUT) + begin + next_demux_dr <= (others => '0'); + current_demux_READ <= (others => '0'); + -- generate the READ_OUT + next_MED_READ_OUT <= and_all(demux_next_READ or INT_READ_IN); + -- (follow instruction on sbuf) + + current_demux_READ <= (others => '0'); + if current_MED_READ_OUT = '1' then + current_demux_READ <= (others => '1'); + end if; + if current_MED_READ_OUT = '1' and MED_DATAREADY_IN = '1' then + if MED_PACKET_NUM_IN = "00" then --demux_dr_tmp only valid on packet 0, use saved demux_dr otherwise + next_demux_dr <= next_demux_dr_tmp; --enable DR on the sbufs + else + next_demux_dr <= demux_dr_tmp; + end if; + end if; + end process; + + +-- define next DRx +-- the output of the pattern generator is only valid for packet number 00! + + DEFDR: trb_net_pattern_gen + generic map (MULT_WIDTH => MULT_WIDTH) + port map ( + INPUT_IN => MED_DATA_IN(3+MULT_WIDTH-1 downto 3), + RESULT_OUT => next_demux_dr_tmp -- this will have a 1 in ANY case + ); + keep_valid_demux : process(CLK) + begin + if rising_edge(CLK) then + if RESET = '1' then + demux_dr_tmp <= (others => '0'); + elsif current_MED_READ_OUT = '1' and MED_DATAREADY_IN = '1' and MED_PACKET_NUM_IN = "00" then + demux_dr_tmp <= next_demux_dr_tmp; + else + demux_dr_tmp <= demux_dr_tmp; + end if; + end if; + end process; + + + sync_demux : process(CLK) + begin + if rising_edge(CLK) then + if RESET = '1' then + current_MED_READ_OUT <= '0'; + elsif CLK_EN = '1' then + current_MED_READ_OUT <= next_MED_READ_OUT; + else + current_MED_READ_OUT <= current_MED_READ_OUT; + end if; + end if; + end process; + + +------------------------------------------------------------------------------- +-- MUX part with arbitration scheme +------------------------------------------------------------------------------- +ARBITER: trb_net_priority_arbiter + generic map (WIDTH => 2**MULT_WIDTH) + port map ( + CLK => CLK, + RESET => RESET, + CLK_EN => CLK_EN, + INPUT_IN => INT_DATAREADY_IN, + RESULT_OUT => tmp_INT_READ_OUT, + ENABLE => mux_enable, + CTRL => CTRL + ); + + + +-- we have to care to read four packets from every endpoint + process(current_mux_buffer, mux_read, endpoint_locked) + begin + next_endpoint_locked <= endpoint_locked; + if current_mux_buffer(BUS_WIDTH+1 downto BUS_WIDTH) = "11" and mux_read = '1' then + next_endpoint_locked <= '0'; + elsif current_mux_buffer(BUS_WIDTH+1 downto BUS_WIDTH) = "00" and mux_read = '1' then + next_endpoint_locked <= '1'; + end if; + end process; + + process(CLK) + begin + if rising_edge(CLK) then + if RESET = '1' then + final_INT_READ_OUT <= (others => '0'); + elsif endpoint_locked = '0' then + final_INT_READ_OUT <= tmp_INT_READ_OUT; + end if; + end if; + end process; + + process(CLK) + begin + if rising_edge(CLK) then + if RESET = '1' then + endpoint_locked <= '0'; + else + endpoint_locked <= next_endpoint_locked; + end if; + end if; + end process; + + INT_READ_OUT <= final_INT_READ_OUT; + + + + + + MUX_SBUF: trb_net_sbuf + generic map (DATA_WIDTH => BUS_WIDTH+2, VERSION => 0) + port map ( + CLK => CLK, + RESET => RESET, + CLK_EN => CLK_EN, + COMB_DATAREADY_IN => mux_read, + COMB_next_READ_OUT => mux_next_READ, + COMB_READ_IN => '1', + COMB_DATA_IN => current_mux_buffer, + SYN_DATAREADY_OUT => MED_DATAREADY_OUT, + SYN_DATA_OUT => MUX_SBUF_data_out, + SYN_READ_IN => MED_READ_IN + ); + + +MED_DATA_OUT <= MUX_SBUF_data_out(BUS_WIDTH-1 downto 0); +MED_PACKET_NUM_OUT <= MUX_SBUF_data_out(BUS_WIDTH+1 downto BUS_WIDTH); + +--this process is easier to implement without implicit priority -> use an OR of all possibilities +-- process (tmp_INT_READ_OUT, INT_DATA_IN, INT_PACKET_NUM_IN) +-- begin +-- current_mux_buffer <= (others => '0'); +-- for i in 0 to 2**MULT_WIDTH-1 loop +-- if tmp_INT_READ_OUT(i) = '1' then +-- current_mux_buffer(BUS_WIDTH-1 downto 0) +-- <= INT_DATA_IN((BUS_WIDTH)*(i+1)-1 downto (BUS_WIDTH)*(i)); +-- current_mux_buffer(BUS_WIDTH+1 downto BUS_WIDTH) <= INT_PACKET_NUM_IN(2*(i+1)-1 downto 2*i); +-- if INT_PACKET_NUM_IN(2*(i+1)-1 downto 2*i) = "00" then +-- current_mux_buffer(3+MULT_WIDTH-1 downto 3) <= conv_std_logic_vector(i, MULT_WIDTH); +-- end if; +-- end if; +-- end loop; +-- end process; + + process (tmp_INT_READ_OUT, INT_DATA_IN, INT_PACKET_NUM_IN) + variable var_mux_buffer : STD_LOGIC_VECTOR (BUS_WIDTH+2-1 downto 0); + begin + var_mux_buffer := (others => '0'); + for i in 0 to 2**MULT_WIDTH-1 loop + if tmp_INT_READ_OUT(i) = '1' then + var_mux_buffer(BUS_WIDTH-1 downto 0) + := var_mux_buffer(BUS_WIDTH-1 downto 0) or INT_DATA_IN((BUS_WIDTH)*(i+1)-1 downto (BUS_WIDTH)*(i)); + var_mux_buffer(BUS_WIDTH+1 downto BUS_WIDTH) + := var_mux_buffer(BUS_WIDTH+1 downto BUS_WIDTH) or INT_PACKET_NUM_IN(2*(i+1)-1 downto 2*i); + if INT_PACKET_NUM_IN(2*(i+1)-1 downto 2*i) = "00" then + var_mux_buffer(3+MULT_WIDTH-1 downto 3) + := var_mux_buffer(3+MULT_WIDTH-1 downto 3) or conv_std_logic_vector(i, MULT_WIDTH); + end if; + end if; + end loop; + current_mux_buffer <= var_mux_buffer; + end process; + + + mux_enable <= (mux_next_READ); -- or MED_READ_IN + mux_read <= or_all(final_INT_READ_OUT and INT_DATAREADY_IN); + +end architecture; \ No newline at end of file diff --git a/trb_net_64_to_18_converter.vhd b/trb_net_64_to_18_converter.vhd new file mode 100644 index 0000000..69a8265 --- /dev/null +++ b/trb_net_64_to_18_converter.vhd @@ -0,0 +1,229 @@ +--this is a converter from 64/55 Bit to 18 Bit format. +--It's just a quick hack and should not be used in the final network +--for example, no packet number check is implemented and one cycle is wasted + + +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.STD_LOGIC_ARITH.ALL; +USE IEEE.STD_LOGIC_UNSIGNED.ALL; +use work.trb_net_std.all; + +--Entity decalaration for clock generator +entity trb_net_64_to_18_converter is + port( + -- Misc + CLK : in std_logic; + RESET : in std_logic; + CLK_EN : in std_logic; + + D55_DATA_IN : in std_logic_vector(50 downto 0); + D55_DATAREADY_IN : in std_logic; + D55_READ_OUT : out std_logic; + + D18_DATA_OUT : out std_logic_vector(15 downto 0); + D18_PACKET_NUM_OUT : out std_logic_vector(1 downto 0); + D18_DATAREADY_OUT : out std_logic; + D18_READ_IN : in std_logic; + + D55_DATA_OUT : out std_logic_vector(50 downto 0); + D55_DATAREADY_OUT : out std_logic; + D55_READ_IN : in std_logic; + + D18_DATA_IN : in std_logic_vector(15 downto 0); + D18_PACKET_NUM_IN : in std_logic_vector(1 downto 0); + D18_DATAREADY_IN : in std_logic; + D18_READ_OUT : out std_logic + ); +end entity; + + +architecture trb_net_64_to_18_converter_arch of trb_net_64_to_18_converter is + + + +type CONV_STATE is (IDLE, FIRST, SECOND, THIRD, LAST); +signal D55to18_state, next_D55to18_state : CONV_STATE; +signal D18to55_state, next_D18to55_state : CONV_STATE; + +signal next_D55_READ_OUT, buf_D55_READ_OUT : std_logic; +signal next_D18_DATAREADY_OUT, buf_D18_DATAREADY_OUT : std_logic; +signal next_D18_PACKET_NUM_OUT, buf_D18_PACKET_NUM_OUT : std_logic_vector(1 downto 0); +signal next_D18_DATA_OUT, buf_D18_DATA_OUT : std_logic_vector(15 downto 0); + + +signal next_D18_READ_OUT, buf_D18_READ_OUT : std_logic; +signal next_D55_DATAREADY_OUT, buf_D55_DATAREADY_OUT : std_logic; +signal next_dataread55, dataread55 : std_logic; + --data from 55 read and waiting to be written + +signal next_buf_D55_DATA_IN, buf_D55_DATA_IN : std_logic_vector(50 downto 0); +signal next_D55_DATA_OUT, buf_D55_DATA_OUT : std_logic_vector(50 downto 0); + --databuffer for both directions +begin +----------------------------------------------------------- +--Direction 18 to 55 +----------------------------------------------------------- + + D18to55_fsm : process(D55_READ_IN, buf_D55_DATAREADY_OUT, buf_D18_READ_OUT, D18_DATAREADY_IN, + D18to55_state, buf_D55_DATA_OUT, D18_DATA_IN) + variable dataisread18, dataisread55 : std_logic; + begin + next_D55_DATA_OUT <= buf_D55_DATA_OUT; + next_D18to55_state <= D18to55_state; + next_D18_READ_OUT <= '1'; + next_D55_DATAREADY_OUT <= '0'; + + dataisread55 := D55_READ_IN AND buf_D55_DATAREADY_OUT; + dataisread18 := buf_D18_READ_OUT AND D18_DATAREADY_IN; + + + case D18to55_state is + when IDLE => + if(dataisread18 = '1') then + next_D55_DATA_OUT(50 downto 48) <= D18_DATA_IN(2 downto 0); + next_D18to55_state <= FIRST; + end if; + when FIRST => + if(dataisread18 = '1') then + next_D55_DATA_OUT(47 downto 32) <= D18_DATA_IN; + next_D18to55_state <= SECOND; + end if; + when SECOND => + if(dataisread18 = '1') then + next_D55_DATA_OUT(31 downto 16) <= D18_DATA_IN; + next_D18to55_state <= THIRD; + end if; + when THIRD => + if(dataisread18 = '1') then + next_D55_DATA_OUT(15 downto 0) <= D18_DATA_IN; + next_D55_DATAREADY_OUT <= '1'; + next_D18to55_state <= LAST; + next_D18_READ_OUT <= '0'; + end if; + when LAST => + if(dataisread55 = '1') then + next_D55_DATA_OUT <= (others => '0'); + next_D55_DATAREADY_OUT <= '0'; + next_D18to55_state <= IDLE; + else + next_D18_READ_OUT <= '0'; + next_D55_DATAREADY_OUT <= '1'; + end if; + end case; + end process; + + D18to55_fsm_reg : process(CLK) + begin + if rising_edge(CLK) then + if RESET = '1' then + buf_D55_DATA_OUT <= (others => '0'); + D18to55_state <= IDLE; + buf_D55_DATAREADY_OUT <= '0'; + buf_D18_READ_OUT <= '0'; + else + buf_D55_DATA_OUT <= next_D55_DATA_OUT; + D18to55_state <= next_D18to55_state; + buf_D55_DATAREADY_OUT <= next_D55_DATAREADY_OUT; + buf_D18_READ_OUT <= next_D18_READ_OUT; + end if; + end if; + end process; + +D55_DATA_OUT <= buf_D55_DATA_OUT; +D55_DATAREADY_OUT <= buf_D55_DATAREADY_OUT; +D18_READ_OUT <= buf_D18_READ_OUT; + +----------------------------------------------------------- +--Direction 55 to 18 +----------------------------------------------------------- + D55to18_fsm : process(buf_D18_DATA_OUT, buf_D18_PACKET_NUM_OUT, buf_D18_DATAREADY_OUT, + D18_READ_IN, D55_DATA_IN, D55_DATAREADY_IN, D55to18_state, + buf_D55_READ_OUT, buf_D55_DATA_IN, dataread55) + variable dataisread18, dataisread55 : std_logic; + begin + next_D18_DATA_OUT <= buf_D18_DATA_OUT; + next_D18_PACKET_NUM_OUT <= buf_D18_PACKET_NUM_OUT; + next_D55to18_state <= D55to18_state; + next_D55_READ_OUT <= '0'; + next_buf_D55_DATA_IN <= buf_D55_DATA_IN; + + dataisread18 := D18_READ_IN AND buf_D18_DATAREADY_OUT; + dataisread55 := D55_DATAREADY_IN AND buf_D55_READ_OUT; + + if(dataisread18 = '1') then + next_D18_DATAREADY_OUT <= '0'; + else + next_D18_DATAREADY_OUT <= buf_D18_DATAREADY_OUT; + end if; + + + case D55to18_state is + when IDLE => + if (dataisread18 = '1' OR buf_D18_DATAREADY_OUT = '0') then + next_D55_READ_OUT <= '1'; + if dataisread55 = '1' then + next_buf_D55_DATA_IN(50 downto 0) <= D55_DATA_IN(50 downto 0); + next_D55_READ_OUT <= '0'; + next_D18_DATA_OUT(2 downto 0) <= D55_DATA_IN(50 downto 48); + next_D18_DATA_OUT(15 downto 3) <= (others => '0'); + next_D18_PACKET_NUM_OUT <= "00"; + next_D18_DATAREADY_OUT <= '1'; + next_D55to18_state <= FIRST; + end if; + end if; + when FIRST => + if(dataisread18 = '1') then + next_D18_DATA_OUT(15 downto 0) <= buf_D55_DATA_IN(47 downto 32); + next_D18_DATAREADY_OUT <= '1'; + next_D18_PACKET_NUM_OUT <= "01"; + next_D55to18_state <= SECOND; + end if; + when SECOND => + if(dataisread18 = '1') then + next_D18_DATA_OUT(15 downto 0) <= buf_D55_DATA_IN(31 downto 16); + next_D18_DATAREADY_OUT <= '1'; + next_D18_PACKET_NUM_OUT <= "10"; + next_D55to18_state <= THIRD; + end if; + when THIRD => + if(dataisread18 = '1') then + next_D18_DATA_OUT(15 downto 0) <= buf_D55_DATA_IN(15 downto 0); + next_D18_DATAREADY_OUT <= '1'; + next_D18_PACKET_NUM_OUT <= "11"; + next_D55to18_state <= IDLE; + next_D55_READ_OUT <= '1'; + end if; + when others => + next_D55to18_state <= IDLE; + end case; + end process; + + D55to18_fsm_reg : process(CLK) + begin + if rising_edge(CLK) then + if RESET = '1' then + buf_D18_DATA_OUT <= (others => '0'); + buf_D55_DATA_IN <= (others => '0'); + buf_D55_READ_OUT <= '0'; + buf_D18_DATAREADY_OUT <= '0'; + buf_D18_PACKET_NUM_OUT <= "00"; + D55to18_state <= IDLE; + else + buf_D18_DATA_OUT <= next_D18_DATA_OUT; + buf_D18_DATAREADY_OUT <= next_D18_DATAREADY_OUT; + buf_D55_READ_OUT <= next_D55_READ_OUT; + buf_D55_DATA_IN <= next_buf_D55_DATA_IN; + buf_D18_PACKET_NUM_OUT <= next_D18_PACKET_NUM_OUT; + D55to18_state <= next_D55to18_state; + end if; + end if; + end process; + +D18_DATA_OUT <= buf_D18_DATA_OUT; +D18_DATAREADY_OUT <= buf_D18_DATAREADY_OUT; +D18_PACKET_NUM_OUT <= buf_D18_PACKET_NUM_OUT; +D55_READ_OUT <= buf_D55_READ_OUT; + + +end architecture; \ No newline at end of file