URL
https://opencores.org/ocsvn/tosnet/tosnet/trunk
Subversion Repositories tosnet
[/] [tosnet/] [trunk/] [gateware/] [TosNet_rev3_2/] [tal_top.vhd] - Rev 4
Go to most recent revision | Compare with Previous | Blame | View Log
---------------------------------------------------------------------------------- -- Company: University of Southern Denmark -- Engineer: Simon Falsig -- -- Create Date: 17/3/2008 -- Design Name TosNet -- Module Name: tal_top - Behavioral -- File Name: tal_top.vhd -- Project Name: TosNet -- Target Devices: Spartan3/6 -- Tool versions: Xilinx ISE 12.2 -- Description: The TosNet application layer handles the shared memory block, -- and keeps it updated. It also handles the FIFO buffers used -- for the asynchronous communication. -- -- Revision: -- Revision 3.2 - Initial release -- -- Copyright 2010 -- -- This module is free software: you can redistribute it and/or modify -- it under the terms of the GNU Lesser General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This module is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public License -- along with this module. If not, see <http://www.gnu.org/licenses/>. ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.NUMERIC_STD.ALL; ---- Uncomment the following library declaration if instantiating ---- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity tal_top is Generic(disable_master : in STD_LOGIC := '0'; disable_slave : in STD_LOGIC := '1'; disable_async : in STD_LOGIC := '1'); Port ( node_id : in STD_LOGIC_VECTOR(3 downto 0); max_skipped_writes : in STD_LOGIC_VECTOR(15 downto 0); max_skipped_reads : in STD_LOGIC_VECTOR(15 downto 0); data_in : in STD_LOGIC_VECTOR(7 downto 0); data_in_strobe : in STD_LOGIC; data_in_enable : in STD_LOGIC; data_out : out STD_LOGIC_VECTOR(7 downto 0); data_out_strobe : out STD_LOGIC; data_out_enable : out STD_LOGIC; buffer_full : in STD_LOGIC; packet_error : in STD_LOGIC; force_packet_error : out STD_LOGIC; sync_strobe : in STD_LOGIC; network_reg_addr : out STD_LOGIC_VECTOR(3 downto 0); network_reg_data : in STD_LOGIC_VECTOR(31 downto 0); network_reg_clk : out STD_LOGIC; data_reg_addr : in STD_LOGIC_VECTOR(9 downto 0); data_reg_data_in : in STD_LOGIC_VECTOR(31 downto 0); data_reg_data_out : out STD_LOGIC_VECTOR(31 downto 0); data_reg_clk : in STD_LOGIC; data_reg_we : in STD_LOGIC_VECTOR(0 downto 0); data_reg_commit_write : in STD_LOGIC; data_reg_commit_read : in STD_LOGIC; skip_count_write : out STD_LOGIC_VECTOR(15 downto 0); skip_count_read : out STD_LOGIC_VECTOR(15 downto 0); current_buffer_index : out STD_LOGIC_VECTOR(3 downto 0); node_address : in STD_LOGIC_VECTOR(3 downto 0); is_master : in STD_LOGIC; clk_50M : in STD_LOGIC; pause : in STD_LOGIC; pause_ack : out STD_LOGIC; reset : in STD_LOGIC; system_halt : out STD_LOGIC; reset_counter : out STD_LOGIC_VECTOR(31 downto 0); packet_counter : out STD_LOGIC_VECTOR(31 downto 0); error_counter : out STD_LOGIC_VECTOR(31 downto 0); async_in_data : in STD_LOGIC_VECTOR(37 downto 0); async_out_data : out STD_LOGIC_VECTOR(37 downto 0); async_in_clk : in STD_LOGIC; async_out_clk : in STD_LOGIC; async_in_full : out STD_LOGIC; async_out_empty : out STD_LOGIC; async_in_wr_en : in STD_LOGIC; async_out_rd_en : in STD_LOGIC; async_out_valid : out STD_LOGIC); end tal_top; architecture Behavioral of tal_top is constant ASYNC_M2S_VALID : STD_LOGIC_VECTOR := "1001"; constant ASYNC_S2M_VALID : STD_LOGIC_VECTOR := "1010"; constant ASYNC_M2S_INVALID : STD_LOGIC_VECTOR := "0001"; constant ASYNC_S2M_INVALID : STD_LOGIC_VECTOR := "0010"; type SLV_STATES is (IDLE, ADDR_1, ADDR_2, ADDR_3, DATA, ASYNC_CTL_HEAD, ASYNC, ASYNC_CTL_TAIL); type MST_TRN_STATES is (IDLE, ADDR_1, ADDR_2, ADDR_3, DATA, ASYNC_CTL_HEAD, ASYNC, ASYNC_CTL_TAIL, WAIT_STATE); type MST_REC_STATES is (IDLE, ADDR_1, ADDR_2, ADDR_3, DATA, ASYNC_CTL_HEAD, ASYNC, ASYNC_CTL_TAIL); signal slv_state : SLV_STATES := IDLE; signal next_slv_state : SLV_STATES := IDLE; signal mst_trn_state : MST_TRN_STATES := IDLE; signal next_mst_trn_state : MST_TRN_STATES := IDLE; signal mst_rec_state : MST_REC_STATES := IDLE; signal next_mst_rec_state : MST_REC_STATES := IDLE; signal slave_reset : STD_LOGIC; signal master_reset : STD_LOGIC; signal last_data_in_strobe : STD_LOGIC := '0'; signal current_user_reg_write : STD_LOGIC := '0'; signal current_sys_reg_write : STD_LOGIC := '1'; signal current_user_reg_read : STD_LOGIC := '0'; signal current_sys_reg_read : STD_LOGIC := '1'; signal skip_counter_write : STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000"; signal skip_counter_read : STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000"; signal write_commited : STD_LOGIC := '0'; signal read_commited : STD_LOGIC := '0'; signal last_commit_write : STD_LOGIC; signal last_commit_read : STD_LOGIC; signal data_reg_addr_user : STD_LOGIC_VECTOR(10 downto 0) := "00000000000"; signal sync_ok : STD_LOGIC := '1'; signal last_sync_strobe : STD_LOGIC := '0'; signal slv_current_node : STD_LOGIC_VECTOR(3 downto 0) := "0000"; signal slv_current_reg : STD_LOGIC_VECTOR(2 downto 0) := "000"; signal slv_current_rw : STD_LOGIC := '0'; --Read: '0', Write: '1' signal slv_current_var : STD_LOGIC_VECTOR(3 downto 0) := "0000"; signal slv_current_reg_ok : STD_LOGIC; signal slv_current_node_address : STD_LOGIC_VECTOR(3 downto 0); signal slv_current_node_id : STD_LOGIC_VECTOR(3 downto 0); signal slv_current_node_read_reg_enable : STD_LOGIC_VECTOR(7 downto 0); signal slv_current_node_write_reg_enable : STD_LOGIC_VECTOR(7 downto 0); signal mst_trn_current_node : STD_LOGIC_VECTOR(3 downto 0) := "0000"; signal mst_trn_current_reg : STD_LOGIC_VECTOR(2 downto 0) := "000"; signal mst_trn_current_rw : STD_LOGIC := '0'; --Read: '0', Write: '1' signal mst_trn_current_var : STD_LOGIC_VECTOR(3 downto 0) := "0000"; signal mst_trn_current_reg_ok : STD_LOGIC; signal mst_trn_current_node_address : STD_LOGIC_VECTOR(3 downto 0); signal mst_trn_current_node_id : STD_LOGIC_VECTOR(3 downto 0); signal mst_trn_current_node_read_reg_enable : STD_LOGIC_VECTOR(7 downto 0); signal mst_trn_current_node_write_reg_enable: STD_LOGIC_VECTOR(7 downto 0); signal mst_rec_current_node : STD_LOGIC_VECTOR(3 downto 0) := "0000"; signal mst_rec_current_reg : STD_LOGIC_VECTOR(2 downto 0) := "000"; signal mst_rec_current_rw : STD_LOGIC := '0'; --Read: '0', Write: '1' signal mst_rec_current_var : STD_LOGIC_VECTOR(3 downto 0) := "0000"; signal mst_rec_current_reg_ok : STD_LOGIC; signal mst_rec_current_node_address : STD_LOGIC_VECTOR(3 downto 0); signal mst_rec_current_node_id : STD_LOGIC_VECTOR(3 downto 0); signal mst_rec_current_node_read_reg_enable : STD_LOGIC_VECTOR(7 downto 0); signal mst_rec_current_node_write_reg_enable: STD_LOGIC_VECTOR(7 downto 0); signal data_in_buffer : STD_LOGIC_VECTOR(7 downto 0); signal waiting_for_trn : STD_LOGIC; signal data_reg_internal_clk : STD_LOGIC; signal data_reg_internal_data_in : STD_LOGIC_VECTOR(7 downto 0); signal data_reg_internal_addr : STD_LOGIC_VECTOR(12 downto 0); signal data_reg_internal_data_out : STD_LOGIC_VECTOR(7 downto 0); signal data_reg_internal_we : STD_LOGIC_VECTOR(0 downto 0); signal async_rd_en : STD_LOGIC; signal async_wr_en : STD_LOGIC; signal async_rd_data : STD_LOGIC_VECTOR(37 downto 0); signal async_wr_data : STD_LOGIC_VECTOR(37 downto 0); signal async_full : STD_LOGIC; signal async_empty : STD_LOGIC; signal async_valid : STD_LOGIC; signal async_buffer : STD_LOGIC_VECTOR(95 downto 0); signal async_trn_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_trn_valid_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_rec_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_rec_valid_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_trn_target : STD_LOGIC_VECTOR(3 downto 0); signal async_rec_target : STD_LOGIC_VECTOR(3 downto 0); signal async_trn_done : STD_LOGIC; signal async_wr_be : STD_LOGIC_VECTOR(1 downto 0); signal async_rec_valid : STD_LOGIC; signal async_slv_buffer : STD_LOGIC_VECTOR(95 downto 0); signal async_slv_trn_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_slv_trn_valid_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_slv_rec_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_slv_rec_valid_byte_count : STD_LOGIC_VECTOR(3 downto 0); signal async_slv_trn_target : STD_LOGIC_VECTOR(3 downto 0); signal async_slv_rec_target : STD_LOGIC_VECTOR(3 downto 0); signal async_slv_trn_done : STD_LOGIC; signal async_slv_wr_be : STD_LOGIC_VECTOR(1 downto 0); signal async_slv_valid : STD_LOGIC; signal async_slv_broadcast : STD_LOGIC; signal read_done : STD_LOGIC; signal read_progress : STD_LOGIC_VECTOR(1 downto 0); signal write_done : STD_LOGIC; signal write_progress : STD_LOGIC_VECTOR(1 downto 0); signal slv_progress : STD_LOGIC_VECTOR(1 downto 0); signal rw_arbiter : STD_LOGIC; signal reset_counter_int : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000"; signal packet_counter_int : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000"; signal error_counter_int : STD_LOGIC_VECTOR(31 downto 0) := "00000000000000000000000000000000"; signal reset_counted : STD_LOGIC := '0'; component data_reg is Port ( clka : in STD_LOGIC; dina : in STD_LOGIC_VECTOR(7 downto 0); addra : in STD_LOGIC_VECTOR(12 downto 0); wea : in STD_LOGIC_VECTOR(0 downto 0); douta : out STD_LOGIC_VECTOR(7 downto 0); clkb : in STD_LOGIC; dinb : in STD_LOGIC_VECTOR(31 downto 0); addrb : in STD_LOGIC_VECTOR(10 downto 0); web : in STD_LOGIC_VECTOR(0 downto 0); doutb : out STD_LOGIC_VECTOR(31 downto 0)); end component; component async_fifo is Port ( rst : in STD_LOGIC; wr_clk : in STD_LOGIC; rd_clk : in STD_LOGIC; din : in STD_LOGIC_VECTOR(37 downto 0); wr_en : in STD_LOGIC; rd_en : in STD_LOGIC; dout : out STD_LOGIC_VECTOR(37 downto 0); full : out STD_LOGIC; empty : out STD_LOGIC; valid : out STD_LOGIC); end component; begin data_reg_inst : data_reg Port map ( clka => data_reg_internal_clk, dina => data_reg_internal_data_in, addra => data_reg_internal_addr, wea => data_reg_internal_we, douta => data_reg_internal_data_out, clkb => data_reg_clk, dinb => data_reg_data_in, addrb => data_reg_addr_user, web => data_reg_we, doutb => data_reg_data_out); async_enabled: if(disable_async = '0') generate in_fifo : async_fifo Port map ( rst => reset, wr_clk => async_in_clk, rd_clk => clk_50M, din => async_in_data, wr_en => async_in_wr_en, rd_en => async_rd_en, dout => async_rd_data, full => async_in_full, empty => async_empty, valid => async_valid); out_fifo : async_fifo Port map ( rst => reset, wr_clk => clk_50M, rd_clk => async_out_clk, din => async_wr_data, wr_en => async_wr_en, rd_en => async_out_rd_en, dout => async_out_data, full => async_full, empty => async_out_empty, valid => async_out_valid); end generate; async_disabled: if(disable_async = '1') generate async_rd_data <= (others => '0'); async_in_full <= '1'; async_empty <= '1'; async_valid <= '0'; async_out_data <= (others => '0'); async_full <= '1'; async_out_empty <= '1'; async_out_valid <= '0'; end generate; data_reg_addr_user <= current_user_reg_write & data_reg_addr when --Create the address for the data register depending on the current buffer selection... (((data_reg_addr(9 downto 6) = node_id) and data_reg_addr(2) = '0') or (not(data_reg_addr(9 downto 6) = node_id) and data_reg_addr(2) = '1')) else current_user_reg_read & data_reg_addr; slave_reset <= (reset or is_master) or disable_slave; --The disable switches work by simply making sure that the slave- or master-reset is '1' always master_reset <= (reset or not is_master) or disable_master; --XST will thus be able to optimize most of the slave- or master-functionality away...:) error_counter <= error_counter_int; packet_counter <= packet_counter_int; reset_counter <= reset_counter_int; skip_count_write <= skip_counter_write; skip_count_read <= skip_counter_read; current_buffer_index <= current_user_reg_write & current_user_reg_read & current_sys_reg_write & current_sys_reg_read; force_packet_error <= (packet_error and not is_master) and not reset; --If we are forwarding a packet (slave only), and the current packet has an error, make sure that the packet is poisoned... process(clk_50M) begin if(clk_50M = '1' and clk_50M'EVENT) then if(reset = '1') then write_commited <= '0'; read_commited <= '0'; skip_counter_write <= "0000000000000000"; skip_counter_read <= "0000000000000000"; system_halt <= '0'; sync_ok <= '1'; --Make sure that the system starts automagically when it exits reset pause_ack <= '0'; if(reset_counted = '0') then reset_counter_int <= reset_counter_int + 1; reset_counted <= '1'; end if; else reset_counted <= '0'; end if; if(data_reg_commit_write = '1' and last_commit_write = '0') then write_commited <= '1'; end if; if(data_reg_commit_read = '1' and last_commit_read = '0') then read_commited <= '1'; end if; if((sync_strobe = '1') and (last_sync_strobe = '0')) then if(write_commited = '1' and packet_error = '0') then --Handle the doublebuffering for the write buffers if(current_user_reg_write = '1') then current_user_reg_write <= '0'; else current_user_reg_write <= '1'; end if; if(current_sys_reg_write = '1') then current_sys_reg_write <= '0'; else current_sys_reg_write <= '1'; end if; write_commited <= '0'; skip_counter_write <= "0000000000000000"; else skip_counter_write <= skip_counter_write + 1; end if; if(read_commited = '1' and packet_error = '0') then --Handle the doublebuffering for the read buffers if(current_user_reg_read = '1') then current_user_reg_read <= '0'; else current_user_reg_read <= '1'; end if; if(current_sys_reg_read = '1') then current_sys_reg_read <= '0'; else current_sys_reg_read <= '1'; end if; read_commited <= '0'; skip_counter_read <= "0000000000000000"; else skip_counter_read <= skip_counter_read + 1; end if; sync_ok <= '1'; packet_counter_int <= packet_counter_int + 1; if(packet_error = '1') then error_counter_int <= error_counter_int + 1; end if; if(pause = '1' and is_master = '1') then --Handle pause functionality pause_ack <= '1'; else pause_ack <= '0'; end if; end if; if(((skip_counter_write > max_skipped_writes) and not(max_skipped_writes = 0)) or --The system only uses the skip counters if they're different from 0. If 0, an unlimited number of skips are allowed... ((skip_counter_read > max_skipped_reads) and not (max_skipped_reads = 0))) then system_halt <= '1'; end if; async_wr_en <= '0'; ------------------------------------------------------------------------ -- Slave synchronous part ------------------------------------------------------------------------ if(slave_reset = '1') then slv_state <= IDLE; slv_current_node <= "0000"; slv_current_rw <= '0'; slv_current_var <= "0000"; async_slv_buffer <= (others => '0'); async_slv_trn_byte_count <= (others => '0'); async_slv_trn_valid_byte_count <= (others => '0'); async_slv_rec_byte_count <= (others => '0'); async_slv_rec_valid_byte_count <= (others => '0'); async_slv_trn_target <= (others => '0'); async_slv_rec_target <= (others => '0'); async_slv_trn_done <= '0'; async_slv_wr_be <= (others => '0'); async_slv_valid <= '0'; async_slv_broadcast <= '0'; slv_progress <= "00"; else slv_state <= next_slv_state; case slv_state is when IDLE => slv_current_node <= "0000"; slv_current_rw <= '0'; slv_current_var <= "0000"; data_out_strobe <= '0'; data_out_enable <= '0'; async_slv_buffer <= (others => '0'); async_slv_trn_byte_count <= (others => '0'); async_slv_trn_valid_byte_count <= (others => '0'); async_slv_rec_byte_count <= (others => '0'); async_slv_rec_valid_byte_count <= (others => '0'); async_slv_trn_target <= (others => '0'); async_slv_rec_target <= (others => '0'); async_slv_trn_done <= '0'; async_slv_wr_be <= (others => '0'); async_slv_valid <= '0'; async_slv_broadcast <= '0'; slv_progress <= "00"; when ADDR_1 => --Retreive network register entry for node network_reg_addr <= slv_current_node; network_reg_clk <= '0'; sync_ok <= '0'; when ADDR_2 => network_reg_clk <= '1'; when ADDR_3 => network_reg_clk <= '0'; slv_current_node_address <= network_reg_data(7 downto 4); slv_current_node_id <= network_reg_data(3 downto 0); slv_current_node_read_reg_enable <= network_reg_data(15 downto 8); slv_current_node_write_reg_enable <= network_reg_data(23 downto 16); slv_current_rw <= '0'; slv_current_var <= "0000"; when DATA => --Receive, store, and forward packet data_out_enable <= '1'; if(slv_current_reg_ok = '0') then --No more registers for this part if(slv_current_rw = '0') then --If read registers are currently selected, slv_current_rw <= '1'; --then switch to write else --else the node is done, slv_current_rw <= '0'; slv_current_node <= slv_current_node + 1; --so go to the next node... slv_current_var <= "0000"; end if; else if(data_in_strobe = '1' and last_data_in_strobe = '0') then if(slv_current_node = node_address) then if(slv_current_rw = '1') then --Ignore the Read registers from this node, we're only interested in the write registers... data_reg_internal_addr <= current_sys_reg_read & slv_current_node_id & slv_current_reg & '1' & slv_current_var; data_reg_internal_data_in <= data_in; data_reg_internal_we <= "1"; data_reg_internal_clk <= '0'; data_out <= data_reg_internal_data_out; data_out_strobe <= '1'; else data_out <= data_in; data_out_strobe <= '1'; end if; else data_reg_internal_addr <= current_sys_reg_read & slv_current_node_id & slv_current_reg & slv_current_rw & slv_current_var; data_reg_internal_data_in <= data_in; data_reg_internal_we <= "1"; data_reg_internal_clk <= '0'; data_out <= data_in; data_out_strobe <= '1'; end if; elsif(data_in_strobe = '0' and last_data_in_strobe = '1') then if(not((slv_current_node = node_address) and (slv_current_rw = '0'))) then data_reg_internal_clk <= '1'; end if; data_out_strobe <= '0'; if(slv_current_var = "1111") then --All vars for this register read, set the reg_enable bit for this register to 0 to go to the next register if(slv_current_rw = '0') then slv_current_node_read_reg_enable(conv_integer(slv_current_reg)) <= '0'; else slv_current_node_write_reg_enable(conv_integer(slv_current_reg)) <= '0'; end if; end if; slv_current_var <= slv_current_var + 1; elsif((data_reg_internal_clk = '1') and (data_reg_internal_we = "1") and (data_in_strobe = '0')) then data_reg_internal_clk <= '0'; data_reg_internal_addr <= current_sys_reg_write & slv_current_node_id & slv_current_reg & '0' & slv_current_var; data_reg_internal_we <= "0"; elsif((data_reg_internal_clk = '0') and (data_reg_internal_we = "0") and (data_in_strobe = '0')) then data_reg_internal_clk <= '1'; else data_reg_internal_clk <= '0'; data_reg_internal_we <= "1"; end if; end if; when ASYNC_CTL_HEAD => if(data_in_strobe = '1' and last_data_in_strobe = '0') then if(data_in = ASYNC_M2S_VALID & NODE_ID) then --Data for this node only received async_slv_valid <= '1'; if(async_valid = '1') then data_out <= ASYNC_S2M_VALID & NODE_ID; else data_out <= ASYNC_S2M_INVALID & NODE_ID; end if; elsif(data_in = ASYNC_M2S_VALID & "0000") then --Broadcast received data_out <= data_in; async_slv_valid <= '1'; async_trn_done <= '1'; async_slv_broadcast <= '1'; else --Nothing of interest for this node async_slv_valid <= '0'; data_out <= data_in; end if; data_out_strobe <= '1'; end if; when ASYNC => data_out_strobe <= '0'; if(data_in_strobe = '1' and last_data_in_strobe = '0') then if(async_slv_valid = '0') then data_out <= data_in; data_out_strobe <= '1'; else async_slv_buffer <= async_slv_buffer(87 downto 0) & data_in; async_slv_rec_byte_count <= async_slv_rec_byte_count + 1; if(async_valid = '1') then if(async_slv_trn_byte_count = 0) then async_slv_trn_target <= async_rd_data(35 downto 32); end if; else async_slv_trn_done <= '1'; end if; slv_progress <= "01"; end if; elsif(slv_progress = "01") then --We'll only increase slv_progress if async_slv_valid is true, thus no need for a (redundant) check for validity here... if(async_slv_trn_done = '0' and async_slv_trn_target = async_rd_data(35 downto 32)) then case async_slv_trn_byte_count(1 downto 0) is when "00" => data_out <= async_rd_data(31 downto 24); if(async_rd_data(37 downto 36) = "00") then async_slv_trn_done <= '1'; end if; when "01" => data_out <= async_rd_data(23 downto 16); if(async_rd_data(37 downto 36) = "01") then async_slv_trn_done <= '1'; end if; when "10" => data_out <= async_rd_data(15 downto 8); if(async_rd_data(37 downto 36) = "10") then async_slv_trn_done <= '1'; end if; when "11" => data_out <= async_rd_data(7 downto 0); when others => end case; async_slv_trn_valid_byte_count <= async_slv_trn_valid_byte_count + 1; else data_out <= data_in; async_slv_trn_done <= '1'; end if; data_out_strobe <= '1'; async_slv_trn_byte_count <= async_slv_trn_byte_count + 1; slv_progress <= "10"; elsif(slv_progress = "10") then slv_progress <= "00"; end if; when ASYNC_CTL_TAIL => data_out_strobe <= '0'; if(data_in_strobe = '1' and last_data_in_strobe = '0' and slv_progress = "00") then if(async_slv_broadcast = '1') then data_out <= data_in; else data_out <= async_slv_trn_valid_byte_count & NODE_ID; end if; data_out_strobe <= '1'; async_slv_rec_valid_byte_count <= data_in(7 downto 4) - 4; async_slv_rec_target <= data_in(3 downto 0); slv_progress <= "01"; if(data_in(7 downto 4) > 3) then async_slv_wr_be <= "11"; else async_slv_wr_be <= data_in(5 downto 4) - 1; end if; elsif(slv_progress = "01") then data_out_strobe <= '0'; if((async_slv_rec_valid_byte_count > 8) and (async_slv_rec_valid_byte_count < 13)) then slv_progress <= "11"; --Done else slv_progress <= "10"; --Delay one clock (we've got lots), to make sure we jump out if no data has been received (8 < async_rec_valid_byte_count < 13) end if; async_wr_en <= '0'; elsif(slv_progress = "10") then async_wr_data <= async_slv_wr_be & async_slv_rec_target & async_slv_buffer(95 downto 64); async_wr_en <= '1'; async_slv_buffer(95 downto 32) <= async_slv_buffer(63 downto 0); async_slv_rec_valid_byte_count <= async_slv_rec_valid_byte_count - 4; if(async_slv_rec_valid_byte_count > 3) then async_slv_wr_be <= "11"; else async_slv_wr_be <= async_slv_rec_valid_byte_count(1 downto 0) - 1; end if; slv_progress <= "01"; end if; end case; end if; ------------------------------------------------------------------------ -- Master TRN synchronous part ------------------------------------------------------------------------ if(master_reset = '1') then mst_trn_state <= IDLE; mst_trn_current_node <= "0000"; mst_trn_current_rw <= '0'; mst_trn_current_var <= "0000"; read_progress <= "00"; read_done <= '1'; async_trn_byte_count <= (others => '0'); async_trn_valid_byte_count <= (others => '0'); async_trn_done <= '0'; async_trn_target <= (others => '0'); else mst_trn_state <= next_mst_trn_state; case mst_trn_state is when IDLE => mst_trn_current_node <= "0000"; mst_trn_current_rw <= '0'; mst_trn_current_var <= "0000"; data_out_strobe <= '0'; data_out_enable <= '0'; read_progress <= "00"; read_done <= '1'; async_trn_byte_count <= (others => '0'); async_trn_valid_byte_count <= (others => '0'); async_trn_done <= '0'; async_trn_target <= (others => '0'); when ADDR_1 => --Retreive network register entry for node network_reg_addr <= mst_trn_current_node; network_reg_clk <= '0'; sync_ok <= '0'; pause_ack <= '0'; when ADDR_2 => network_reg_clk <= '1'; when ADDR_3 => network_reg_clk <= '0'; mst_trn_current_node_address <= network_reg_data(7 downto 4); mst_trn_current_node_id <= network_reg_data(3 downto 0); mst_trn_current_node_read_reg_enable <= network_reg_data(15 downto 8); mst_trn_current_node_write_reg_enable <= network_reg_data(23 downto 16); mst_trn_current_rw <= '0'; mst_trn_current_var <= "0000"; when DATA => --Receive, store, and forward packet data_out_enable <= '1'; if(mst_trn_current_reg_ok = '0') then --No more registers for this part if(mst_trn_current_rw = '0') then --If read registers are currently selected, mst_trn_current_rw <= '1'; --then switch to write else --else the node is done, mst_trn_current_rw <= '0'; mst_trn_current_node <= mst_trn_current_node + 1; --so go to the next node... mst_trn_current_var <= "0000"; end if; else if(read_progress = "00" and write_done = '1' and buffer_full = '0' and rw_arbiter = '0') then if(mst_trn_current_rw = '0' and not(mst_trn_current_node = node_address)) then data_reg_internal_addr <= current_sys_reg_read & mst_trn_current_node_id & mst_trn_current_reg & mst_trn_current_rw & mst_trn_current_var; else data_reg_internal_addr <= current_sys_reg_write & mst_trn_current_node_id & mst_trn_current_reg & mst_trn_current_rw & mst_trn_current_var; end if; data_reg_internal_we <= "0"; data_reg_internal_clk <= '0'; read_progress <= "01"; read_done <= '0'; elsif(read_progress = "01") then data_reg_internal_clk <= '1'; read_progress <= "10"; elsif(read_progress = "10") then data_reg_internal_clk <= '0'; data_out <= data_reg_internal_data_out; data_out_strobe <= '1'; read_progress <= "11"; read_done <= '1'; elsif(read_progress = "11") then data_out_strobe <= '0'; read_progress <= "00"; if(mst_trn_current_var = "1111") then --All vars for this register read, set the reg_enable bit for this register to 0 to go to the next register if(mst_trn_current_rw = '0') then mst_trn_current_node_read_reg_enable(conv_integer(mst_trn_current_reg)) <= '0'; else mst_trn_current_node_write_reg_enable(conv_integer(mst_trn_current_reg)) <= '0'; end if; end if; mst_trn_current_var <= mst_trn_current_var + 1; end if; end if; when ASYNC_CTL_HEAD => if(buffer_full = '0' and read_progress <= "00") then if(async_valid = '1') then async_trn_target <= async_rd_data(35 downto 32); data_out <= ASYNC_M2S_VALID & async_rd_data(35 downto 32); else data_out <= ASYNC_M2S_INVALID & "0000"; async_trn_done <= '1'; end if; data_out_strobe <= '1'; read_progress <= "01"; else data_out_strobe <= '0'; end if; when ASYNC => data_out_strobe <= '0'; if(read_progress = "00") then read_progress <= "01"; elsif(read_progress = "01" and buffer_full = '0') then if(async_valid = '0') then async_trn_done <= '1'; end if; read_progress <= "10"; elsif(read_progress = "10") then if(async_trn_done = '0' and async_trn_target = async_rd_data(35 downto 32)) then case async_trn_byte_count(1 downto 0) is when "00" => data_out <= async_rd_data(31 downto 24); if(async_rd_data(37 downto 36) = "00") then async_trn_done <= '1'; end if; when "01" => data_out <= async_rd_data(23 downto 16); if(async_rd_data(37 downto 36) = "01") then async_trn_done <= '1'; end if; when "10" => data_out <= async_rd_data(15 downto 8); if(async_rd_data(37 downto 36) = "10") then async_trn_done <= '1'; end if; when "11" => data_out <= async_rd_data(7 downto 0); when others => end case; async_trn_valid_byte_count <= async_trn_valid_byte_count + 1; else data_out <= (others => '0'); async_trn_done <= '1'; end if; data_out_strobe <= '1'; async_trn_byte_count <= async_trn_byte_count + 1; read_progress <= "11"; elsif(read_progress = "11") then data_out_strobe <= '0'; read_progress <= "00"; end if; when ASYNC_CTL_TAIL => if(read_progress = "00" and buffer_full = '0') then data_out <= async_trn_valid_byte_count & async_trn_target; data_out_strobe <= '1'; read_progress <= "01"; elsif(read_progress = "01") then data_out_strobe <= '0'; read_progress <= "00"; end if; when WAIT_STATE => --Just do nothing... end case; end if; ------------------------------------------------------------------------ -- Master REC synchronous part ------------------------------------------------------------------------ if(master_reset = '1') then mst_rec_state <= IDLE; mst_rec_current_node <= "0000"; mst_rec_current_rw <= '0'; mst_rec_current_var <= "0000"; write_progress <= "00"; write_done <= '1'; async_rec_byte_count <= (others => '0'); async_rec_valid_byte_count <= (others => '0'); async_rec_target <= (others => '0'); async_wr_be <= "00"; async_rec_valid <= '0'; else mst_rec_state <= next_mst_rec_state; case mst_rec_state is when IDLE => mst_rec_current_node <= "0000"; mst_rec_current_rw <= '0'; mst_rec_current_var <= "0000"; write_progress <= "00"; write_done <= '1'; async_rec_byte_count <= (others => '0'); async_rec_valid_byte_count <= (others => '0'); async_rec_target <= (others => '0'); async_wr_be <= "00"; async_rec_valid <= '0'; when ADDR_1 => --Retreive network register entry for node network_reg_addr <= mst_rec_current_node; network_reg_clk <= '0'; sync_ok <= '0'; when ADDR_2 => network_reg_clk <= '1'; when ADDR_3 => network_reg_clk <= '0'; mst_rec_current_node_address <= network_reg_data(7 downto 4); mst_rec_current_node_id <= network_reg_data(3 downto 0); mst_rec_current_node_read_reg_enable <= network_reg_data(15 downto 8); mst_rec_current_node_write_reg_enable <= network_reg_data(23 downto 16); mst_rec_current_rw <= '0'; mst_rec_current_var <= "0000"; when DATA => --Receive, store, and forward packet if(mst_rec_current_reg_ok = '0') then --No more registers for this part if(waiting_for_trn = '0') then if(mst_rec_current_rw = '0') then --If read registers are currently selected, mst_rec_current_rw <= '1'; --then switch to write else --else the node is done, mst_rec_current_rw <= '0'; mst_rec_current_node <= mst_rec_current_node + 1; --so go to the next node... mst_rec_current_var <= "0000"; end if; end if; else if(data_in_strobe = '1' and last_data_in_strobe = '0') then if((mst_rec_current_rw = '1') and not(mst_rec_current_node = node_address)) then --Ignore the Read registers for the nodes, we're only interested in the write registers, which hold the newest data... data_in_buffer <= data_in; write_progress <= "01"; end if; elsif(data_in_strobe = '0' and last_data_in_strobe = '1') then if(mst_rec_current_var = "1111") then --All vars for this register read, set the reg_enable bit for this register to 0 to go to the next register if(mst_rec_current_rw = '0') then mst_rec_current_node_read_reg_enable(conv_integer(mst_rec_current_reg)) <= '0'; else mst_rec_current_node_write_reg_enable(conv_integer(mst_rec_current_reg)) <= '0'; end if; end if; mst_rec_current_var <= mst_rec_current_var + 1; elsif(write_progress = "01" and write_done = '1' and read_done = '1' and rw_arbiter = '1') then data_reg_internal_addr <= current_sys_reg_read & mst_rec_current_node_id & mst_rec_current_reg & '0' & mst_rec_current_var; data_reg_internal_data_in <= data_in_buffer; data_reg_internal_we <= "1"; data_reg_internal_clk <= '0'; write_done <= '0'; write_progress <= "10"; elsif(write_progress = "10" and write_done = '0') then data_reg_internal_clk <= '1'; write_progress <= "11"; elsif(write_progress = "11" and write_done = '0') then data_reg_internal_clk <= '0'; data_reg_internal_we <= "0"; write_done <= '1'; write_progress <= "00"; end if; end if; when ASYNC_CTL_HEAD => if(data_in_strobe = '1' and last_data_in_strobe = '0') then if(data_in(7 downto 4) = ASYNC_S2M_VALID) then async_rec_valid <= '1'; else async_rec_valid <= '0'; end if; end if; when ASYNC => if(data_in_strobe = '1' and last_data_in_strobe = '0') then async_buffer <= async_buffer(87 downto 0) & data_in; async_rec_byte_count <= async_rec_byte_count + 1; end if; when ASYNC_CTL_TAIL => if(data_in_strobe = '1' and last_data_in_strobe = '0' and write_progress = "00") then async_rec_valid_byte_count <= data_in(7 downto 4) - 4; async_rec_target <= data_in(3 downto 0); write_progress <= "01"; if(data_in(7 downto 4) > 3) then async_wr_be <= "11"; else async_wr_be <= data_in(5 downto 4) - 1; end if; elsif(write_progress = "01") then write_progress <= "10"; --Delay one clock (we've got lots), to make sure we jump out if no data has been received (async_rec_valid_byte_count > 8) async_wr_en <= '0'; elsif(write_progress = "10") then async_wr_data <= async_wr_be & async_rec_target & async_buffer(95 downto 64); async_wr_en <= '1'; async_buffer(95 downto 32) <= async_buffer(63 downto 0); async_rec_valid_byte_count <= async_rec_valid_byte_count - 4; if(async_rec_valid_byte_count > 3) then async_wr_be <= "11"; else async_wr_be <= async_rec_valid_byte_count(1 downto 0) - 1; end if; write_progress <= "01"; end if; end case; end if; ------------------------------------------------------------------------ last_data_in_strobe <= data_in_strobe; last_sync_strobe <= sync_strobe; last_commit_write <= data_reg_commit_write; last_commit_read <= data_reg_commit_read; if(rw_arbiter = '0') then rw_arbiter <= '1'; else rw_arbiter <= '0'; end if; end if; end process; ------------------------------------------------------------------------ -- Slave combinatorial next-state logic ------------------------------------------------------------------------ process(slv_state, data_in_enable, slv_current_reg_ok, slv_current_rw, slv_current_node, network_reg_data(7 downto 4), slv_progress, async_slv_trn_byte_count, async_slv_rec_valid_byte_count, data_in_strobe, last_data_in_strobe) begin case slv_state is when IDLE => if(data_in_enable = '1') then next_slv_state <= ADDR_1; else next_slv_state <= IDLE; end if; when ADDR_1 => next_slv_state <= ADDR_2; when ADDR_2 => next_slv_state <= ADDR_3; when ADDR_3 => if(slv_current_node = network_reg_data(7 downto 4)) then next_slv_state <= DATA; else next_slv_state <= ASYNC_CTL_HEAD; end if; when DATA => if(data_in_enable = '0') then next_slv_state <= IDLE; elsif(slv_current_reg_ok = '0' and slv_current_rw = '1') then next_slv_state <= ADDR_1; else next_slv_state <= DATA; end if; when ASYNC_CTL_HEAD => if(data_in_strobe = '1' and last_data_in_strobe = '0') then next_slv_state <= ASYNC; else next_slv_state <= ASYNC_CTL_HEAD; end if; when ASYNC => if(data_in_enable = '0') then next_slv_state <= IDLE; elsif(slv_progress = "00" and async_slv_trn_byte_count = 12) then next_slv_state <= ASYNC_CTL_TAIL; else next_slv_state <= ASYNC; end if; when ASYNC_CTL_TAIL => if(data_in_enable = '0') then next_slv_state <= IDLE; else next_slv_state <= ASYNC_CTL_TAIL; end if; end case; end process; ------------------------------------------------------------------------ -- Master TRN combinatorial next-state logic ------------------------------------------------------------------------ process(mst_trn_state, mst_rec_state, sync_ok, data_in_enable, mst_trn_current_reg_ok, mst_trn_current_rw, mst_trn_current_node, network_reg_data(7 downto 4), pause, read_progress, async_trn_byte_count) begin case mst_trn_state is when IDLE => if(mst_rec_state = IDLE and sync_ok = '1' and pause = '0') then --Make sure that we're done receiving and sync'ing before sending out the next packet (for synchronization, buffering and a couple of other reasons...) next_mst_trn_state <= WAIT_STATE; else next_mst_trn_state <= IDLE; end if; when ADDR_1 => next_mst_trn_state <= ADDR_2; when ADDR_2 => next_mst_trn_state <= ADDR_3; when ADDR_3 => if(mst_trn_current_node = network_reg_data(7 downto 4)) then next_mst_trn_state <= DATA; else next_mst_trn_state <= ASYNC_CTL_HEAD; end if; when DATA => if(mst_trn_current_reg_ok = '0' and mst_trn_current_rw = '1') then next_mst_trn_state <= WAIT_STATE; else next_mst_trn_state <= DATA; end if; when ASYNC_CTL_HEAD => if(read_progress = "01") then next_mst_trn_state <= ASYNC; else next_mst_trn_state <= ASYNC_CTL_HEAD; end if; when ASYNC => if(read_progress = "11" and async_trn_byte_count = 12) then next_mst_trn_state <= ASYNC_CTL_TAIL; else next_mst_trn_state <= ASYNC; end if; when ASYNC_CTL_TAIL => if(read_progress = "01") then next_mst_trn_state <= IDLE; else next_mst_trn_state <= ASYNC_CTL_TAIL; end if; when WAIT_STATE => if(mst_rec_state = DATA or mst_rec_state = IDLE) then next_mst_trn_state <= ADDR_1; else next_mst_trn_state <= WAIT_STATE; end if; end case; end process; ------------------------------------------------------------------------ -- Master REC combinatorial next-state logic ------------------------------------------------------------------------ process(mst_rec_state, mst_trn_state, data_in_enable, mst_rec_current_reg_ok, mst_rec_current_rw, mst_rec_current_node, network_reg_data(7 downto 4), async_rec_byte_count, async_rec_valid_byte_count, async_rec_valid, data_in_strobe, last_data_in_strobe) begin waiting_for_trn <= '0'; case mst_rec_state is when IDLE => if(data_in_enable = '1' and (mst_trn_state = DATA or mst_trn_state = IDLE or mst_trn_state = ASYNC_CTL_HEAD or mst_trn_state = ASYNC or mst_trn_state = ASYNC_CTL_TAIL)) then next_mst_rec_state <= ADDR_1; else next_mst_rec_state <= IDLE; end if; when ADDR_1 => next_mst_rec_state <= ADDR_2; when ADDR_2 => next_mst_rec_state <= ADDR_3; when ADDR_3 => if(mst_rec_current_node = network_reg_data(7 downto 4)) then next_mst_rec_state <= DATA; else next_mst_rec_state <= ASYNC_CTL_HEAD; end if; when DATA => if(data_in_enable = '0') then next_mst_rec_state <= IDLE; elsif(mst_rec_current_reg_ok = '0' and mst_rec_current_rw = '1' and (mst_trn_state = DATA or mst_trn_state = IDLE or mst_trn_state = ASYNC_CTL_HEAD or mst_trn_state = ASYNC or mst_trn_state = ASYNC_CTL_TAIL)) then next_mst_rec_state <= ADDR_1; elsif(mst_rec_current_reg_ok = '0' and mst_rec_current_rw = '1') then waiting_for_trn <= '1'; next_mst_rec_state <= DATA; else next_mst_rec_state <= DATA; end if; when ASYNC_CTL_HEAD => if(data_in_strobe = '1' and last_data_in_strobe = '0') then next_mst_rec_state <= ASYNC; else next_mst_rec_state <= ASYNC_CTL_HEAD; end if; when ASYNC => if(async_rec_byte_count = 12) then next_mst_rec_state <= ASYNC_CTL_TAIL; else next_mst_rec_state <= ASYNC; end if; when ASYNC_CTL_TAIL => if(((async_rec_valid_byte_count > 8) and (async_rec_valid_byte_count < 13)) or async_rec_valid <= '0') then next_mst_rec_state <= IDLE; else next_mst_rec_state <= ASYNC_CTL_TAIL; end if; end case; end process; ------------------------------------------------------------------------ -- Combinatorial logic for address generation ------------------------------------------------------------------------ async_rd_en <= '1' when (((mst_trn_state = ASYNC) and (read_progress = "11") and (async_trn_done = '0') and (async_trn_byte_count(1 downto 0) = "00")) or ((mst_trn_state = ASYNC_CTL_TAIL) and (read_progress = "01") and not (async_trn_valid_byte_count(1 downto 0) = "00")) or ((slv_state = ASYNC) and (slv_progress = "10") and (async_slv_trn_done = '0') and (async_slv_trn_byte_count(1 downto 0) = "00")) or ((slv_state = ASYNC_CTL_TAIL) and (data_in_strobe = '1') and (last_data_in_strobe = '0') and (slv_progress = "00") and not (async_slv_trn_valid_byte_count(1 downto 0) = "00"))) else '0'; slv_current_reg <= "111" when (slv_current_node_read_reg_enable(7) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(7) = '1' and slv_current_rw = '1') else "110" when (slv_current_node_read_reg_enable(6) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(6) = '1' and slv_current_rw = '1') else "101" when (slv_current_node_read_reg_enable(5) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(5) = '1' and slv_current_rw = '1') else "100" when (slv_current_node_read_reg_enable(4) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(4) = '1' and slv_current_rw = '1') else "011" when (slv_current_node_read_reg_enable(3) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(3) = '1' and slv_current_rw = '1') else "010" when (slv_current_node_read_reg_enable(2) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(2) = '1' and slv_current_rw = '1') else "001" when (slv_current_node_read_reg_enable(1) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(1) = '1' and slv_current_rw = '1') else "000"; slv_current_reg_ok <= '0' when slv_current_reg = "000" and not ((slv_current_node_read_reg_enable(0) = '1' and slv_current_rw = '0') or (slv_current_node_write_reg_enable(0) = '1' and slv_current_rw = '1')) else '1'; mst_trn_current_reg <= "111" when (mst_trn_current_node_read_reg_enable(7) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(7) = '1' and mst_trn_current_rw = '1') else "110" when (mst_trn_current_node_read_reg_enable(6) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(6) = '1' and mst_trn_current_rw = '1') else "101" when (mst_trn_current_node_read_reg_enable(5) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(5) = '1' and mst_trn_current_rw = '1') else "100" when (mst_trn_current_node_read_reg_enable(4) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(4) = '1' and mst_trn_current_rw = '1') else "011" when (mst_trn_current_node_read_reg_enable(3) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(3) = '1' and mst_trn_current_rw = '1') else "010" when (mst_trn_current_node_read_reg_enable(2) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(2) = '1' and mst_trn_current_rw = '1') else "001" when (mst_trn_current_node_read_reg_enable(1) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(1) = '1' and mst_trn_current_rw = '1') else "000"; mst_trn_current_reg_ok <= '0' when mst_trn_current_reg = "000" and not ((mst_trn_current_node_read_reg_enable(0) = '1' and mst_trn_current_rw = '0') or (mst_trn_current_node_write_reg_enable(0) = '1' and mst_trn_current_rw = '1')) else '1'; mst_rec_current_reg <= "111" when (mst_rec_current_node_read_reg_enable(7) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(7) = '1' and mst_rec_current_rw = '1') else "110" when (mst_rec_current_node_read_reg_enable(6) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(6) = '1' and mst_rec_current_rw = '1') else "101" when (mst_rec_current_node_read_reg_enable(5) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(5) = '1' and mst_rec_current_rw = '1') else "100" when (mst_rec_current_node_read_reg_enable(4) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(4) = '1' and mst_rec_current_rw = '1') else "011" when (mst_rec_current_node_read_reg_enable(3) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(3) = '1' and mst_rec_current_rw = '1') else "010" when (mst_rec_current_node_read_reg_enable(2) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(2) = '1' and mst_rec_current_rw = '1') else "001" when (mst_rec_current_node_read_reg_enable(1) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(1) = '1' and mst_rec_current_rw = '1') else "000"; mst_rec_current_reg_ok <= '0' when mst_rec_current_reg = "000" and not ((mst_rec_current_node_read_reg_enable(0) = '1' and mst_rec_current_rw = '0') or (mst_rec_current_node_write_reg_enable(0) = '1' and mst_rec_current_rw = '1')) else '1'; end Behavioral;
Go to most recent revision | Compare with Previous | Blame | View Log