---------------------------------------------------------------------------- -- Lawrence Berkeley National Laboratory (c) 1997 -- BaBar Trigger Electronics ---------------------------------------------------------------------------- -- Description: -- Several simple clocked processes, decoding the comand and sub comand. -- This entity also produces the 30MHz alligned strobes from the strobe -- pimitives generated in sm0_clink. ---------------------------------------------------------------------------- -- Structure: -- ltch_cmd: 5 bit latch, latches command -- ltch_tag: 5 bit latch, latches subcommand -- output: decodes latched command and (partial) subcommand, generates reg_rd -- (csr read access strobe) -- str_dec: decodes the access type to determine which strobe to generate. -- Counts the number of words transfered in this cycle to properly -- indicate address or data strobes. -- d_strobe: Uses output of sm0_clink and process str_dec to generate the -- clk30 aligned data and address strobes. -- c_strobe: Uses output of sm0_clink to generate the clk30 aligned cmd_str. ---------------------------------------------------------------------------- -- Timing: -- cmd_str_30 is valid on the first rising edge of clk30 after the -- corresponding cmd_str. ---------------------------------------------------------------------------- -- Author: Armin Karcher -- History: -- Karcher 03/97 - First Version -- Karcher 6/2/97 - Changed op-code 16 to 6 (start play) -- Karcher 8/1/97 - Fixed 32 bit flag -- Liu 10/16/97 -(1) Comment: for opcode 1 (clear readout) -- there is no need for cmd_str here. -- clear readout is internal, never gets out. -- cmd_ext was set to 1. leave it as it is for now. -- -(2) Comment: -- strb_id = 100 is for write mem, -- write add and read csr. Even though start play, -- clear readout, sync, L1A or read Event, -- calibration and user reset can cause -- strb_id = 100, no add_str will be sent. -- Karcher/Marks 4/14/98 - added block write capability -- Karcher 12-11-98 - Finished block write, added opcode 14 for -- input Fifo reframe. externally this signal runs on -- the sync line to input control. -- Fixed read event variable latency bug. -- Karcher 12-15-98 added block read -- ---------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; ---------------------------------------------------------------------------- --PORT DECLARATION ---------------------------------------------------------------------------- entity cmd_decode is port( clk : in std_logic; -- clk60 input, distributed rst : in std_logic; -- global reset clk_30 : in std_logic; -- clk30 c_str : in std_logic; -- strobe on cycle 13 after -- the begin of a 12 bit command sequence nxt_wrd : in std_logic; -- next word (command or data) rd_inc : in std_logic; -- next word during block read latch_t : in std_logic; -- latch subcommand (1-tick strobe) latch_cmd : in std_logic; -- latch command (1-tick strobe) latch_dt : in std_logic; -- latch data (1-tick strobe) dt_in : in std_logic_vector(15 downto 0); -- output of the ser2par shift register, not latched. cmd_ext : out std_logic; -- external command cmd_end : out std_logic; -- transfer/command about to terminate. cmd_lng : out std_logic; -- long command, more than the command -- word (12 bits) will be read from the clink r_w_out : out std_logic; -- direction of internal bus reg_rd : out std_logic; -- read csr register rd_blk : out std_logic; -- read block blk_done : out std_logic; -- read block done inc_add : out std_logic; -- increment address strobe modifier increment_add : out std_logic; -- increment address for -- address counter clr_rd : out std_logic; -- clear readout l1 : out std_logic; -- level1 accept rd_evt : out std_logic; -- read event cal_str : out std_logic; -- calibration strobe sync_out : out std_logic; -- sync reframe : out std_logic; -- clear input fifo usr_rst : out std_logic; -- user (subsystem) reset start_pl : out std_logic; -- start record / playback dt_lng_out : out std_logic; -- data long (32 bit transfer) wr_dt_str : out std_logic; -- write data strobe aligned to clk30 rd_dt_str : out std_logic; -- read data strobe aligned to clk30 ad_str : out std_logic; -- address strobe aligned to clk30 blk_str : out std_logic; -- block addr. strobe aligned to clk30 cmd_str : out std_logic; -- command strobe on cycle 14 cmd_str_30 : out std_logic; -- command strobe aligned to clk30 sel_csr : out std_logic_vector(2 downto 0); -- select csr cmd : out std_logic_vector(4 downto 0); -- latched command tag : out std_logic_vector(4 downto 0) -- " subcommand ); end cmd_decode; architecture rtl of cmd_decode is ---------------------------------------------------------------------------- --SIGNAL DECLARATION ---------------------------------------------------------------------------- signal reg_pre : std_logic; -- delay this signal for register read signal cmd_cond : std_logic; -- command condition (used for cmd_end) signal first_word : std_logic;-- first data word (used during 32 bit transfer) signal dt_lng : std_logic; -- data_long (32 bit transfer) signal r_w : std_logic; -- internal data bus direction signal blk : std_logic; -- current cycle is "write block address" signal csr_acc : std_logic; -- current cycle is a csr access signal mem_acc : std_logic; -- current cycle is a memory access signal cyc_cnt : std_logic_vector(1 downto 0); -- wordcount within cycle signal strb_id : std_logic_vector(2 downto 0); -- what kind of strobe signal cmd_reg : std_logic_vector(4 downto 0); -- latched command signal tag_reg : std_logic_vector(4 downto 0); -- latched subcommand signal sel : std_logic_vector(4 downto 0); -- select strobe type signal latch_del : std_logic; -- delayed latch (used for strobe alignment) signal latch_end : std_logic; -- used for strobe alignment signal str_del : std_logic; -- used for cmd_str alignment signal str_end : std_logic; -- used for cmd_str alignment signal sync : std_logic; -- sync, used to generate proper cmd_str signal dt_blk : std_logic; -- 4K-data blk being transfered signal wr_blk_done : std_logic; -- 4K-data blk transfer finished signal wr_blk_cnt : std_logic_vector(11 downto 0); -- 4K-data blk transfer counter signal dt_inc : std_logic; -- data increment signal inc_add_i : std_logic; -- increment address flag begin ---------------------------------------------------------------------------- --COMPONENT DECLARATION ---------------------------------------------------------------------------- ltch_cmd: process (clk,rst,dt_in(4 downto 0)) begin if (rst = '1') then -- reset all variables cmd_reg <= "00000"; elsif (clk'event and clk = '1') then -- rising edge if ( latch_cmd = '1') then cmd_reg <= dt_in(4 downto 0); end if; end if; end process ltch_cmd; ltch_tag: process (clk,rst,dt_in(4 downto 0)) begin if (rst = '1') then -- reset all variables tag_reg <= "00000"; elsif (clk'event and clk = '1') then -- rising edge if ( latch_t = '1') then tag_reg <= dt_in(4 downto 0); end if; end if; end process ltch_tag; output: process (clk,rst,cmd_reg) begin if (rst = '1') then -- reset all variables cmd_ext <= '0'; cmd_lng <= '0'; r_w <= '0'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; sel_csr(0) <= '0'; sel_csr(1) <= '0'; sel_csr(2) <= '0'; reg_rd <= '0'; reg_pre <= '0'; elsif (clk'event and clk = '1') then -- rising edge sel_csr(2) <= tag_reg(2) AND csr_acc; sel_csr(1) <= tag_reg(3) AND csr_acc; sel_csr(0) <= tag_reg(4) AND csr_acc; reg_rd <= reg_pre; reg_pre <= latch_t AND csr_acc AND r_w; case cmd_reg is when "10000" => -- opcode 1 cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '1'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "01000" => --sync cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '1'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "11000" => cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '1'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "00100" => cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '1'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "10100" => -- opcode 5 SET start_pl for TEST cmd_ext <= '1'; -- change back to cal_str for final system cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '1'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "01100" => -- opcode 6 hex start play cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '1'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "11101" => -- opcode 17 hex write mem cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '0'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '1'; inc_add_i <= '0'; blk <= '0'; when "00101" => -- opcode 14 hex reframe cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '1'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "10101" => -- opcode 15 hex read 4K byte mem (LUT -- only) and inc. add. cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '1'; inc_add_i <= '1'; blk <= '1'; when "01101" => -- opcode 16 hex write 4K mem (LUT -- only) and inc. add. cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '0'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '1'; inc_add_i <= '1'; blk <= '1'; when "00011" => -- opcode 18 hex read mem increment cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '1'; inc_add_i <= '1'; blk <= '0'; when "10011" => -- read mem cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '1'; inc_add_i <= '0'; blk <= '0'; when "01011" => -- write addr cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "11011" => -- mem. block cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '1'; when "00111" => -- write csr cmd_ext <= '0'; cmd_lng <= '1'; r_w <= '0'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '1'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "10111" => --read csr cmd_ext <= '0'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '1'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when "01111" => -- opcode 1e hex usr reset cmd_ext <= '1'; cmd_lng <= '0'; r_w <= '1'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '1'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; when others => cmd_ext <= '0'; cmd_lng <= '0'; r_w <= '0'; clr_rd <= '0'; l1 <= '0'; rd_evt <= '0'; cal_str <= '0'; sync <= '0'; reframe <= '0'; usr_rst <= '0'; start_pl <= '0'; csr_acc <= '0'; mem_acc <= '0'; inc_add_i <= '0'; blk <= '0'; end case; end if; end process output; sel(4) <= blk; sel(3) <= mem_acc; sel(2) <= cyc_cnt(0); sel(1) <= cyc_cnt(1); sel(0) <= r_w; str_dec: process (clk,rst) begin if (rst = '1') then -- reset all variables cyc_cnt <= "00"; strb_id <= "000"; cmd_end <= '0'; cmd_cond <= '0'; dt_lng <= '0'; dt_blk <= '0'; rd_blk <= '0'; r_w_out <= '0'; elsif (clk'event and clk = '1') then -- rising edge cmd_cond <= r_w OR NOT (csr_acc or mem_acc) OR (dt_blk AND wr_blk_done); first_word <= NOT cyc_cnt(1) AND ((r_w AND NOT cyc_cnt(0)) OR NOT r_w); r_w_out <= r_w AND mem_acc; dt_lng <= mem_acc AND tag_reg(4) AND ( first_word OR blk ); dt_blk <= mem_acc AND blk; rd_blk <= mem_acc AND blk AND r_w; if ( latch_cmd = '1') then cyc_cnt <= "00"; elsif (cyc_cnt = "11") then cyc_cnt <= "11"; elsif (nxt_wrd = '1') then cyc_cnt(0) <= NOT cyc_cnt(0); cyc_cnt(1) <= cyc_cnt(1) XOR cyc_cnt(0); end if; if (( cmd_cond = '1' ) OR (dt_blk = '0' AND ((cyc_cnt(0) ='1' AND dt_lng = '0') OR (cyc_cnt(1) ='1')))) then cmd_end <= '1'; else cmd_end <= '0'; end if; case sel is when "01001" => strb_id <= "001"; when "11001" => strb_id <= "001"; when "01100" => strb_id <= "011"; when "01010" => strb_id <= "011"; when "11010" => strb_id <= "000"; -- filler on 2nd address cycle when "11100" => strb_id <= "011"; when "11110" => strb_id <= "011"; when "11000" => strb_id <= "100"; when "01000" => strb_id <= "100"; when "00001" => strb_id <= "100"; when "10001" => strb_id <= "101"; when others => strb_id <= "000"; end case; end if; end process str_dec; d_strobe: process (clk,rst,latch_dt,strb_id) begin if (rst = '1') then -- reset all variables latch_del <= '0'; latch_end <= '0'; rd_dt_str <= '0'; wr_dt_str <= '0'; dt_inc <= '0'; ad_str <= '0'; blk_str <= '0'; increment_add <= '0'; elsif (clk'event and clk = '1') then -- rising edge latch_del <= latch_dt; latch_end <= ((NOT clk_30) AND (latch_dt OR latch_del)); case strb_id is when "001" => rd_dt_str <= latch_end OR ((NOT clk_30) AND (latch_dt OR latch_del)); dt_inc <= rd_inc OR (latch_dt and inc_add_i); wr_dt_str <= '0'; ad_str <= '0'; blk_str <= '0'; when "011" => rd_dt_str <= '0'; wr_dt_str <= latch_end OR ((NOT clk_30) AND (latch_dt OR latch_del)); dt_inc <= latch_dt and inc_add_i; ad_str <= '0'; blk_str <= '0'; when "100" => rd_dt_str <= '0'; wr_dt_str <= '0'; dt_inc <= '0'; ad_str <= latch_end OR ((NOT clk_30) AND (latch_dt OR latch_del)); blk_str <= '0'; when "101" => rd_dt_str <= '0'; wr_dt_str <= '0'; dt_inc <= '0'; ad_str <= '0'; blk_str <= latch_end OR ((NOT clk_30) AND (latch_dt OR latch_del)); when others => rd_dt_str <= '0'; wr_dt_str <= '0'; dt_inc <= '0'; ad_str <= '0'; blk_str <= '0'; end case; increment_add <= dt_inc; end if; end process d_strobe; c_strobe: process (clk,rst,c_str) --allign cmd_str_30 to the next clk_30 begin if (rst = '1') then -- reset all variables str_del <= '0'; str_end <= '0'; cmd_str_30 <= '0'; elsif (clk'event and clk = '1') then -- rising edge str_del <= c_str; str_end <= (clk_30 AND (c_str OR str_del)); cmd_str_30 <= (str_end OR ((clk_30 OR sync) AND (c_str OR str_del))); end if; end process c_strobe; blk_ctr : process (rst,clk) -- blk counter variable ia_tmp : unsigned (11 downto 0); begin -- blk_counter if (rst='1') then wr_blk_cnt <= (others => '0'); wr_blk_done <= '0'; elsif (clk'event and clk='1') then if (dt_blk = '0' OR latch_cmd ='1') then wr_blk_cnt <= (others => '0'); elsif (dt_blk = '1' and (nxt_wrd = '1' OR rd_inc = '1')) then ia_tmp := unsigned(wr_blk_cnt) + 1; wr_blk_cnt <= std_logic_vector(ia_tmp); end if; if (wr_blk_cnt = "100000000001") then wr_blk_done <= '1'; else wr_blk_done <= '0'; end if; end if; end process blk_ctr; ---------------------------------------------------------------------------- --OUTPUT ASSIGNMENTS ---------------------------------------------------------------------------- cmd_str <= str_del; tag <= tag_reg; cmd <= cmd_reg; dt_lng_out <= dt_lng; sync_out <= sync; inc_add <= inc_add_i; blk_done <= wr_blk_done; end rtl;