added files
This commit is contained in:
parent
ef36daccae
commit
4a3b0bfedf
|
@ -0,0 +1,5 @@
|
|||
|
||||
*.ini
|
||||
*.wlf
|
||||
work
|
||||
transcript
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,582 @@
|
|||
---------------------------------------------------------------
|
||||
-- File : qlaser_dacs_pulse_channel.vhd
|
||||
-- Description : Single channel of pulse output
|
||||
----------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
use work.qlaser_pkg.all;
|
||||
|
||||
entity qlaser_dacs_pulse_channel is
|
||||
port (
|
||||
reset : in std_logic;
|
||||
clk : in std_logic;
|
||||
|
||||
enable : in std_logic; -- Set when DAC interface is running
|
||||
start : in std_logic; -- Set when pulse generation sequence begins (trigger)
|
||||
cnt_time : in std_logic_vector(23 downto 0); -- Time since trigger.
|
||||
|
||||
busy : out std_logic; -- Status signal
|
||||
|
||||
-- CPU interface
|
||||
cpu_addr : in std_logic_vector( 9 downto 0); -- Address input
|
||||
cpu_wdata : in std_logic_vector(31 downto 0); -- Data input
|
||||
cpu_wr : in std_logic; -- Write enable
|
||||
cpu_sel : in std_logic; -- Block select
|
||||
cpu_rdata : out std_logic_vector(31 downto 0); -- Data output
|
||||
cpu_rdata_dv : out std_logic; -- Acknowledge output
|
||||
|
||||
-- AXI-stream output
|
||||
axis_tready : in std_logic; -- axi_stream ready from downstream module
|
||||
axis_tdata : out std_logic_vector(15 downto 0); -- axi stream output data
|
||||
axis_tvalid : out std_logic; -- axi_stream output data valid
|
||||
axis_tlast : out std_logic -- axi_stream output set on last data
|
||||
);
|
||||
end entity;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Single channel pulse generator with two RAMs and a FIFO
|
||||
----------------------------------------------------------------
|
||||
architecture rtl of qlaser_dacs_pulse_channel is
|
||||
|
||||
-- RAM, pulse position, CPU port, read/write
|
||||
constant C_NUM_PULSE : integer := 16; -- Number of output data values from pulse RAM (16x24-bit)
|
||||
signal ram_pulse_addra : std_logic_vector( 3 downto 0); -- 16 entry RAM
|
||||
signal ram_pulse_dina : std_logic_vector(95 downto 0);
|
||||
signal ram_pulse_douta : std_logic_vector(95 downto 0);
|
||||
signal ram_pulse_douta_d1 : std_logic_vector(95 downto 0); -- Delay distrib RAM output to match pipeline of Block RAM
|
||||
signal ram_pulse_we : std_logic;
|
||||
|
||||
-- RAM, pulse position, from state machine
|
||||
constant C_BITS_GAIN_FACTOR : integer := 16; -- Number of bits in gain table
|
||||
constant C_BITS_TIME_FACTOR : integer := 16; -- Number of bits in time table
|
||||
constant C_BITS_TIME_INT : integer := 14; -- Starting bit for time integer part of the time factor, counting from MSB
|
||||
constant C_BITS_TIME_FRAC : integer := 5; -- Starting bit for time fractional part of the time factor, counting from MSB
|
||||
constant C_BITS_ADDR_START : integer := 10; -- Number of bits for starting address
|
||||
constant C_BITS_ADDR_LENGTH : integer := 10; -- Number of bits for length address used by an edge of a pulse
|
||||
constant C_BITS_ADDR_TOP : integer := 17; -- Number of bits for the "flat top", the top of the pulse
|
||||
signal cnt_wave_top : std_logic_vector( C_BITS_ADDR_TOP - 1 downto 0); -- Counter for the top of the waveform
|
||||
signal ram_pulse_addrb : std_logic_vector( 3 downto 0);
|
||||
signal ram_pulse_doutb : std_logic_vector(95 downto 0);
|
||||
|
||||
signal cpu_rdata_dv_e1 : std_logic;
|
||||
signal cpu_rdata_dv_e2 : std_logic;
|
||||
signal cpu_rdata_ramsel_d1 : std_logic;
|
||||
signal cpu_rdata_ramsel_d2 : std_logic;
|
||||
|
||||
signal cpu_wdata_top : std_logic_vector(31 downto 0); -- Top 32 bits of CPU write data (95:64)
|
||||
signal cpu_wdata_mid : std_logic_vector(31 downto 0); -- Middle 32 bits of CPU write data (63:32)
|
||||
|
||||
-- Waveform RAM port connections.
|
||||
-- NOTE: Port A is 32-bit data, port B is 16-bit
|
||||
constant C_LENGTH_WAVEFORM : integer := 1024; -- Number of output data values from waveform RAM (1024x16-bit)
|
||||
constant C_BITS_ADDR_WAVE : integer := 10; -- Number of bits in address for waveform RAM
|
||||
signal ram_waveform_ena : std_logic;
|
||||
signal ram_waveform_wea : std_logic_vector( 0 downto 0);
|
||||
signal ram_waveform_addra : std_logic_vector( 8 downto 0);
|
||||
signal ram_waveform_dina : std_logic_vector(31 downto 0);
|
||||
signal ram_waveform_douta : std_logic_vector(31 downto 0);
|
||||
|
||||
signal ram_waveform_enb : std_logic := '0';
|
||||
signal ram_waveform_web : std_logic_vector( 0 downto 0) := (others=>'0');
|
||||
signal ram_waveform_addrb : std_logic_vector( 9 downto 0);
|
||||
signal ram_waveform_dinb : std_logic_vector(15 downto 0) := (others=>'0');
|
||||
signal ram_waveform_doutb : std_logic_vector(15 downto 0);
|
||||
|
||||
|
||||
-- State variable type declaration for main state machine
|
||||
type t_sm_state is (
|
||||
S_RESET, -- Wait for 'enable'. Stay here until JESD interface is up and running,
|
||||
S_IDLE, -- Wait for 'start'
|
||||
S_WAIT, -- Wait for cnt_time, external input, to match pulse position RAM output
|
||||
S_WAVE_UP, -- Output the rising edge of a waveform
|
||||
S_WAVE_FLAT,-- Output the flat top part of a waveform
|
||||
S_WAVE_DOWN -- Output the falling edge of a waveform
|
||||
);
|
||||
signal sm_state : t_sm_state;
|
||||
signal sm_wavedata : std_logic_vector(15 downto 0); -- Waveform RAM data
|
||||
signal sm_wavedata_dv : std_logic; -- Signal to indicate that waveform RAM data is valid
|
||||
signal sm_busy : std_logic; -- Signal to indicate that s.m. is not idle
|
||||
|
||||
|
||||
---- FIFO port connections
|
||||
--signal fifo_wr_en : std_logic;
|
||||
--signal fifo_full : std_logic;
|
||||
--signal fifo_empty : std_logic;
|
||||
--signal fifo_wr_rst_busy : std_logic;
|
||||
--signal fifo_rd_rst_busy : std_logic;
|
||||
--signal fifo_rd_en : std_logic;
|
||||
---- FIFO status signals for debug purpose
|
||||
--signal fifo_wr_ack : std_logic;
|
||||
--signal fifo_overflow : std_logic;
|
||||
--signal fifo_valid : std_logic;
|
||||
--signal fifo_underflow : std_logic;
|
||||
|
||||
-- Pipeline delays
|
||||
signal start_d1 : std_logic;
|
||||
signal enable_d1 : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
busy <= sm_busy;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Distributed RAM to hold 16 24-bit Pulse start times.
|
||||
-- Synch write, Asynch read
|
||||
-- Port A is for CPU read/write. 16x24-bit
|
||||
-- Port B is for pulse time data output. 16x24-bit
|
||||
----------------------------------------------------------------
|
||||
u_ram_pulse : entity work.bram_pulseposition
|
||||
port map(
|
||||
clk => clk , -- input std_logic
|
||||
a => ram_pulse_addra , -- input slv[3:0]
|
||||
d => ram_pulse_dina , -- input slv[95 downto 0]
|
||||
we => ram_pulse_we ,
|
||||
spo => ram_pulse_douta , -- output slv(95 downto 0]
|
||||
|
||||
dpra => ram_pulse_addrb , -- input slv[3:0]
|
||||
dpo => ram_pulse_doutb -- output slv(95 downto 0)
|
||||
);
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Waveform table Block RAM.
|
||||
-- Synch write, Synch read
|
||||
-- Port A is for CPU read/write. 512x32-bit
|
||||
-- Port B is for waveform data. 1024x16-bit
|
||||
----------------------------------------------------------------
|
||||
u_ram_waveform : entity work.bram_waveform
|
||||
port map (
|
||||
-- Port A CPU Bus
|
||||
clka => clk , -- input std_logic
|
||||
ena => ram_waveform_ena , -- input std_logic
|
||||
wea => ram_waveform_wea , -- input slv(0 downto 0)
|
||||
addra => ram_waveform_addra , -- input slv(8 downto 0)
|
||||
dina => ram_waveform_dina , -- input slv(31 downto 0)
|
||||
douta => ram_waveform_douta , -- output slv(31 downto 0)
|
||||
|
||||
-- Port B waveform output
|
||||
clkb => clk , -- input std_logic
|
||||
enb => ram_waveform_enb , -- input std_logic
|
||||
web => (others=>'0') , -- input slv(0 downto 0)
|
||||
addrb => ram_waveform_addrb , -- input slv(9 downto 0)
|
||||
dinb => (others=>'0') , -- input slv(15 downto 0)
|
||||
doutb => ram_waveform_doutb -- output slv(15 downto 0)
|
||||
);
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- State machine:
|
||||
-- Compares cnt_time input against current output from pulse position RAM.
|
||||
-- When values match iti incremnts the pulse postion RAM address to
|
||||
-- retrieve the next pulse position and also starts reading the
|
||||
-- entire waveform table, one value every clock cycle, until it reaches the end.
|
||||
-- Once the pulse is complete it waits for the next cnt_time match.
|
||||
-- Repeat until all pulse position RAM times have triggered a pulse output
|
||||
-- or until the maximum counter time has been reached.
|
||||
----------------------------------------------------------------
|
||||
pr_sm : process (reset, clk)
|
||||
-- TODO: those bitwidth are not correct, we could optimize it later and find out how many bits each variable should be. But for now just make it big
|
||||
variable v_ram_waveform_addrb : unsigned(95 downto 0);
|
||||
begin
|
||||
if (reset = '1') then
|
||||
|
||||
sm_state <= S_IDLE; -- TODO: Eric: Should this be S_RESET since we reset the JEDS interface as well?
|
||||
ram_pulse_addrb <= (others=>'0');
|
||||
ram_waveform_addrb <= (others=>'0');
|
||||
|
||||
sm_wavedata <= (others=>'0');
|
||||
sm_wavedata_dv <= '0';
|
||||
sm_busy <= '0';
|
||||
ram_waveform_enb <= '0';
|
||||
|
||||
elsif rising_edge(clk) then
|
||||
|
||||
-- Pipeline delays to use for rising edge detection
|
||||
enable_d1 <= enable;
|
||||
start_d1 <= start;
|
||||
|
||||
-- Default
|
||||
sm_wavedata <= (others=>'0');
|
||||
sm_wavedata_dv <= '0';
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Main state machine
|
||||
------------------------------------------------------------------------
|
||||
case sm_state is
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Wait for rising edge of enable
|
||||
-- This is set when the JESD interface is aligned and functional.
|
||||
-- Send a zero value to initialize the DAC then go to idle.
|
||||
------------------------------------------------------------------------
|
||||
when S_RESET =>
|
||||
|
||||
if (enable = '1') and (enable_d1 = '0') then
|
||||
sm_wavedata <= (others=>'0');
|
||||
sm_wavedata_dv <= '1';
|
||||
sm_state <= S_IDLE;
|
||||
end if;
|
||||
sm_busy <= '0';
|
||||
ram_waveform_enb <= '0';
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Wait for rising edge of 'start'.
|
||||
-- No data output.
|
||||
------------------------------------------------------------------------
|
||||
when S_IDLE =>
|
||||
|
||||
if (start = '1') and (start_d1 = '0') then
|
||||
sm_state <= S_WAIT;
|
||||
sm_busy <= '1';
|
||||
else
|
||||
sm_busy <= '0';
|
||||
end if;
|
||||
|
||||
ram_waveform_enb <= '0';
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Wait for cnt_time, external input, to match pulse position RAM output
|
||||
-- Return to idle state if max time is reached. Output waveform value zero.
|
||||
------------------------------------------------------------------------
|
||||
when S_WAIT =>
|
||||
|
||||
-- Start to output wave and increment pulse position RAM address
|
||||
if (ram_pulse_doutb(93 downto C_BITS_TIME_FACTOR) = cnt_time) then
|
||||
sm_state <= S_WAVE_UP;
|
||||
-- set the wavetable's address to the starting address defined from the pulse ram
|
||||
ram_waveform_addrb <= ram_pulse_doutb(C_BITS_GAIN_FACTOR - 1 downto C_BITS_ADDR_START);
|
||||
elsif (cnt_time = X"FFFFFF") then
|
||||
sm_state <= S_IDLE;
|
||||
end if;
|
||||
|
||||
ram_waveform_enb <= '1';
|
||||
------------------------------------------------------------------------
|
||||
-- Output the raising edge of a waveform
|
||||
-- Hold the last address when complete
|
||||
------------------------------------------------------------------------
|
||||
when S_WAVE_UP =>
|
||||
-- Check if is end of rise of the waveform, and hold the address
|
||||
if (ram_waveform_addrb = std_logic_vector(unsigned(ram_pulse_doutb(C_BITS_GAIN_FACTOR - 1 downto C_BITS_ADDR_START)) + unsigned(ram_pulse_doutb(C_BITS_ADDR_START - 1 downto C_BITS_ADDR_LENGTH)))) then
|
||||
sm_state <= S_WAVE_FLAT;
|
||||
-- initialize the counter for the flat top of the waveform
|
||||
cnt_wave_top <= std_logic_vector(to_unsigned(0, C_BITS_ADDR_TOP));
|
||||
else
|
||||
-- Output waveform from RAM with rounded gain factor
|
||||
v_ram_waveform_addrb := ((unsigned(ram_waveform_addrb) + 1) * unsigned(ram_pulse_doutb(C_BITS_TIME_FACTOR - 1 downto C_BITS_GAIN_FACTOR)));
|
||||
ram_waveform_addrb <= std_logic_vector(v_ram_waveform_addrb(C_BITS_TIME_INT downto C_BITS_TIME_FRAC));
|
||||
sm_wavedata <= ram_waveform_doutb;
|
||||
sm_wavedata_dv <= '1';
|
||||
|
||||
end if;
|
||||
|
||||
when S_WAVE_FLAT =>
|
||||
if (cnt_wave_top = ram_pulse_doutb(C_BITS_ADDR_TOP - 1 downto 0)) then
|
||||
sm_state <= S_WAVE_DOWN;
|
||||
else
|
||||
cnt_wave_top <= std_logic_vector(unsigned(cnt_wave_top) + 1);
|
||||
sm_wavedata <= ram_waveform_doutb;
|
||||
sm_wavedata_dv <= '1';
|
||||
end if;
|
||||
|
||||
when S_WAVE_DOWN =>
|
||||
-- End of waveform?
|
||||
if (ram_waveform_addrb = std_logic_vector(to_unsigned(C_LENGTH_WAVEFORM-1,10))) then
|
||||
|
||||
-- If the end of the pulse table is reached then go to idle
|
||||
if (ram_pulse_addrb = std_logic_vector(to_unsigned(C_NUM_PULSE-1,10))) then
|
||||
ram_pulse_addrb <= (others=>'0');
|
||||
sm_state <= S_IDLE;
|
||||
|
||||
else -- Increment pulse address. Wait for next pulse start time
|
||||
ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
|
||||
sm_state <= S_WAIT;
|
||||
end if;
|
||||
|
||||
-- Output waveform from RAM with decremented address
|
||||
else
|
||||
v_ram_waveform_addrb := (unsigned(ram_waveform_addrb) - 1) * unsigned(ram_pulse_doutb(C_BITS_TIME_FACTOR - 1 downto C_BITS_GAIN_FACTOR));
|
||||
ram_waveform_addrb <= std_logic_vector(v_ram_waveform_addrb(C_BITS_TIME_INT downto C_BITS_TIME_FRAC));
|
||||
sm_wavedata <= ram_waveform_doutb;
|
||||
sm_wavedata_dv <= '1';
|
||||
end if;
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Default
|
||||
------------------------------------------------------------------------
|
||||
when others =>
|
||||
sm_state <= S_IDLE;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
-- AXI-Stream output.
|
||||
-- TBD: This should come from a FIFO
|
||||
-- TODO: the bits are not correct, should be top bits (C_BITS_GAIN_FACTOR + 16 downto C_BITS_GAIN_FACTOR), but for now just make it this way so modelsim can simulate
|
||||
-- TODO: apply scaling factor to the output
|
||||
axis_tdata <= sm_wavedata; -- axi stream output data, this output should be multiplied by the gain factor, then take the top 16 bits
|
||||
axis_tvalid <= sm_wavedata_dv; -- axi_stream output data valid
|
||||
|
||||
-- TBD : Generate in state machine?
|
||||
axis_tlast <= '0'; -- axi_stream output last
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- **** TBD : ADD FIFO ****
|
||||
----------------------------------------------------------------
|
||||
-- FIFO for waveform data
|
||||
-- connect to external output to whatever we want to connect
|
||||
----------------------------------------------------------------
|
||||
--u_data_to_stream : entity work.fifo_data_to_stream
|
||||
--port map (
|
||||
-- clk => clk, -- input std_logic
|
||||
-- srst => reset, -- input std_logic
|
||||
-- rd_en => fifo_rd_en, -- input std_logic
|
||||
-- wr_en => fifo_wr_en, -- input std_logic
|
||||
-- empty => fifo_empty, -- output std_logic
|
||||
-- full => fifo_full, -- output std_logic
|
||||
-- din => ram_waveform_doutb, -- input slv(15 downto 0)
|
||||
-- dout => fifo_dout, -- output slv(15 downto 0)
|
||||
--
|
||||
-- -- FIFO signals, some of then are for debug purpose
|
||||
-- wr_ack => fifo_wr_ack, -- output std_logic
|
||||
-- overflow => fifo_overflow, -- output std_logic
|
||||
-- valid => fifo_valid, -- output std_logic
|
||||
-- underflow => fifo_underflow, -- output std_logic
|
||||
-- wr_rst_busy => fifo_wr_rst_busy, -- output std_logic
|
||||
-- rd_rst_busy => fifo_rd_rst_busy -- output std_logic
|
||||
--);
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- CPU Read/Write RAM
|
||||
-- MSB of cpu_addr is used to select one of the two RAMs
|
||||
-- to read/write, and the remainder are a 9-bit or 4-bit RAM address.
|
||||
----------------------------------------------------------------
|
||||
pr_ram_rw : process (reset, clk)
|
||||
begin
|
||||
if (reset = '1') then
|
||||
|
||||
ram_pulse_addra <= (others=>'0');
|
||||
ram_pulse_dina <= (others=>'0');
|
||||
ram_pulse_we <= '0';
|
||||
|
||||
ram_waveform_ena <= '0';
|
||||
ram_waveform_wea <= (others=>'0');
|
||||
ram_waveform_addra <= (others=>'0');
|
||||
ram_waveform_dina <= (others=>'0');
|
||||
|
||||
cpu_rdata <= (others=>'0');
|
||||
cpu_rdata_dv <= '0';
|
||||
cpu_rdata_dv_e1 <= '0';
|
||||
cpu_rdata_dv_e2 <= '0';
|
||||
cpu_rdata_ramsel_d1 <= '0';
|
||||
cpu_rdata_ramsel_d2 <= '0';
|
||||
|
||||
elsif rising_edge(clk) then
|
||||
|
||||
ram_waveform_ena <= '0';
|
||||
|
||||
-------------------------------------------------
|
||||
-- CPU writing RAM
|
||||
-------------------------------------------------
|
||||
if (cpu_wr = '1') and (cpu_sel = '1') then
|
||||
|
||||
-- 0 for pulse position, 1 for waveform table
|
||||
if (cpu_addr(9) = '1') then
|
||||
|
||||
ram_pulse_addra <= (others=>'0');
|
||||
ram_pulse_dina <= (others=>'0');
|
||||
ram_pulse_we <= '0';
|
||||
|
||||
ram_waveform_wea(0) <= '1';
|
||||
ram_waveform_ena <= '1';
|
||||
ram_waveform_addra <= cpu_addr(8 downto 0);
|
||||
ram_waveform_dina <= cpu_wdata;
|
||||
|
||||
else
|
||||
|
||||
ram_pulse_addra <= cpu_addr(5 downto 2);
|
||||
-- select which part of the 96-bit data to write
|
||||
if (cpu_addr(1 downto 0) = "00") then
|
||||
ram_pulse_dina(31 downto 0) <= cpu_wdata;
|
||||
elsif (cpu_addr(1 downto 0) = "01") then
|
||||
ram_pulse_dina(63 downto 32) <= cpu_wdata;
|
||||
elsif (cpu_addr(1 downto 0) = "10") then
|
||||
ram_pulse_dina(95 downto 64) <= cpu_wdata;
|
||||
ram_pulse_we <= '1'; -- Write on the thrid cycle
|
||||
end if;
|
||||
|
||||
|
||||
ram_waveform_ena <= '0';
|
||||
ram_waveform_wea <= (others=>'0');
|
||||
ram_waveform_addra <= (others=>'0');
|
||||
ram_waveform_dina <= (others=>'0');
|
||||
|
||||
end if;
|
||||
|
||||
cpu_rdata_dv_e1 <= '0';
|
||||
cpu_rdata_dv_e2 <= '0';
|
||||
cpu_rdata_ramsel_d1 <= '0';
|
||||
cpu_rdata_ramsel_d2 <= '0';
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- CPU read
|
||||
-------------------------------------------------
|
||||
elsif (cpu_wr = '0') and (cpu_sel = '1') then
|
||||
|
||||
if (cpu_addr(9) = '1') then -- Waveform
|
||||
ram_waveform_ena <= '1';
|
||||
ram_pulse_addra <= (others=>'0');
|
||||
ram_waveform_addra <= cpu_addr(8 downto 0);
|
||||
else -- Pulse
|
||||
ram_pulse_addra <= cpu_addr(5 downto 2);
|
||||
ram_pulse_douta_d1 <= ram_pulse_douta; -- Delay distrib RAM output to match pipeline of Block RAM
|
||||
ram_waveform_addra <= (others=>'0');
|
||||
end if;
|
||||
|
||||
ram_pulse_we <= '0';
|
||||
ram_waveform_wea(0) <= '0';
|
||||
|
||||
cpu_rdata_dv_e2 <= '1'; -- DV for cycle, when RAM output occurs
|
||||
cpu_rdata_dv_e1 <= cpu_rdata_dv_e2; -- DV for next cycle
|
||||
cpu_rdata_ramsel_d1 <= cpu_addr(9); -- Save the select bit one cycle later
|
||||
cpu_rdata_ramsel_d2 <= cpu_rdata_ramsel_d1;
|
||||
|
||||
else
|
||||
ram_pulse_addra <= (others=>'0');
|
||||
ram_pulse_we <= '0';
|
||||
ram_waveform_addra <= (others=>'0');
|
||||
ram_waveform_wea(0) <= '0';
|
||||
|
||||
cpu_rdata_dv_e2 <= '0';
|
||||
cpu_rdata_dv_e1 <= cpu_rdata_dv_e2; -- DV for next cycle
|
||||
cpu_rdata_ramsel_d1 <= '0';
|
||||
cpu_rdata_ramsel_d2 <= cpu_rdata_ramsel_d1;
|
||||
|
||||
end if;
|
||||
|
||||
-------------------------------------------------
|
||||
-- Output the delayed RAM data
|
||||
-- This adds a pipeline delay to the cpu_rdata_dv to account for
|
||||
-- the delay in reading data from the RAM
|
||||
-------------------------------------------------
|
||||
if (cpu_rdata_dv_e1 = '1') then
|
||||
|
||||
cpu_rdata_dv <= '1';
|
||||
|
||||
-- Select source of output data
|
||||
if (cpu_rdata_ramsel_d2 = '1') then -- Output is from waveform table
|
||||
cpu_rdata <= ram_waveform_douta;
|
||||
|
||||
elsif (cpu_rdata_ramsel_d2 = '0') then
|
||||
-- cpu_rdata <= X"00" & ram_pulse_douta_d1;
|
||||
-- select which part of the 96-bit data to read
|
||||
if (cpu_addr(1 downto 0) = "00") then
|
||||
cpu_rdata <= ram_pulse_douta_d1(31 downto 0);
|
||||
elsif (cpu_addr(1 downto 0) = "01") then
|
||||
cpu_rdata <= ram_pulse_douta_d1(63 downto 32);
|
||||
elsif (cpu_addr(1 downto 0) = "10") then
|
||||
cpu_rdata <= ram_pulse_douta_d1(95 downto 64);
|
||||
|
||||
end if;
|
||||
end if;
|
||||
|
||||
else
|
||||
cpu_rdata <= (others=>'0');
|
||||
cpu_rdata_dv <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
|
||||
-- ----------------------------------------------------------------
|
||||
-- -- Read time from RAM to generate pulses
|
||||
-- -- When input cnt_time equals RAM time output then set dout
|
||||
-- -- to RAM amplitude output and read next set of RAM data.
|
||||
-- -- Keep reading waveform RAM every clock cycle until the end of the RAM
|
||||
-- ----------------------------------------------------------------
|
||||
-- pr_ram_pulse : process(reset, clk)
|
||||
-- begin
|
||||
-- if (reset = '1') then
|
||||
--
|
||||
-- ram_pulse_addrb <= (others => '0');
|
||||
-- start_pulse <= '0';
|
||||
-- dout_dv <= '0';
|
||||
--
|
||||
-- elsif rising_edge(clk) then
|
||||
--
|
||||
-- -- dout <= ram_amplitude;
|
||||
--
|
||||
-- if (cnt_time = X"000000") then -- Not triggered
|
||||
-- ram_pulse_addrb <= (others=>'0');
|
||||
-- dout_dv <= '0';
|
||||
-- start_pulse <= '0';
|
||||
--
|
||||
-- elsif (ram_time = cnt_time) then
|
||||
--
|
||||
-- ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
|
||||
-- dout_dv <= '1';
|
||||
-- start_pulse <= '1';
|
||||
--
|
||||
-- else
|
||||
-- dout_dv <= '0';
|
||||
-- start_pulse <= '0';
|
||||
-- end if;
|
||||
--
|
||||
-- end if;
|
||||
--
|
||||
-- end process;
|
||||
--
|
||||
--
|
||||
-- ----------------------------------------------------------------
|
||||
-- -- Read amplitude from Waveform RAM to generate pulses
|
||||
-- -- When start_pulse is asserted, and when FIFO is not full, write
|
||||
-- -- amplitude to FIFO.
|
||||
-- ----------------------------------------------------------------
|
||||
-- pr_ram_wavetable : process(reset, clk)
|
||||
-- begin
|
||||
-- if (reset = '1') then
|
||||
-- fifo_wr_en <= '0';
|
||||
-- ram_waveform_addrb <= (others => '0');
|
||||
-- ram_waveform_enb <= '0';
|
||||
-- busy <= '0';
|
||||
-- elsif rising_edge(clk) then
|
||||
-- if (read_table = '1') then -- start_pulse get asserted
|
||||
-- busy <= '1';
|
||||
-- -- TODO EricToGeoff : This condition may not satisfy all cases of a fifo_ready, maybe also utilize fifo_wr_ack or just a simple FSM?
|
||||
-- if (fifo_full = '0') then
|
||||
-- fifo_wr_en <= '1';
|
||||
-- ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1);
|
||||
-- ram_waveform_enb <= '1';
|
||||
-- else
|
||||
-- fifo_wr_en <= '0';
|
||||
-- -- FIFO is full, wait
|
||||
-- ram_waveform_addrb <= ram_waveform_addrb;
|
||||
-- ram_waveform_enb <= '0';
|
||||
-- end if;
|
||||
-- else
|
||||
-- fifo_wr_en <= '0';
|
||||
-- ram_waveform_addrb <= (others => '0');
|
||||
-- ram_waveform_enb <= '0';
|
||||
-- end if;
|
||||
-- end if;
|
||||
--
|
||||
-- end process;
|
||||
--
|
||||
-- -- For new versions, ram_doutb are differnt RAMs b port outputs, ram_amplitude should go thought a FIFO first from RAM
|
||||
-- ram_time <= ram_doutb;
|
||||
-- read_table <= start_pulse;
|
||||
--
|
||||
-- fifo_rd_en <= axi_tready and fifo_full;
|
||||
|
||||
end rtl;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,30 @@
|
|||
----------------------------------------------------------------------------------------
|
||||
-- Project : qlaser FPGA
|
||||
-- File : qlaser_dac_dc_pkg.vhd
|
||||
-- Description : Version package file.
|
||||
-- Author : akozyra
|
||||
----------------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
package qlaser_dac_dc_pkg is
|
||||
|
||||
----------------------------------------------------------------------------------------
|
||||
-- Constants
|
||||
----------------------------------------------------------------------------------------
|
||||
|
||||
-- Addresses
|
||||
constant C_ADDR_SPI0 : std_logic_vector(2 downto 0) := "000";
|
||||
constant C_ADDR_SPI1 : std_logic_vector(2 downto 0) := "001";
|
||||
constant C_ADDR_SPI2 : std_logic_vector(2 downto 0) := "010";
|
||||
constant C_ADDR_SPI3 : std_logic_vector(2 downto 0) := "011";
|
||||
constant C_ADDR_SPI_ALL : std_logic_vector(2 downto 0) := "100";
|
||||
constant C_ADDR_INTERNAL_REF : std_logic_vector(2 downto 0) := "101";
|
||||
constant C_ADDR_POWER_ON : std_logic_vector(2 downto 0) := "110";
|
||||
|
||||
-- Commands
|
||||
constant C_CMD_DAC_DC_WR : std_logic_vector(3 downto 0) := "0011";
|
||||
constant C_CMD_DAC_DC_INTERNAL_REF : std_logic_vector(3 downto 0) := "1000";
|
||||
constant C_CMD_DAC_DC_POWER : std_logic_vector(3 downto 0) := "0100";
|
||||
|
||||
end package qlaser_dac_dc_pkg;
|
|
@ -0,0 +1,146 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- Filename : qlaser_pkg.vhd
|
||||
-------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
use work.qlaser_dac_dc_pkg.all;
|
||||
-- use work.qlaser_dac_ac_pkg.all;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- FPGA constant definitions
|
||||
-------------------------------------------------------------------------------
|
||||
package qlaser_pkg is
|
||||
|
||||
-- FPGA internal (PLL) clock freq expressed in MHz
|
||||
constant C_CLK_FREQ_MHZ : real := 100.0;
|
||||
-- Clock period
|
||||
constant C_CLK_PERIOD : time := integer(1.0E+6/(C_CLK_FREQ_MHZ)) * 1 ps;
|
||||
|
||||
constant C_NUM_CHAN_DC : integer := 32; -- Number of DC channels
|
||||
constant C_NUM_CHAN_AC : integer := 32; -- Number of AC (pulse) channels
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- FPGA Addresses
|
||||
-- Main blocks. Decoded from upper 4 bits of address [15:12]
|
||||
--------------------------------------------------------------------------------
|
||||
constant ADR_BASE_DC : std_logic_vector( 3 downto 0) := X"0"; -- Registers to load DC DAC values
|
||||
constant ADR_BASE_PULSE : std_logic_vector( 3 downto 0) := X"1"; -- RAMs for Pulse output start/stop times
|
||||
constant ADR_BASE_MISC : std_logic_vector( 3 downto 0) := X"2"; -- Misc, LEDs, switches, power control
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Define the number of internal blocks that are addressed by the CPU
|
||||
--------------------------------------------------------------------------------
|
||||
constant C_NUM_BLOCKS : integer := 3;
|
||||
type t_arr_cpu_dout is array (0 to C_NUM_BLOCKS-1) of std_logic_vector(31 downto 0);
|
||||
type t_arr_dout_ac is array (0 to C_NUM_CHAN_AC-1) of std_logic_vector(15 downto 0);
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- 'DC' DAC block registers. 32 16-bit DAC outputs [5:3]
|
||||
constant C_ADDR_CH_SPI0 : std_logic_vector(2 downto 0) := "000";
|
||||
constant C_ADDR_CH_SPI1 : std_logic_vector(2 downto 0) := "001";
|
||||
constant C_ADDR_CH_SPI2 : std_logic_vector(2 downto 0) := "010";
|
||||
constant C_ADDR_CH_SPI3 : std_logic_vector(2 downto 0) := "011";
|
||||
constant C_ADDR_CH_SPI_ALL : std_logic_vector(2 downto 0) := "100";
|
||||
constant C_ADDR_INTERNAL_REF : std_logic_vector(2 downto 0) := "101";
|
||||
constant C_ADDR_POWER_ON : std_logic_vector(2 downto 0) := "110";
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- Individual DAC data registers
|
||||
constant ADR_DAC_DC0 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "000"; --
|
||||
constant ADR_DAC_DC1 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "001"; --
|
||||
constant ADR_DAC_DC2 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "010"; --
|
||||
constant ADR_DAC_DC3 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "011"; --
|
||||
constant ADR_DAC_DC4 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "100"; --
|
||||
constant ADR_DAC_DC5 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "101"; --
|
||||
constant ADR_DAC_DC6 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "110"; --
|
||||
constant ADR_DAC_DC7 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "111"; --
|
||||
|
||||
constant ADR_DAC_DC8 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI1 & "000"; --
|
||||
constant ADR_DAC_DC9 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI1 & "001"; --
|
||||
|
||||
-- constant ADR_DAC_DC6 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI2 & "000"; --
|
||||
-- constant ADR_DAC_DC7 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI2 & "001"; --
|
||||
-- etc. etc.
|
||||
-- constant ADR_DAC_DC6 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI3 & "110"; --
|
||||
-- constant ADR_DAC_DC7 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI3 & "111"; --
|
||||
constant ADR_DAC_DC30 : std_logic_vector(15 downto 0) := ADR_BASE_DC & X"01E"; --
|
||||
constant ADR_DAC_DC31 : std_logic_vector(15 downto 0) := ADR_BASE_DC & X"01F"; --
|
||||
|
||||
constant ADR_DAC_DC_ALL : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_CH_SPI_ALL & "000"; -- Write all channels
|
||||
constant ADR_DAC_DC_IREF : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_INTERNAL_REF & "000"; --
|
||||
constant ADR_DAC_DC_POWER_ON : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_POWER_ON & "000"; --
|
||||
constant ADR_DAC_DC_STATUS : std_logic_vector(15 downto 0) := ADR_BASE_DC & X"000"; -- Reading any address returns SPI interface busy status (this was 32 bit, but decleared as 16, so I changed to 16)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- 'Pulse' DAC block registers.
|
||||
-- The block has a set of block registers and contains 16 'channels'
|
||||
-- Each channel has a 40-bit memory to specify 24-bit time and a 16-bit level.
|
||||
-- Initially just using the MSB of the level to drive a single pin output
|
||||
--
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- Block-level registers
|
||||
-- CPU_ADDR(11) = '0' selects local regs
|
||||
-- CPU_ADDR(11) = '1' selects the channel specified in reg_ctrl(3 :0)
|
||||
-- Then CPU_ADDR(10:1) selects RAM word address (1024 address MAX)
|
||||
-- CPU_ADDR(0) selects MSB or LSB of 40-bit RAM word (time or amplitude)
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- Addresses for block-level registers.
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
constant ADR_DAC_PULSE_CTRL : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"800"; -- 4:0 select channel RAM for CPU read/write. Bit 8 is rising edge internal trigger
|
||||
constant ADR_DAC_PULSE_STATUS : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"801"; -- R/O Level status for output of each channel
|
||||
constant ADR_DAC_PULSE_RUNTIME : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"802"; -- Max time for pulse train
|
||||
constant ADR_DAC_PULSE_CH_EN : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"803"; -- Enable bit for each individual channel
|
||||
constant ADR_DAC_PULSE_TIMER : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"804"; -- R/O Current timer value (used by all channels)
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- Pulse Channel offsets
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
constant ADR_DAC_PULSE0 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"000"; -- Base address of a 16-word x 40-bit RAM
|
||||
constant ADR_DAC_PULSE1 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"040"; --
|
||||
constant ADR_DAC_PULSE2 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"080"; --
|
||||
constant ADR_DAC_PULSE3 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"0C0"; --
|
||||
--
|
||||
constant ADR_DAC_PULSE4 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"100"; --
|
||||
constant ADR_DAC_PULSE5 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"140"; --
|
||||
constant ADR_DAC_PULSE6 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"180"; --
|
||||
constant ADR_DAC_PULSE7 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"1C0"; --
|
||||
--
|
||||
constant ADR_DAC_PULSE8 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"200"; --
|
||||
constant ADR_DAC_PULSE9 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"240"; --
|
||||
constant ADR_DAC_PULSE10 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"280"; --
|
||||
constant ADR_DAC_PULSE11 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"2C0"; --
|
||||
--
|
||||
constant ADR_DAC_PULSE12 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"300"; --
|
||||
constant ADR_ADC_PULSE13 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"340"; --
|
||||
constant ADR_DAC_PULSE14 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"380"; --
|
||||
constant ADR_DAC_PULSE15 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"3C0"; --
|
||||
--
|
||||
-- etc. etc.
|
||||
constant ADR_DAC_PULSE28 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"700"; --
|
||||
constant ADR_DAC_PULSE29 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"740"; --
|
||||
constant ADR_DAC_PULSE30 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"780"; --
|
||||
constant ADR_DAC_PULSE31 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"7C0"; --
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc block registers
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
constant ADR_MISC_VERSION : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"000"; -- HDL code version
|
||||
constant ADR_MISC_LEDS : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"001"; -- LEDs
|
||||
constant ADR_MISC_LEDS_EN : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"002"; -- LEDs enable
|
||||
constant ADR_MISC_SW_IN : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"003"; -- Read board switch settings (if present)
|
||||
constant ADR_MISC_DEBUG_CTRL : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"004"; -- Select debug output from top level to pins
|
||||
|
||||
|
||||
end package;
|
||||
|
||||
package body qlaser_pkg is
|
||||
|
||||
end package body;
|
||||
|
|
@ -0,0 +1,394 @@
|
|||
-----------------------------------------------------------
|
||||
-- File : tb_cpubus_dacs_pulse_channel.vhd
|
||||
-----------------------------------------------------------
|
||||
--
|
||||
-- Testbench for CPU bus peripheral.
|
||||
--
|
||||
-- Description : Pulse output control of Qlaser FPGA
|
||||
-- Block drives AXI-stream to JESD DACs
|
||||
--
|
||||
----------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.std_logic_1164.all;
|
||||
use std.textio.all;
|
||||
|
||||
use work.std_iopak.all;
|
||||
|
||||
|
||||
entity tb_cpubus_dacs_pulse_channel is
|
||||
end tb_cpubus_dacs_pulse_channel;
|
||||
|
||||
architecture behave of tb_cpubus_dacs_pulse_channel is
|
||||
|
||||
signal clk : std_logic;
|
||||
signal reset : std_logic;
|
||||
signal enable : std_logic;
|
||||
signal start : std_logic;
|
||||
signal cnt_time : std_logic_vector(23 downto 0);
|
||||
signal busy : std_logic;
|
||||
signal cpu_wr : std_logic;
|
||||
signal cpu_sel : std_logic;
|
||||
signal cpu_addr : std_logic_vector(15 downto 0);
|
||||
signal cpu_wdata : std_logic_vector(31 downto 0);
|
||||
signal cpu_rdata : std_logic_vector(31 downto 0);
|
||||
signal cpu_rdata_dv : std_logic;
|
||||
|
||||
-- AXI-stream output interface
|
||||
signal axis_tready : std_logic := '1'; -- Always ready
|
||||
signal axis_tdata : std_logic_vector(15 downto 0);
|
||||
signal axis_tvalid : std_logic;
|
||||
signal axis_tlast : std_logic;
|
||||
|
||||
-- Halts simulation by stopping clock when set true
|
||||
signal sim_done : boolean := false;
|
||||
|
||||
-- Crystal clock freq expressed in MHz
|
||||
constant CLK_FREQ_MHZ : real := 100.0;
|
||||
-- Clock period
|
||||
constant CLK_PER : time := integer(1.0E+6/(CLK_FREQ_MHZ)) * 1 ps;
|
||||
|
||||
-- Block registers
|
||||
constant ADR_RAM_PULSE : integer := 0; -- base address for pulse RAM, TODO: this constant should eventually go to qlaser_pkg
|
||||
constant ADR_RAM_WAVE : integer := 512; --
|
||||
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- CPU write procedure. Address in decimal. Data in hex
|
||||
-------------------------------------------------------------
|
||||
procedure cpu_write(
|
||||
signal clk : in std_logic;
|
||||
constant a : in integer;
|
||||
constant d : in std_logic_vector(31 downto 0);
|
||||
signal cpu_sel : out std_logic;
|
||||
signal cpu_wr : out std_logic;
|
||||
signal cpu_addr : out std_logic_vector(15 downto 0);
|
||||
signal cpu_wdata : out std_logic_vector(31 downto 0)
|
||||
) is
|
||||
begin
|
||||
wait until clk'event and clk='0';
|
||||
cpu_sel <= '1';
|
||||
cpu_wr <= '1';
|
||||
cpu_addr <= std_logic_vector(to_unsigned(a, 16));
|
||||
cpu_wdata <= std_logic_vector(d);
|
||||
wait until clk'event and clk='0';
|
||||
cpu_sel <= '0';
|
||||
cpu_wr <= '0';
|
||||
cpu_addr <= (others=>'0');
|
||||
cpu_wdata <= (others=>'0');
|
||||
wait until clk'event and clk='0';
|
||||
end;
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- CPU write pulse definition RAM
|
||||
-- Use 96 bit data to make three 32-bit writes
|
||||
-------------------------------------------------------------
|
||||
procedure cpu_write_pulsedef(
|
||||
signal clk : in std_logic;
|
||||
|
||||
constant num_entry : in integer;
|
||||
|
||||
-- TODO: Partial ? list of parameters
|
||||
constant pulsetime : in integer; -- Pulse time in clock cycles
|
||||
constant timefactor : in real; -- Fixed point time scale factor
|
||||
constant gainfactor : in real; -- Fixed point gain value. Max value 1.0 is hex X"8000". Gain 0.5 is therefore X"4000"
|
||||
constant wavestartaddr : in integer; -- Start address in waveform RAM
|
||||
constant wavesteps : in integer; -- Number of steps in waveform rise and fall
|
||||
constant wavetopwidth : in integer; -- Number of clock cycles in waveform top between end of rise and start of fall
|
||||
|
||||
|
||||
signal cpu_sel : out std_logic;
|
||||
signal cpu_wr : out std_logic;
|
||||
signal cpu_addr : out std_logic_vector(15 downto 0);
|
||||
signal cpu_wdata : out std_logic_vector(31 downto 0)
|
||||
) is
|
||||
-- Vectors for converted values
|
||||
variable slv_pulsetime : std_logic_vector(23 downto 0); -- For 24-bit pulse time
|
||||
variable slv_timefactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point timestep
|
||||
variable slv_gainfactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point gain
|
||||
variable slv_wavestartaddr : std_logic_vector( 9 downto 0); -- For 10-bit address i.e. 1024 point waveform RAM
|
||||
variable slv_wavesteps : std_logic_vector( 9 downto 0); -- For 10-bit number of steps i.e. 0 = 1 step, X"3FF" = 1024 points
|
||||
variable slv_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit number of clock cycles in top of waveform
|
||||
|
||||
variable slv_entry_data : std_logic_vector(95 downto 0); -- Vector for entire memory entry
|
||||
|
||||
-- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg
|
||||
-- Define the number of fractional bits
|
||||
constant BIT_FRAC : integer := 4; -- TODO: this should be defined in qlaser_pkg
|
||||
begin
|
||||
|
||||
-- Convert each field into its std_logic_vector equivalent
|
||||
slv_pulsetime := std_logic_vector(to_unsigned(pulsetime, 24));
|
||||
slv_timefactor := std_logic_vector(to_unsigned(integer(timefactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
|
||||
slv_gainfactor := std_logic_vector(to_unsigned(integer(gainfactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
|
||||
slv_wavestartaddr := std_logic_vector(to_unsigned(wavestartaddr, 10));
|
||||
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
|
||||
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
|
||||
|
||||
|
||||
--etc, etc.
|
||||
|
||||
-- Build full entry out of component fields. Final length should be 96 bits.
|
||||
slv_entry_data := "000" & slv_pulsetime & slv_timefactor & slv_gainfactor & slv_wavestartaddr & slv_wavesteps & slv_wavetopwidth; -- This might not correct
|
||||
|
||||
-- Write 96-bit entry in 3 writes. (Address is an integer)
|
||||
cpu_write(clk, ADR_RAM_PULSE+(4*num_entry) , slv_entry_data(31 downto 0), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
|
||||
cpu_write(clk, ADR_RAM_PULSE+(4*num_entry)+1 , slv_entry_data(63 downto 32), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
|
||||
cpu_write(clk, ADR_RAM_PULSE+(4*num_entry)+2 , slv_entry_data(95 downto 64), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
|
||||
end;
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- CPU write procedure. Address and Data in decimal
|
||||
-------------------------------------------------------------
|
||||
procedure cpu_write(
|
||||
signal clk : in std_logic;
|
||||
constant a : in integer;
|
||||
constant d : in integer;
|
||||
signal cpu_sel : out std_logic;
|
||||
signal cpu_wr : out std_logic;
|
||||
signal cpu_addr : out std_logic_vector(15 downto 0);
|
||||
signal cpu_wdata : out std_logic_vector(31 downto 0)
|
||||
) is
|
||||
begin
|
||||
cpu_write(clk, a , std_logic_vector(to_unsigned(d,32)), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
|
||||
end;
|
||||
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- CPU read procedure
|
||||
-------------------------------------------------------------
|
||||
procedure cpu_read(
|
||||
signal clk : in std_logic;
|
||||
constant a : in integer;
|
||||
constant exp_d : in std_logic_vector(31 downto 0);
|
||||
signal cpu_sel : out std_logic;
|
||||
signal cpu_wr : out std_logic;
|
||||
signal cpu_addr : out std_logic_vector(15 downto 0);
|
||||
signal cpu_wdata : out std_logic_vector(31 downto 0);
|
||||
signal cpu_rdata : in std_logic_vector(31 downto 0);
|
||||
signal cpu_rdata_dv : in std_logic
|
||||
) is
|
||||
variable v_bdone : boolean := false;
|
||||
variable str_out : string(1 to 256);
|
||||
begin
|
||||
wait until clk'event and clk='0';
|
||||
cpu_sel <= '1';
|
||||
cpu_wr <= '0';
|
||||
cpu_addr <= std_logic_vector(to_unsigned(a, 16));
|
||||
cpu_wdata <= (others=>'0');
|
||||
while (v_bdone = false) loop
|
||||
wait until clk'event and clk='0';
|
||||
cpu_sel <= '1';
|
||||
if (cpu_rdata_dv = '1') then
|
||||
if (cpu_rdata /= exp_d) then
|
||||
fprint(str_out, "Read exp: 0x%s actual: 0x%s\n", to_string(to_bitvector(exp_d),"%08X"), to_string(to_bitvector(cpu_rdata),"%08X"));
|
||||
report str_out severity error;
|
||||
end if;
|
||||
v_bdone := true;
|
||||
cpu_sel <= '0';
|
||||
cpu_addr <= (others=>'0');
|
||||
end if;
|
||||
end loop;
|
||||
wait until clk'event and clk='0';
|
||||
wait until clk'event and clk='0';
|
||||
end;
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- CPU read pulse definition RAM
|
||||
-- Use 96 bit data to make three 32-bit writes
|
||||
-------------------------------------------------------------
|
||||
procedure cpu_read_pulsedef(
|
||||
signal clk : in std_logic;
|
||||
|
||||
constant num_entry : in integer;
|
||||
|
||||
-- TODO: Partial ? list of parameters
|
||||
constant pulsetime : in integer; -- Pulse time in clock cycles
|
||||
constant timefactor : in real; -- Fixed point time scale factor
|
||||
constant gainfactor : in real; -- Fixed point gain value. Max value 1.0 is hex X"8000". Gain 0.5 is therefore X"4000"
|
||||
constant wavestartaddr : in integer; -- Start address in waveform RAM
|
||||
constant wavesteps : in integer; -- Number of steps in waveform rise and fall
|
||||
constant wavetopwidth : in integer; -- Number of clock cycles in waveform top between end of rise and start of fall
|
||||
|
||||
|
||||
signal cpu_sel : out std_logic;
|
||||
signal cpu_wr : out std_logic;
|
||||
signal cpu_addr : out std_logic_vector(15 downto 0);
|
||||
signal cpu_wdata : out std_logic_vector(31 downto 0)
|
||||
) is
|
||||
-- Vectors for converted values
|
||||
variable slv_pulsetime : std_logic_vector(23 downto 0); -- For 24-bit pulse time
|
||||
variable slv_timefactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point timestep
|
||||
variable slv_gainfactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point gain
|
||||
variable slv_wavestartaddr : std_logic_vector( 9 downto 0); -- For 10-bit address i.e. 1024 point waveform RAM
|
||||
variable slv_wavesteps : std_logic_vector( 9 downto 0); -- For 10-bit number of steps i.e. 0 = 1 step, X"3FF" = 1024 points
|
||||
variable slv_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit number of clock cycles in top of waveform
|
||||
|
||||
variable slv_entry_data : std_logic_vector(95 downto 0); -- Vector for entire memory entry
|
||||
|
||||
-- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg
|
||||
-- Define the number of fractional bits
|
||||
constant BIT_FRAC : integer := 4; -- TODO: this should be defined in qlaser_pkg
|
||||
begin
|
||||
|
||||
-- Convert each field into its std_logic_vector equivalent
|
||||
slv_pulsetime := std_logic_vector(to_unsigned(pulsetime, 24));
|
||||
slv_timefactor := std_logic_vector(to_unsigned(integer(timefactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
|
||||
slv_gainfactor := std_logic_vector(to_unsigned(integer(gainfactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
|
||||
slv_wavestartaddr := std_logic_vector(to_unsigned(wavestartaddr, 10));
|
||||
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
|
||||
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
|
||||
|
||||
|
||||
--etc, etc.
|
||||
|
||||
-- Build full entry out of component fields. Final length should be 96 bits.
|
||||
slv_entry_data := "000" & slv_pulsetime & slv_timefactor & slv_gainfactor & slv_wavestartaddr & slv_wavesteps & slv_wavetopwidth; -- This might not correct
|
||||
|
||||
-- Write 96-bit entry in 3 writes. (Address is an integer)
|
||||
cpu_read(clk, ADR_RAM_PULSE+(4*num_entry), slv_entry_data(31 downto 0), cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
|
||||
cpu_read(clk, ADR_RAM_PULSE+(4*num_entry) + 1, slv_entry_data(63 downto 32), cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
|
||||
cpu_read(clk, ADR_RAM_PULSE+(4*num_entry) + 2, slv_entry_data(95 downto 64), cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Delay
|
||||
-------------------------------------------------------------
|
||||
procedure clk_delay(
|
||||
constant nclks : in integer
|
||||
) is
|
||||
begin
|
||||
for I in 0 to nclks loop
|
||||
wait until clk'event and clk ='0';
|
||||
end loop;
|
||||
end;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Print a string with no time or instance path.
|
||||
----------------------------------------------------------------
|
||||
procedure cpu_print_msg(
|
||||
constant msg : in string
|
||||
) is
|
||||
variable line_out : line;
|
||||
begin
|
||||
write(line_out, msg);
|
||||
writeline(output, line_out);
|
||||
end procedure cpu_print_msg;
|
||||
|
||||
|
||||
begin
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Unit Under Test
|
||||
-------------------------------------------------------------
|
||||
u_dac_pulse : entity work.qlaser_dacs_pulse_channel
|
||||
port map (
|
||||
clk => clk , -- in std_logic;
|
||||
reset => reset , -- in std_logic;
|
||||
|
||||
enable => enable , -- out std_logic;
|
||||
start => start , -- out std_logic;
|
||||
cnt_time => cnt_time , -- out std_logic_vector(23 downto 0); -- Set to '1' while SPI interface is busy
|
||||
|
||||
busy => busy , -- out std_logic; -- Set to '1' while SPI interface is busy
|
||||
|
||||
-- CPU interface
|
||||
cpu_wr => cpu_wr , -- in std_logic;
|
||||
cpu_sel => cpu_sel , -- in std_logic;
|
||||
cpu_addr => cpu_addr( 9 downto 0) , -- in std_logic_vector(11 downto 0);
|
||||
cpu_wdata => cpu_wdata , -- in std_logic_vector(31 downto 0);
|
||||
|
||||
cpu_rdata => cpu_rdata , -- out std_logic_vector(31 downto 0);
|
||||
cpu_rdata_dv => cpu_rdata_dv , -- out std_logic;
|
||||
|
||||
|
||||
-- AXI-Stream interface
|
||||
axis_tready => axis_tready , -- in std_logic; -- Clock (50 MHz max)
|
||||
axis_tdata => axis_tdata , -- out std_logic_vector(15 downto 0);
|
||||
axis_tvalid => axis_tvalid , -- out std_logic; -- Master out, Slave in. (Data to DAC)
|
||||
axis_tlast => axis_tlast -- out std_logic; -- Active low chip select (sync_n)
|
||||
);
|
||||
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Generate system clock. Halt when sim_done is true.
|
||||
-------------------------------------------------------------
|
||||
pr_clk : process
|
||||
begin
|
||||
clk <= '0';
|
||||
wait for (CLK_PER/2);
|
||||
clk <= '1';
|
||||
wait for (CLK_PER-CLK_PER/2);
|
||||
if (sim_done=true) then
|
||||
wait;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Reset and drive CPU bus
|
||||
-------------------------------------------------------------
|
||||
pr_main : process
|
||||
variable v_ndata32 : integer := 0;
|
||||
variable v_ndata16 : integer := 0;
|
||||
begin
|
||||
-- Reset
|
||||
reset <= '1';
|
||||
enable <= '0';
|
||||
start <= '0';
|
||||
cnt_time <= (others=>'0');
|
||||
|
||||
cpu_sel <= '0';
|
||||
cpu_wr <= '0';
|
||||
cpu_wdata <= (others=>'0');
|
||||
cpu_addr <= (others=>'0');
|
||||
|
||||
cpu_print_msg("Simulation start");
|
||||
clk_delay(5);
|
||||
reset <= '0';
|
||||
|
||||
clk_delay(5);
|
||||
enable <= '1';
|
||||
|
||||
|
||||
clk_delay(20);
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Load pulse RAM with a series of pulse start times
|
||||
----------------------------------------------------------------
|
||||
v_ndata32 := 128; -- Time for first pulse
|
||||
cpu_print_msg("Load pulse RAM");
|
||||
for NADDR in 0 to 15 loop
|
||||
-- cpu_write(clk, ADR_RAM_PULSE + NADDR , v_ndata32 + (NADDR*(1024+32)), cpu_sel, cpu_wr, cpu_addr, cpu_wdata); -- TODO: rn don't know how to make it write three difference places, for now I', just gonna manually write it
|
||||
cpu_write_pulsedef(clk, NADDR, v_ndata32 + (NADDR*(1024+32)), 1.0, 1.0, 0, NADDR*32, 512, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
|
||||
end loop;
|
||||
cpu_print_msg("Pulse RAM loaded");
|
||||
clk_delay(20);
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Read back Pulse RAM.
|
||||
----------------------------------------------------------------
|
||||
v_ndata32 := 128; -- Time for first pulse
|
||||
for NADDR in 0 to 15 loop
|
||||
cpu_read_pulsedef(clk, NADDR, v_ndata32 + (NADDR*(1024+32)), 1.0, 1.0, 0, NADDR*32, 512, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
|
||||
end loop;
|
||||
clk_delay(20);
|
||||
|
||||
wait for 10 us;
|
||||
|
||||
cpu_print_msg("Simulation done");
|
||||
clk_delay(5);
|
||||
|
||||
sim_done <= true;
|
||||
wait;
|
||||
|
||||
end process;
|
||||
|
||||
end behave;
|
||||
|
|
@ -1 +1,2 @@
|
|||
Please put your modelsim.ini file in this directory and compile modelsim in this directory.
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
echo off
|
||||
vsim -c -quiet -do compile.do
|
|
@ -0,0 +1,8 @@
|
|||
vlib work
|
||||
|
||||
vcom ../../src/hdl/ip_gen/*.vhd*
|
||||
vcom ../../src/hdl/pkg/*pkg.vhd
|
||||
vcom ../../src/hdl/pkg/iopakp.vhd
|
||||
vcom ../../src/hdl/pkg/iopakb.vhd
|
||||
vcom ../../src/hdl/modules/*.vhd*
|
||||
vcom ../../src/hdl/tb/*.vhd*
|
|
@ -0,0 +1,13 @@
|
|||
do compile.do
|
||||
|
||||
vsim -voptargs="+acc" -lib work tb_cpubus_dacs_pulse_channel
|
||||
|
||||
do waves_do/pp_rw_cpu.do
|
||||
|
||||
view wave
|
||||
view structure
|
||||
view signals
|
||||
|
||||
run -all
|
||||
|
||||
# End
|
|
@ -0,0 +1,34 @@
|
|||
onerror {resume}
|
||||
quietly WaveActivateNextPane {} 0
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reset
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/clk
|
||||
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cnt_time
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/busy
|
||||
add wave -noupdate -radix binary /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_addr
|
||||
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_wdata
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_wr
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_sel
|
||||
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_rdata
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_rdata_dv
|
||||
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_addra
|
||||
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_dina
|
||||
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_douta
|
||||
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_we
|
||||
TreeUpdate [SetDefaultTree]
|
||||
WaveRestoreCursors {{Cursor 1} {480433536 fs} 0}
|
||||
quietly wave cursor active 1
|
||||
configure wave -namecolwidth 150
|
||||
configure wave -valuecolwidth 172
|
||||
configure wave -justifyvalue left
|
||||
configure wave -signalnamewidth 1
|
||||
configure wave -snapdistance 10
|
||||
configure wave -datasetprefix 0
|
||||
configure wave -rowmargin 4
|
||||
configure wave -childrowmargin 2
|
||||
configure wave -gridoffset 0
|
||||
configure wave -gridperiod 1
|
||||
configure wave -griddelta 40
|
||||
configure wave -timeline 0
|
||||
configure wave -timelineunits fs
|
||||
update
|
||||
WaveRestoreZoom {0 fs} {1953088753 fs}
|
Loading…
Reference in New Issue