library IEEE; use IEEE.std_logic_1164.all; use ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; -- Serial master for the PASA test generator -- last modified: 13:12 / 28/Jul/2004 / V.Angelov -- internal address 0 1 -- writing data config -- bits 0 - enable strobe -- bits 1 - enable additional serial clock -- bits 2 - 0 MSB first, 1 LSB first -- bits 3 - enable IRQ when ready, not used here -- bits 4 - enable external IRQ, not used here -- bits 12.. 8 - strobe length -- bits 17..13 - strobe delay -- reading data state_machine & config -- "000" when waiting -- "001" when shd, -- "010" when shc, -- "011" when str, -- "100" when str1, -- MSB is busy -- in the C-program: -- somewhere in main -- -- PASA(ADC_Mask, PASA_DAC, 0, PASA_STR_LEN, PASA_STR_DEL); -- -- int PASA(int ADC_Mask, int DAC, int CNF, int STR_LEN, int STR_DEL) -- { -- unsigned int data; -- -- data = (CNF & 0x1F) | ( (STR_LEN & 0x1F) << 8 ) | ( (STR_DEL & 0x1F) << 13 ); -- put_pci(0x81, data); // write the configuration and params -- data = ( (DAC & 0xFF) << 19) | (ADC_Mask & 0x7FFFF); -- put_pci(0x80, data); // write amplitude and mask -- printf("*** PASA set : ADC Mask 0x%05x, DAC 0x%02x\n", ADC_Mask, DAC); -- return 0; -- } entity par2ser_pci is GENERIC ( WIDTH : Integer := 27 -- Width of the data in/out ); PORT ( CE : IN STD_LOGIC; -- Chip enable A0 : IN STD_LOGIC; -- bit 0 of the address WE : IN STD_LOGIC; -- Write enable D : IN STD_LOGIC_VECTOR(WIDTH-1 downto 0); -- Data input bus CLK : IN STD_LOGIC; -- Clock, can be pci clock RESET_n : IN STD_LOGIC; -- reset PQ : OUT STD_LOGIC_VECTOR(WIDTH-1 downto 0); -- Parallel outputs SCLK : OUT STD_LOGIC; -- Serial Clock (1/8 of CLK) SDAT : OUT STD_LOGIC; -- Serial Data SSTR : OUT STD_LOGIC -- Serial Strobe ); end par2ser_pci; architecture a of par2ser_pci is SIGNAL CNT_FF : Integer range 0 to WIDTH; -- counter for the number of bits to be shifted out SIGNAL SL : STD_LOGIC; signal str_len : std_logic_vector(4 downto 0); signal cnt_str : std_logic_vector(4 downto 0); signal str_del : std_logic_vector(4 downto 0); signal cnt_del : std_logic_vector(4 downto 0); -- DFF_S is the shift register SIGNAL DFF_S, sdata_out : STD_LOGIC_VECTOR(WIDTH-1 downto 0); -- clock enable for the input register SIGNAL EN : STD_LOGIC; SIGNAL EN_shr : STD_LOGIC; TYPE sm IS (waiting, shd, shc, str, str1); -- state machine SIGNAL SERREG : sm; SIGNAL sm_o : STD_LOGIC_VECTOR(2 downto 0); SIGNAL CNF : STD_LOGIC_VECTOR(4 downto 0); SIGNAL cnt_div : STD_LOGIC_VECTOR(1 downto 0); signal clk_slow : std_logic; begin -- IO write process(CLK, RESET_n) begin if RESET_n = '0' then CNF <= (others => '0'); str_len <= (others => '1'); str_del <= (others => '1'); EN <= '0'; sdata_out <= (others => '0'); elsif CLK'event and CLK='1' then if (CE and WE and not A0)='1' then EN <= '1'; elsif SERREG /= waiting then EN <= '0'; end if; if (CE and WE and A0)='1' then CNF <= D(CNF'range); str_len <= D(str_len'high + CNF'length + sm_o'length downto CNF'length + sm_o'length); str_del <= D(str_del'high + str_len'length + CNF'length + sm_o'length downto str_len'length + CNF'length + sm_o'length); end if; if (CE and WE and not A0)='1' then sdata_out <= D(sdata_out'range); end if; end if; end process; -- IO read process(A0, SL, str_del, str_len, sm_o, CNF, DFF_S) begin PQ <= (others => '0'); if A0='0' then PQ(DFF_S'range) <= DFF_S; else PQ(PQ'high) <= SL; PQ(str_del'length + str_len'length + sm_o'length + CNF'length - 1 downto 0) <= str_del & str_len & sm_o & CNF; end if; end process; process(clk) begin if clk'event and clk='1' then cnt_div <= cnt_div + 1; end if; end process; clk_slow <= cnt_div(cnt_div'high); process(clk_slow) -- shift register begin if clk_slow'event and clk_slow='1' then EN_shr <= EN; if EN_shr = '1' or SERREG=shd then if SERREG=shd then if CNF(2)='0' then -- MSB first DFF_S <= DFF_S(WIDTH-2 downto 0) & DFF_S(WIDTH-1); else -- LSB first DFF_S <= DFF_S(0) & DFF_S(WIDTH-1 downto 1); end if; else DFF_S <= sdata_out; end if; end if; end if; end process; process(clk_slow, RESET_n) -- start of the state machine begin if RESET_n = '0' then SL <= '0'; elsif clk_slow'event and clk_slow='1' then if EN = '1' then SL <= '1'; elsif SERREG=str1 then SL <= '0'; end if; end if; end process; process(clk_slow, RESET_n) -- counter for the number of shifts begin if RESET_n = '0' then CNT_FF <= WIDTH; elsif clk_slow'event and clk_slow='1' then case SERREG is when waiting => CNT_FF <= WIDTH; -- sync load when shc => CNT_FF <= CNT_FF - 1; -- decr when others => NULL; end case; end if; end process; process(clk_slow, RESET_n) -- counter for the strobe length begin if RESET_n = '0' then cnt_str <= (others => '1'); elsif clk_slow'event and clk_slow='1' then if SERREG=str1 then cnt_str <= cnt_str - 1; -- decr else cnt_str <= str_len; -- sync load end if; end if; end process; process(clk_slow, RESET_n) -- counter for the strobe delay begin if RESET_n = '0' then cnt_del <= (others => '1'); elsif clk_slow'event and clk_slow='1' then if SERREG=str then cnt_del <= cnt_del - 1; -- decr else cnt_del <= str_del; -- sync load end if; end if; end process; process(clk_slow, RESET_n) -- state machine begin if RESET_n = '0' then SERREG <= waiting; SSTR <= '0'; elsif clk_slow'event and clk_slow='1' then SSTR <= '0'; CASE SERREG IS WHEN waiting => if SL='1' then SERREG <= shc; end if; WHEN shc => SERREG <= shd; WHEN shd => if (CNT_FF = 0) then SERREG <= str; else SERREG <= shc; end if; WHEN str => if cnt_del = 0 then SERREG <= str1; SSTR <= not CNF(0); end if; WHEN str1 => SSTR <= not CNF(0); if cnt_str = 0 then SERREG <= waiting; end if; WHEN others => SERREG <= waiting; end case; end if; end process; with SERREG select sm_o <= "000" when waiting, "001" when shd, "010" when shc, "011" when str, "100" when str1, "111" when others; process(clk_slow, RESET_n) begin if RESET_n = '0' then SCLK <= '0'; elsif CLK_slow'event and CLK_slow='1' then case SERREG is when shc => SCLK <= '1'; when str => SCLK <= CNF(1); when str1 => SCLK <= '0'; when others => SCLK <= '0'; end case; end if; end process; SDAT <= DFF_S(WIDTH-1) when CNF(2)='0' else DFF_S(0); -- serial data output end;