-- -- Produce a clock signal for the A0 system A square wave and sine wave are output -- with a variable phase relatonship. -- The sine wave is a poor sine wave comprising only 16 samples per cycle -- or 5 digitisisation values. However after fltering by the membrane mirror -- and possibly a simple rc filter this should provide an adequate sine wave. -- A square wave (zeros) tracks the zero crossing of the sine wave and -- a second square wave (strobe) is offset by a known phase from the sin wave. -- The operation frequency is set by a 13 bit number (divide) which specifies the -- number of clocks that should comprise each 1/16 sin output. -- The phase is set by a second number (phase), 16 bits long, which specifies the -- phase offset of the (strobe) transition in cycles from the start of each -- (zeros) transition. Note that the number represinting any given phase offset -- is proportional to the frequency divider number (divide), so will have to -- be changed each time the frequency is updated. -- Note that the true sine wave and the (zeros) and (stobe) output are offser -- by 1/32 od a period, which should be accounted for by adjusting the phase -- apropriately. -- -- The 5 levels of sin output can also be programmed externally. This allows for -- the output levels to be changed, or even the generation of a different waveform. -- -- On power up the device shoud be reset by holding the reset pin high and simultaniously -- strobing the data_strobe line -- library ieee; use ieee.std_logic_1164.all; use work.numeric_std.all; -- -- Generates an arbitrary programmable waveform with an offsettavle -- phase signal. This code assumes that the DAC is set up in transparent -- mode so that changes to the DAC output will propagate immediately -- if we need to write data directly to the DAC then the output from the -- sinphase generator mus be momentatily disabled. -- entity sinphase is port(clk: in std_logic; reset: in std_logic; phase1: in unsigned(12 downto 0); phase2: in unsigned(12 downto 0); steplen: in unsigned(9 downto 0); val0: in std_logic_vector(7 downto 0); val1: in std_logic_vector(7 downto 0); val2: in std_logic_vector(7 downto 0); val3: in std_logic_vector(7 downto 0); val4: in std_logic_vector(7 downto 0); val5: in std_logic_vector(7 downto 0); val6: in std_logic_vector(7 downto 0); val7: in std_logic_vector(7 downto 0); predev: in unsigned(3 downto 0); sinphase_zeros:out std_logic; dac_req: out std_logic; dac_ack:in std_logic; dac: buffer std_logic_vector(7 downto 0) ); end sinphase; architecture arch_sinphase of sinphase is type kdac_type is (kd_idle,kd_ack,kd_guard); signal kdac : kdac_type; signal current_phase: unsigned(12 downto 0); signal sample: unsigned(2 downto 0); signal current_count: unsigned(9 downto 0); signal kick_dac : std_logic; signal iclk : std_logic; signal precount : unsigned(3 downto 0); begin -- -- run the various counters. -- with sample select dac(7 downto 0) <= val0 when "000", val1 when "001", val2 when "010", val3 when "011", val4 when "100", val5 when "101", val6 when "110", val7 when "111", val0 when others; -- purpose: predivide the clock for the sinphase doober -- type : sequential -- inputs : clk, reset -- outputs: pre: process (clk, reset, precount) begin -- process pre if reset = '1' then -- asynchronous reset (active low) elsif clk'event and clk = '1' then -- rising clock edge if (precount = predev) then iclk <= not iclk; precount <= (others => '0'); else precount <= precount+1; end if; end if; end process pre; count: process(iclk,reset, steplen, phase1, phase2 ) begin if (rising_edge(iclk)) then kick_dac <= '0'; if (current_count = steplen) then current_count <= (others => '0'); kick_dac <= '1'; if (sample = "111") then -- -- this means we are at the end of the sequence -- sample <= (others => '0'); current_phase <= (others => '0'); else sample <= sample+1; current_phase <= current_phase +1; end if; else if current_phase = phase1 then sinphase_zeros <= '1'; else if (current_phase = phase2) then sinphase_zeros <= '0'; end if; end if; current_phase <= current_phase +1; current_count <= current_count +1; end if; end if; end process count; dacit: process (clk, reset) begin -- process if reset = '1' then -- asynchronous reset (active low) elsif clk'event and clk = '1' then -- rising clock edge dac_req <= '0'; case (kdac) is when kd_idle => if (kick_dac = '1') then dac_req <= '1'; kdac <= kd_ack; end if; when kd_ack => -- Dont bother to check for lowering of ack if (dac_ack = '1') then dac_req <= '0'; kdac <= kd_guard; else dac_req <= '1'; end if; when kd_guard => -- Dont return to idle untill the current request goes away. if (kick_dac = '0') then kdac <= kd_idle; end if; when others => kdac <= kd_idle; end case; end if; end process dacit; end arch_sinphase; library ieee; use ieee.std_logic_1164.all; use work.numeric_std.all; entity write_to_dac is port ( clk : in std_logic; reset : in std_logic; sp_req : in std_logic; sp_ack : out std_logic; pc_req : in std_logic; pc_ack : out std_logic; sp_data : in std_logic_vector(7 downto 0); sp_addr : in std_logic_vector(2 downto 0); pc_data : in std_logic_vector(12 downto 0); pc_addr : in std_logic_vector(3 downto 0); dac_addr : out std_logic_vector(2 downto 0); dac_data : out std_logic_vector(12 downto 0); n_dac_wr : out std_logic; n_dac_clr : out std_logic; n_dac_cs : out std_logic; n_dac_ldab : out std_logic; n_dac_ldcd : out std_logic; n_dac_ldef : out std_logic; n_dac_ldgh : out std_logic; shift : in unsigned(2 downto 0)); end write_to_dac; architecture write_to_dac_arch of write_to_dac is type dac_type is (idle,pc_ack_st,sp_ack_st,sp_shift,write_dac); signal dac_state : dac_type; signal timeout : unsigned(2 downto 0); -- Have to keep a separate copy of this otherwise we end up reading the address lines -- as inputs, which has the undesirable side-effect of removing the drive! signal dac_addr_copy: std_logic_vector(2 downto 0); signal dac_hold : std_logic_vector(12 downto 0); begin -- write_to_dac_arch n_dac_ldab <= '0' when (dac_addr_copy(2 downto 1) = "00") else '1'; n_dac_ldcd <= '0' when (dac_addr_copy(2 downto 1) = "01") else '1'; n_dac_ldef <= '0' when (dac_addr_copy(2 downto 1) = "10") else '1'; n_dac_ldgh <= '0' when (dac_addr_copy(2 downto 1) = "11") else '1'; dac_addr <= dac_addr_copy; -- purpose: clock data to the dac. -- type : sequential -- inputs : clk, reset -- outputs: dacwr: process (clk, reset) begin -- process dacwr if reset = '1' then -- asynchronous reset n_dac_clr <= '0'; n_dac_cs <= '0'; elsif clk'event and clk = '1' then -- rising clock edge n_dac_wr <= '1'; n_dac_clr <= '1'; n_dac_cs <= '0'; sp_ack <= '0'; pc_ack <= '0'; case (dac_state) is when idle => timeout <= (others => '0'); -- -- PC takes presidence because sinphase may be requesting transferrs -- continuously until we get some rigeisters loaded -- if (pc_req = '1') then dac_addr_copy <= pc_addr(2 downto 0); dac_hold <= pc_data; pc_ack <= '1'; dac_state <= pc_ack_st; else if (sp_req = '1') then dac_addr_copy <= sp_addr; dac_hold(7 downto 0) <= sp_data; dac_hold(12 downto 8) <= (others => '0'); sp_ack <= '1'; dac_state <= sp_shift; end if; end if; when sp_shift => -- -- shift the data as indicated by the value of the shift register -- allows us to use the full dynamic range of the DAC while still -- using only 8 bit registers for the waveform values. -- if (timeout = shift) then timeout <= (others => '0'); dac_state <= sp_ack_st; -- -- Following clause sets the MSB to 1 for all shifts less than -- 5 (i'm assuming that software disallows shofts > 5). This -- keeps the signal closer to zero mean without doing fancy -- arithmetic. Still need AC coupling to eliminate dc bas though. -- if (shift = "101") then else dac_hold(12) <= '1'; end if; else timeout <= timeout+1; for i in 11 downto 0 loop dac_hold(i+1) <= dac_hold(i); end loop; -- i dac_hold(0) <= '0'; end if; when sp_ack_st => sp_ack <= '1'; if (sp_req = '0') then dac_state <= write_dac; end if; when pc_ack_st => dac_data <= dac_hold; pc_ack <= '1'; if (pc_req = '0') then dac_state <= write_dac; end if; when write_dac => dac_data <= dac_hold; n_dac_wr <= '0'; if (timeout = "0100") then dac_state <= idle; else timeout <= timeout+1; end if; when others => dac_state <= idle; end case; end if; end process dacwr; end write_to_dac_arch; library ieee; use ieee.std_logic_1164.all; use work.numeric_std.all; entity read_from_ibus is port ( clk : in std_logic; reset : in std_logic; il_req : in std_logic; il_ack : out std_logic; il_io : in std_logic_vector(15 downto 0); data : buffer std_logic_vector(15 downto 0); address:buffer std_logic_vector(3 downto 0); req : out std_logic; ack : in std_logic; i_am_remote:in std_logic; my_data_address:in std_logic_vector(3 downto 0); my_ctrl_address:in std_logic_vector(3 downto 0); --request_reset:out std_logic; il_i_am_addressed: buffer std_logic; phase1 : out unsigned(12 downto 0); -- Phase to switch sinphase_ -- strobe from 0 to 1 phase2 : out unsigned(12 downto 0); -- Phase to switch sinphase -- strobe from 1 to 0 steplen : out unsigned(9 downto 0); val0 : out std_logic_vector(7 downto 0); val1 : out std_logic_vector(7 downto 0); val2 : out std_logic_vector(7 downto 0); val3 : out std_logic_vector(7 downto 0); val4 : out std_logic_vector(7 downto 0); val5 : out std_logic_vector(7 downto 0); val6 : out std_logic_vector(7 downto 0); val7 : out std_logic_vector(7 downto 0); divider: out unsigned(3 downto 0); shift: out unsigned(2 downto 0); digital_out: out std_logic_vector(7 downto 0) ); end read_from_ibus; architecture read_from_ibus_arch of read_from_ibus is type il_read_type is (idle,am_i_addressed,il_hs_for_address,il_hs_for_data, il_use_ctrl_data,internal_ack1 -- ,internal_ack2 ); signal il_read_state : il_read_type; signal this_is_a_ctrl_transaction : std_logic; begin -- read_from_ibus_arch -- purpose: read from the on-board bus -- type : sequential -- inputs : clk, reset -- outputs: read_ibus: process (clk, reset) begin -- process read_ibus if reset = '1' then -- asynchronous reset (active low) il_i_am_addressed <= '0'; this_is_a_ctrl_transaction <= '0'; elsif clk'event and clk = '1' then -- rising clock edge il_ack <= '0'; req <= '0'; --request_reset <= '0'; case (il_read_state) is when idle => if (il_req = '1') then data <= il_io; il_read_state <= am_i_addressed; end if; when am_i_addressed => il_read_state <= idle; if (data(15) = '1') then -- this is an address il_i_am_addressed <= '0'; -- any addtress transaction should -- reset select bits on all chips this_is_a_ctrl_transaction <= '0'; --Dont need to stuff this because this chip is never present on local end -- when there is a possibility of forwarding data over the fiber. --if (data(12) = i_am_remote) then if (data(11 downto 8) = my_ctrl_address) then this_is_a_ctrl_transaction <= '1'; il_i_am_addressed <= '1'; address <= data(3 downto 0); il_read_state <= il_hs_for_address; end if; if (data(11 downto 8) = my_data_address) then il_i_am_addressed <= '1'; address <= data(3 downto 0); il_read_state <= il_hs_for_address; end if; --end if; else -- -- This is not an address, but if this chip is already addressed -- then this will be a data transaction to complete the previous -- address transaction -- if (il_i_am_addressed = '1') then il_read_state <= il_hs_for_data; else il_read_state <= idle; end if; end if; when il_hs_for_address => il_ack <= '1'; if (il_req = '0') then -- -- Only do an ack cycle if we are in loopback mode -- il_read_state <= idle; end if; when il_hs_for_data => il_ack <= '1'; if (il_req = '0') then -- -- things to do once the external transaction has completed -- if (this_is_a_ctrl_transaction = '1') then il_read_state <= il_use_ctrl_data; else -- Just send the data to the dac output il_read_state <= internal_ack1; end if; end if; when il_use_ctrl_data => -- -- What we do with the control data is completely dependent on the -- chip all of the rest of this code should be fairly generic, if -- a littl over elaborate in most cases -- il_read_state <= idle; case address(3 downto 0) is when "0001" => for i in 12 downto 0 loop phase1(i) <= data(i); end loop; when "0010" => for i in 12 downto 0 loop phase2(i) <= data(i); end loop; when "0011" => for i in 9 downto 0 loop steplen(i) <= data(i); end loop; -- i when "0100" => val0 <= data(7 downto 0); when "0101" => val1 <= data(7 downto 0); when "0110" => val2 <= data(7 downto 0); when "0111" => val3 <= data(7 downto 0); when "1000" => val4 <= data(7 downto 0); when "1001" => val5 <= data(7 downto 0); when "1010" => val6 <= data(7 downto 0); when "1011" => val7 <= data(7 downto 0); when "1100" => for i in 3 downto 0 loop divider(i) <= data(i); end loop; -- i when "1101" => for i in 2 downto 0 loop shift(i) <= data(i); end loop; -- i when "1110" => --Hmm enabling this makes us run out of resources. --digital_out(3 downto 0) <= data(3 downto 0); --digital_out <= data(7 downto 0); when others => null; end case; when internal_ack1 => req <= '1'; if (ack = '1') then il_read_state <= idle; end if; when others => il_read_state <= idle; end case; end if; end process read_ibus; end read_from_ibus_arch; library ieee; use ieee.std_logic_1164.all; use work.numeric_std.all; entity tout is port (led1 : out std_logic; clk : in std_logic; id: in std_logic_vector(15 downto 0); -- -- global -- reset: in std_logic; -- -- meanings of these signals are reversed since they are named in the -- master CPLD -- sinphase_bus_request: buffer std_logic; sinphase_bus_grant: in std_logic; sinphase_strobe: in std_logic; -- Switch counter channels sinphase_zeros: out std_logic; -- Mark zero trnsitions (phase shifted sinphase_mids: in std_logic; -- Mark mid-point transisitons. external_zeros: in std_logic; -- External phase transitions. AO_FROM_PC_STROBE:in std_logic; AO_FROM_PC_ACK:out std_logic; DIO_TO_FIBER_READ_REQ:in std_logic; AO_TO_PC_STROBE:in std_logic; AO_TO_PC_ACK:in std_logic; SOFT_RESET:in std_logic; -- -- DA control -- shdn: buffer std_logic_vector(2 downto 0); da_not_clr: out std_logic; da_not_wr: out std_logic; da_not_cs: out std_logic; da_not_ldab: out std_logic; da_not_ldcd: out std_logic; da_not_ldef: out std_logic; da_not_ldgh: out std_logic; dad: out std_logic_vector(12 downto 0); daaddr: out std_logic_vector(2 downto 0); dio: out std_logic_vector(7 downto 0); dio_dir: buffer std_logic; dio_tristate: buffer std_logic ); end tout; -- purpose: Collect together preceeding modules architecture tout_arch of tout is signal write_oe : std_logic; signal read_oe : std_logic; signal ibus_read_frame_flag: std_logic; signal in_strobe_int : std_logic; signal in_is_frame_int : std_logic; signal phase1: unsigned(12 downto 0); -- Phase to switch sinphase_ -- strobe from 0 to 1 signal phase2 : unsigned(12 downto 0); -- Phase to switch sinphase -- strobe from 1 to 0 signal steplen : unsigned(9 downto 0); signal val0 : std_logic_vector(7 downto 0); signal val1 : std_logic_vector(7 downto 0); signal val2 : std_logic_vector(7 downto 0); signal val3 : std_logic_vector(7 downto 0); signal val4 : std_logic_vector(7 downto 0); signal val5 : std_logic_vector(7 downto 0); signal val6 : std_logic_vector(7 downto 0); signal val7 : std_logic_vector(7 downto 0); signal shift : unsigned(2 downto 0); signal predev : unsigned(3 downto 0); signal sinphase_dac: std_logic(7 downto 0); signal to_dac_from_pc_req : std_logic; signal to_dac_from_pc_ack : std_logic; signal to_dac_from_sp_req : std_logic; signal to_dac_from_sp_ack : std_logic; signal dac_data_from_pc : std_logic_vector(15 downto 0); signal dac_from_sp : std_logic_vector(7 downto 0); signal il_ack: std_logic; signal this_chip_selected : std_logic; -- signal request_reset : std_logic; signal sp_req: std_logic; signal sp_ack: std_logic; signal address_from_pc : std_logic_vector(3 downto 0); begin -- shdn(0) <= '0'; -- shdn(1) <= '0'; -- shdn(2) <= '0'; shdn(0) <= '1'; shdn(1) <= '1'; shdn(2) <= '1'; dio_tristate <= '1'; dacwr : write_to_dac port map ( clk => clk, reset => reset, sp_req => sp_req, sp_ack => sp_ack, pc_req => to_dac_from_pc_req, pc_ack => to_dac_from_pc_ack, sp_data => dac_from_sp, sp_addr => "000", pc_data => dac_data_from_pc(12 downto 0), pc_addr => address_from_pc, dac_addr => daaddr, dac_data => dad, n_dac_wr => da_not_wr, n_dac_cs => da_not_cs, n_dac_clr => da_not_clr, n_dac_ldab => da_not_ldab, n_dac_ldcd => da_not_ldcd, n_dac_ldef => da_not_ldef, n_dac_ldgh => da_not_ldgh, shift => shift); -- purpose: Takes care of tristating the internal lower bus ack line which is -- multi-driven by several chips. This is a clocked process because we wish to -- make sure that the ack signal is set to zero before the output is tristated. -- In this way the output holding latch always holds the line low in the AO_FROM_PC_ACK <= il_ack when (this_chip_selected = '1') else 'Z'; rio: read_from_ibus port map ( clk => clk, reset => reset, il_req => AO_FROM_PC_STROBE, il_ack => il_ack, il_io => id, data => dac_data_from_pc, address => address_from_pc, req => to_dac_from_pc_req, ack => to_dac_from_pc_ack, i_am_remote => '1', my_ctrl_address => "0101", my_data_address => "0100", -- request_reset => request_reset, il_i_am_addressed => this_chip_selected, phase1 => phase1, phase2 => phase2, steplen => steplen, val0 => val0, val1 => val1, val2 => val2, val3 => val3, val4 => val4, val5 => val5, val6 => val6, val7 => val7, divider => predev, shift => shift, digital_out => dio ); spg : sinphase port map ( clk => clk, reset => reset, phase1 => phase1, phase2 => phase2, steplen => steplen, val0 => val0, val1 => val1, val2 => val2, val3 => val3, val4 => val4, val5 => val5, val6 => val6, val7 => val7, predev => predev, sinphase_zeros => sinphase_zeros, dac_req => sp_req, dac_ack => sp_ack, dac => dac_from_sp); end tout_arch;