unchecked updated main module cpu rw and its tb

This commit is contained in:
Eric Yu 2023-12-20 17:35:37 -08:00
parent c5f60594ac
commit bad218fbf3
14 changed files with 9049 additions and 4602 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ port (
busy : out std_logic; -- Status signal busy : out std_logic; -- Status signal
-- CPU interface -- CPU interface
cpu_addr : in std_logic_vector( 9 downto 0); -- Address input cpu_addr : in std_logic_vector(11 downto 0); -- Address input
cpu_wdata : in std_logic_vector(31 downto 0); -- Data input cpu_wdata : in std_logic_vector(31 downto 0); -- Data input
cpu_wr : in std_logic; -- Write enable cpu_wr : in std_logic; -- Write enable
cpu_sel : in std_logic; -- Block select cpu_sel : in std_logic; -- Block select
@ -35,56 +35,45 @@ port (
); );
end entity; end entity;
---------------------------------------------------------------- ----------------------------------------------------------------
-- Single channel pulse generator with two RAMs and a FIFO -- Single channel pulse generator with two RAMs
---------------------------------------------------------------- ----------------------------------------------------------------
architecture rtl of qlaser_dacs_pulse_channel is architecture channel of qlaser_dacs_pulse_channel is
-- Constants declearations
constant C_RAM_SELECT : integer := 11; -- Select bit for which RAM for CPU read/write
constant C_NUM_PULSE : integer := 16; -- Number of output data values from pulse RAM (16x24-bit)
-- RAM, pulse position, CPU port, read/write constant C_START_TIME : integer := 24; -- Start time for pulse generation
constant C_NUM_PULSE : integer := 16; -- Number of output data values from pulse RAM (16x24-bit) constant C_BITS_ADDR_START : integer := 12; -- Number of bits for starting address
signal ram_pulse_addra : std_logic_vector( 3 downto 0); -- 16 entry RAM constant C_BITS_ADDR_LENGTH : integer := 10; -- Number of bits for length address used by an edge of a pulse
signal ram_pulse_dina : std_logic_vector(95 downto 0); constant C_BITS_GAIN_FACTOR : integer := 16; -- Number of bits in gain table
signal ram_pulse_douta : std_logic_vector(95 downto 0); constant C_BITS_TIME_FACTOR : integer := 16; -- Number of bits in time table
signal ram_pulse_douta_d1 : std_logic_vector(95 downto 0); -- Delay distrib RAM output to match pipeline of Block RAM constant C_BITS_TIME_INT : integer := 14; -- Starting bit for time integer part of the time factor, counting from MSB
signal ram_pulse_we : std_logic; constant C_BITS_TIME_FRAC : integer := 5; -- Starting bit for time fractional part of the time factor, counting from MSB
constant C_BITS_ADDR_TOP : integer := 17; -- Number of bits for the "flat top", the top of the pulse
-- RAM, pulse position, from state machine constant C_LENGTH_WAVEFORM : integer := 1024; -- Number of output data values from waveform RAM (1024x16-bit)
constant C_BITS_GAIN_FACTOR : integer := 16; -- Number of bits in gain table constant C_BITS_ADDR_WAVE : integer := 10; -- Number of bits in address for waveform RAM
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; constant C_PC_INCR : integer := 4; -- Width of pulse counter increment
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 declarations for pulse RAM
signal cpu_wdata_mid : std_logic_vector(31 downto 0); -- Middle 32 bits of CPU write data (63:32) signal ram_pulse_we : std_logic_vector( 0 downto 0); -- Write enable for pulse RAM
signal ram_pulse_addra : std_logic_vector( 9 downto 0); -- Address for pulse RAM
-- Waveform RAM port connections. signal ram_pulse_dina : std_logic_vector(31 downto 0); -- Data for pulse RAM
-- NOTE: Port A is 32-bit data, port B is 16-bit signal ram_pulse_douta : std_logic_vector(31 downto 0); -- Data out from pulse RAM
constant C_LENGTH_WAVEFORM : integer := 1024; -- Number of output data values from waveform RAM (1024x16-bit) signal ram_pulse_addrb : std_logic_vector( 9 downto 0); -- Address for pulse RAM
constant C_BITS_ADDR_WAVE : integer := 10; -- Number of bits in address for waveform RAM signal ram_pulse_doutb : std_logic_vector(31 downto 0); -- Data out from pulse 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);
-- Signal declarations for waveform RAM
signal ram_waveform_ena : std_logic; -- Enable for waveform RAM
signal ram_waveform_wea : std_logic_vector( 0 downto 0); -- Write enable for waveform RAM
signal ram_waveform_addra : std_logic_vector(10 downto 0); -- Address for waveform RAM
signal ram_waveform_dina : std_logic_vector(31 downto 0); -- Data for waveform RAM
signal ram_waveform_douta : std_logic_vector(31 downto 0); -- Data out from waveform RAM
signal ram_waveform_enb : std_logic; -- Enable for waveform RAM
signal ram_waveform_addrb : std_logic_vector(11 downto 0); -- Address for waveform RAM
signal ram_waveform_doutb : std_logic_vector(15 downto 0); -- Data out from waveform RAM
-- State variable type declaration for main state machine -- State variable type declaration for main state machine
type t_sm_state is ( type t_sm_state is (
@ -96,23 +85,16 @@ type t_sm_state is (
S_WAVE_DOWN -- Output the falling edge of a waveform S_WAVE_DOWN -- Output the falling edge of a waveform
); );
signal sm_state : t_sm_state; signal sm_state : t_sm_state;
signal sm_wavedata : std_logic_vector(15 downto 0); -- Waveform RAM data 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_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 signal sm_busy : std_logic; -- Signal to indicate that s.m. is not idle
-- Misc signals
---- FIFO port connections signal ram_pulse_douta_d1 : std_logic_vector(31 downto 0); -- Delay distrib RAM output to match pipeline of Block RAM
--signal fifo_wr_en : std_logic; signal cpu_rdata_dv_e1 : std_logic;
--signal fifo_full : std_logic; signal cpu_rdata_dv_e2 : std_logic;
--signal fifo_empty : std_logic; signal cpu_rdata_ramsel_d1 : std_logic;
--signal fifo_wr_rst_busy : std_logic; signal cpu_rdata_ramsel_d2 : 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 -- Pipeline delays
signal start_d1 : std_logic; signal start_d1 : std_logic;
@ -120,32 +102,34 @@ signal enable_d1 : std_logic;
begin begin
busy <= sm_busy;
---------------------------------------------------------------- ----------------------------------------------------------------
-- Distributed RAM to hold 16 24-bit Pulse start times. -- Pulse Definition Block RAM.
-- Synch write, Asynch read -- Synch write, Synch read
-- Port A is for CPU read/write. 16x24-bit -- Port A is for CPU read/write. 1024x32-bit
-- Port B is for pulse time data output. 16x24-bit -- Port B is for pulse time data output. 1024x32-bit
---------------------------------------------------------------- ----------------------------------------------------------------
u_ram_pulse : entity work.bram_pulseposition u_ram_pulse : entity work.bram_pulse_definition
port map( port map(
clk => clk , -- input std_logic -- Port A CPU Bus
a => ram_pulse_addra , -- input slv[3:0] clka => clk, -- input std_logic
d => ram_pulse_dina , -- input slv[95 downto 0] wea => ram_pulse_we, -- input slv( 0 to 0 )
we => ram_pulse_we , addra => ram_pulse_addra, -- input slv( 9 downto 0 )
spo => ram_pulse_douta , -- output slv(95 downto 0] dina => ram_pulse_dina, -- input slv( 31 downto 0 )
douta => ram_pulse_douta, -- output slv( 31 downto 0 ),
dpra => ram_pulse_addrb , -- input slv[3:0] -- Port B waveform input
dpo => ram_pulse_doutb -- output slv(95 downto 0) clkb => clk,
web => (others=>'0'),
addrb => ram_pulse_addrb, -- input slv( 9 downto 0 )
dinb => (others=>'0'),
doutb => ram_pulse_doutb -- output slv( 31 downto 0 )
); );
---------------------------------------------------------------- ----------------------------------------------------------------
-- Waveform table Block RAM. -- Waveform table Block RAM.
-- Synch write, Synch read -- Synch write, Synch read
-- Port A is for CPU read/write. 512x32-bit -- Port A is for CPU read/write. 2048x32-bit
-- Port B is for waveform data. 1024x16-bit -- Port B is for waveform data. 4096x16-bit
---------------------------------------------------------------- ----------------------------------------------------------------
u_ram_waveform : entity work.bram_waveform u_ram_waveform : entity work.bram_waveform
port map ( port map (
@ -153,7 +137,7 @@ begin
clka => clk , -- input std_logic clka => clk , -- input std_logic
ena => ram_waveform_ena , -- input std_logic ena => ram_waveform_ena , -- input std_logic
wea => ram_waveform_wea , -- input slv(0 downto 0) wea => ram_waveform_wea , -- input slv(0 downto 0)
addra => ram_waveform_addra , -- input slv(8 downto 0) addra => ram_waveform_addra , -- input slv(10 downto 0)
dina => ram_waveform_dina , -- input slv(31 downto 0) dina => ram_waveform_dina , -- input slv(31 downto 0)
douta => ram_waveform_douta , -- output slv(31 downto 0) douta => ram_waveform_douta , -- output slv(31 downto 0)
@ -161,224 +145,12 @@ begin
clkb => clk , -- input std_logic clkb => clk , -- input std_logic
enb => ram_waveform_enb , -- input std_logic enb => ram_waveform_enb , -- input std_logic
web => (others=>'0') , -- input slv(0 downto 0) web => (others=>'0') , -- input slv(0 downto 0)
addrb => ram_waveform_addrb , -- input slv(9 downto 0) addrb => ram_waveform_addrb , -- input slv(11 downto 0)
dinb => (others=>'0') , -- input slv(15 downto 0) dinb => (others=>'0') , -- input slv(15 downto 0)
doutb => ram_waveform_doutb -- output 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_flattop : std_logic_vector(C_BITS_ADDR_TOP - 1 downto 0); -- wait times (flat_top), managed by an internal counter process sm_top_counter unter state S_WAVE_TOP
variable v_addr_length : std_logic_vector(C_BITS_ADDR_LENGTH - 1 downto 0); -- number of points/addresses used by the pulse edge, the bit width should increase with the amount of addresses the wavetable has
variable v_addr_start : std_logic_vector(C_BITS_ADDR_START - 1 downto 0); -- start address of the pulse edge data in the Waveform RAM, the bit width should increase with the amount of address the wavetable has.
variable v_addr_end : std_logic_vector(C_BITS_ADDR_START - 1 downto 0); -- end address of the pulse edge data in the Waveform RAM, the bit width should align with the bit width of v_addr_start
variable v_amplitude_factor : std_logic_vector(C_BITS_GAIN_FACTOR - 1 downto 0); -- pulse edge amplitude scale factor
variable v_time_factor : std_logic_vector(C_BITS_TIME_FACTOR - 1 downto 0); -- pulse edge time scale factor
variable v_cnt_time : std_logic_vector(23 downto 0); -- counter for the time, the bit width should increase with the amount of addresses the wavetable has
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';
-- Actively read pulse definition RAM and update the variables
v_flattop := ram_pulse_doutb(C_BITS_ADDR_TOP - 1 downto 0);
v_addr_length := ram_pulse_doutb(C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_ADDR_TOP);
v_addr_start := ram_pulse_doutb(C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
v_addr_end := std_logic_vector(unsigned(v_addr_start) + unsigned(v_addr_length) - 1);
v_amplitude_factor := ram_pulse_doutb(C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
v_time_factor := ram_pulse_doutb(C_BITS_TIME_FACTOR + C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
v_cnt_time := ram_pulse_doutb(24 + C_BITS_TIME_FACTOR + C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_TIME_FACTOR + C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
------------------------------------------------------------------------
-- 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 (v_cnt_time = 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 <= v_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 = v_addr_end) 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 , and increment the address
-- TODO: apply scaling factor to the address and then to the output
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1);
end if;
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- Hold the last address and output its data
-- decrement from this address when finished waiting
------------------------------------------------------------------------
when S_WAVE_FLAT =>
if (cnt_wave_top = v_flattop) then
sm_state <= S_WAVE_DOWN;
else
cnt_wave_top <= std_logic_vector(unsigned(cnt_wave_top) + 1);
end if;
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- Output the falling edge of a waveform
-- Hold the start address when complete
------------------------------------------------------------------------
when S_WAVE_DOWN =>
-- End of waveform?
if (ram_waveform_addrb = v_addr_start) 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,4))) then
ram_pulse_addrb <= (others=>'0');
sm_state <= S_IDLE;
else -- increment pulse address for the next waveform
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
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) - 1);
end if;
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- 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 -- CPU Read/Write RAM
-- MSB of cpu_addr is used to select one of the two RAMs -- 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. -- to read/write, and the remainder are a 9-bit or 4-bit RAM address.
@ -389,7 +161,7 @@ begin
ram_pulse_addra <= (others=>'0'); ram_pulse_addra <= (others=>'0');
ram_pulse_dina <= (others=>'0'); ram_pulse_dina <= (others=>'0');
ram_pulse_we <= '0'; ram_pulse_we <= (others=>'0');
ram_waveform_ena <= '0'; ram_waveform_ena <= '0';
ram_waveform_wea <= (others=>'0'); ram_waveform_wea <= (others=>'0');
@ -412,32 +184,23 @@ begin
------------------------------------------------- -------------------------------------------------
if (cpu_wr = '1') and (cpu_sel = '1') then if (cpu_wr = '1') and (cpu_sel = '1') then
-- 0 for pulse position, 1 for waveform table -- 0 for pulse definition, 1 for waveform table
if (cpu_addr(9) = '1') then if (cpu_addr(9) = '1') then
ram_pulse_addra <= (others=>'0'); ram_pulse_addra <= (others=>'0');
ram_pulse_dina <= (others=>'0'); ram_pulse_dina <= (others=>'0');
ram_pulse_we <= '0'; ram_pulse_we <= (others=>'0');
ram_waveform_wea(0) <= '1'; ram_waveform_wea(0) <= '1';
ram_waveform_ena <= '1'; ram_waveform_ena <= '1';
ram_waveform_addra <= cpu_addr(8 downto 0); ram_waveform_addra <= cpu_addr(10 downto 0);
ram_waveform_dina <= cpu_wdata; ram_waveform_dina <= cpu_wdata;
else else
ram_pulse_addra <= cpu_addr(5 downto 2); ram_pulse_addra <= cpu_addr(9 downto 0);
-- select which part of the 96-bit data to write ram_pulse_dina <= cpu_wdata;
if (cpu_addr(1 downto 0) = "00") then ram_pulse_we <= std_logic_vector(to_unsigned(1, ram_pulse_we'length));
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_ena <= '0';
ram_waveform_wea <= (others=>'0'); ram_waveform_wea <= (others=>'0');
ram_waveform_addra <= (others=>'0'); ram_waveform_addra <= (others=>'0');
@ -456,17 +219,17 @@ begin
------------------------------------------------- -------------------------------------------------
elsif (cpu_wr = '0') and (cpu_sel = '1') then elsif (cpu_wr = '0') and (cpu_sel = '1') then
if (cpu_addr(9) = '1') then -- Waveform if (cpu_addr(C_RAM_SELECT) = '1') then -- Waveform
ram_waveform_ena <= '1'; ram_waveform_ena <= '1';
ram_pulse_addra <= (others=>'0'); ram_pulse_addra <= (others=>'0');
ram_waveform_addra <= cpu_addr(8 downto 0); ram_waveform_addra <= cpu_addr(10 downto 0);
else -- Pulse else -- Pulse
ram_pulse_addra <= cpu_addr(5 downto 2); ram_pulse_addra <= cpu_addr(9 downto 0);
ram_pulse_douta_d1 <= ram_pulse_douta; -- Delay distrib RAM output to match pipeline of Block RAM ram_pulse_douta_d1 <= ram_pulse_douta; -- Delay distrib RAM output to match pipeline of Block RAM
ram_waveform_addra <= (others=>'0'); ram_waveform_addra <= (others=>'0');
end if; end if;
ram_pulse_we <= '0'; ram_pulse_we <= (others=>'0');
ram_waveform_wea(0) <= '0'; ram_waveform_wea(0) <= '0';
cpu_rdata_dv_e2 <= '1'; -- DV for cycle, when RAM output occurs cpu_rdata_dv_e2 <= '1'; -- DV for cycle, when RAM output occurs
@ -476,7 +239,7 @@ begin
else else
ram_pulse_addra <= (others=>'0'); ram_pulse_addra <= (others=>'0');
ram_pulse_we <= '0'; ram_pulse_we <= (others=>'0');
ram_waveform_addra <= (others=>'0'); ram_waveform_addra <= (others=>'0');
ram_waveform_wea(0) <= '0'; ram_waveform_wea(0) <= '0';
@ -501,16 +264,7 @@ begin
cpu_rdata <= ram_waveform_douta; cpu_rdata <= ram_waveform_douta;
elsif (cpu_rdata_ramsel_d2 = '0') then elsif (cpu_rdata_ramsel_d2 = '0') then
-- cpu_rdata <= X"00" & ram_pulse_douta_d1; cpu_rdata <= 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; end if;
else else
@ -521,86 +275,4 @@ begin
end if; end if;
end process; end process;
end channel;
-- ----------------------------------------------------------------
-- -- 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;

View File

@ -0,0 +1,606 @@
---------------------------------------------------------------
-- 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_flattop : std_logic_vector(C_BITS_ADDR_TOP - 1 downto 0); -- wait times (flat_top), managed by an internal counter process sm_top_counter unter state S_WAVE_TOP
variable v_addr_length : std_logic_vector(C_BITS_ADDR_LENGTH - 1 downto 0); -- number of points/addresses used by the pulse edge, the bit width should increase with the amount of addresses the wavetable has
variable v_addr_start : std_logic_vector(C_BITS_ADDR_START - 1 downto 0); -- start address of the pulse edge data in the Waveform RAM, the bit width should increase with the amount of address the wavetable has.
variable v_addr_end : std_logic_vector(C_BITS_ADDR_START - 1 downto 0); -- end address of the pulse edge data in the Waveform RAM, the bit width should align with the bit width of v_addr_start
variable v_amplitude_factor : std_logic_vector(C_BITS_GAIN_FACTOR - 1 downto 0); -- pulse edge amplitude scale factor
variable v_time_factor : std_logic_vector(C_BITS_TIME_FACTOR - 1 downto 0); -- pulse edge time scale factor
variable v_cnt_time : std_logic_vector(23 downto 0); -- counter for the time, the bit width should increase with the amount of addresses the wavetable has
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';
-- Actively read pulse definition RAM and update the variables
v_flattop := ram_pulse_doutb(C_BITS_ADDR_TOP - 1 downto 0);
v_addr_length := ram_pulse_doutb(C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_ADDR_TOP);
v_addr_start := ram_pulse_doutb(C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
v_addr_end := std_logic_vector(unsigned(v_addr_start) + unsigned(v_addr_length) - 1);
v_amplitude_factor := ram_pulse_doutb(C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
v_time_factor := ram_pulse_doutb(C_BITS_TIME_FACTOR + C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
v_cnt_time := ram_pulse_doutb(24 + C_BITS_TIME_FACTOR + C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP - 1 downto C_BITS_TIME_FACTOR + C_BITS_GAIN_FACTOR + C_BITS_ADDR_START + C_BITS_ADDR_LENGTH + C_BITS_ADDR_TOP);
------------------------------------------------------------------------
-- 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 (v_cnt_time = 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 <= v_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 = v_addr_end) 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 , and increment the address
-- TODO: apply scaling factor to the address and then to the output
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1);
end if;
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- Hold the last address and output its data
-- decrement from this address when finished waiting
------------------------------------------------------------------------
when S_WAVE_FLAT =>
if (cnt_wave_top = v_flattop) then
sm_state <= S_WAVE_DOWN;
else
cnt_wave_top <= std_logic_vector(unsigned(cnt_wave_top) + 1);
end if;
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- Output the falling edge of a waveform
-- Hold the start address when complete
------------------------------------------------------------------------
when S_WAVE_DOWN =>
-- End of waveform?
if (ram_waveform_addrb = v_addr_start) 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,4))) then
ram_pulse_addrb <= (others=>'0');
sm_state <= S_IDLE;
else -- increment pulse address for the next waveform
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
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) - 1);
end if;
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- 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;

View File

@ -105,10 +105,10 @@ procedure cpu_write_pulsedef(
signal cpu_wdata : out std_logic_vector(31 downto 0) signal cpu_wdata : out std_logic_vector(31 downto 0)
) is ) is
-- Vectors for converted values -- Vectors for converted values
variable slv_pulsetime : std_logic_vector(23 downto 0); -- For 24-bit pulse time variable slv_pulsetime : std_logic_vector(26 downto 0); -- For 27-bit pulse time
variable slv_timefactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point timestep 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_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_wavestartaddr : std_logic_vector(11 downto 0); -- For 12-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_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_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit number of clock cycles in top of waveform
@ -120,10 +120,10 @@ constant BIT_FRAC : integer := 4; -- TODO: this should be defined in qlaser_pkg
begin begin
-- Convert each field into its std_logic_vector equivalent -- Convert each field into its std_logic_vector equivalent
slv_pulsetime := std_logic_vector(to_unsigned(pulsetime, 24)); slv_pulsetime := std_logic_vector(to_unsigned(pulsetime, 27));
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_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_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_wavestartaddr := std_logic_vector(to_unsigned(wavestartaddr, 12));
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10)); slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17)); slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
@ -131,12 +131,13 @@ begin
--etc, etc. --etc, etc.
-- Build full entry out of component fields. Final length should be 96 bits. -- 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 -- 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) -- -- 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) , 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)+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); -- cpu_write(clk, ADR_RAM_PULSE+(4*num_entry)+2 , slv_entry_data(95 downto 64), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- Write 32-bit entry in
end; end;
------------------------------------------------------------- -------------------------------------------------------------
@ -300,7 +301,7 @@ begin
-- CPU interface -- CPU interface
cpu_wr => cpu_wr , -- in std_logic; cpu_wr => cpu_wr , -- in std_logic;
cpu_sel => cpu_sel , -- 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_addr => cpu_addr(11 downto 0) , -- in std_logic_vector(11 downto 0);
cpu_wdata => cpu_wdata , -- in std_logic_vector(31 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 => cpu_rdata , -- out std_logic_vector(31 downto 0);

View File

@ -0,0 +1,428 @@
-----------------------------------------------------------
-- 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 := to_integer(unsigned(X"0000")); -- TODO: Modelsim cannot compile this
-- constant ADR_RAM_WAVE : integer := to_integer(unsigned(X"0200")); -- TODO: Modelsim cannot compile this
constant ADR_RAM_PULSE : integer := 0; -- TODO: Modelsim cannot compile this
constant ADR_RAM_WAVE : integer := 2048; -- TODO: Modelsim cannot compile this
-------------------------------------------------------------
-- 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 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 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(11 downto 0); -- For 12-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
-- 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, 12));
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
--etc, etc.
-- 4 writes. (Address is an integer)
cpu_write(clk, ADR_RAM_PULSE+num_entry , x"00" & slv_pulsetime, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+1) , "00" & x"00" & slv_wavesteps & slv_wavestartaddr, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+2) , slv_timefactor & slv_gainfactor, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+3) , "0000000" & x"00" & slv_wavetopwidth, 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(11 downto 0); -- For 12-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
-- 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, 12));
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
--etc, etc.
-- 4 writes. (Address is an integer)
cpu_write(clk, ADR_RAM_PULSE+num_entry , x"00" & slv_pulsetime, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+1) , "00" & x"00" & slv_wavesteps & slv_wavestartaddr, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+2) , slv_timefactor & slv_gainfactor, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+3) , "0000000" & x"00" & slv_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
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(11 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 255 loop
cpu_write_pulsedef(clk, NADDR*4, 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);
-- ----------------------------------------------------------------
-- -- Load waveform RAM with a simple ramp
-- -- Write two 16-bit values with each write
-- ----------------------------------------------------------------
-- cpu_print_msg("Load waveform RAM");
-- v_ndata16 := 1; -- first waveform value
-- for NADDR in 0 to 511 loop
-- v_ndata32 := (((v_ndata16+1) * 65536) + v_ndata16);
-- cpu_write(clk, (ADR_RAM_WAVE + NADDR) , v_ndata32, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- v_ndata16 := v_ndata16 + 2;
-- end loop;
-- cpu_print_msg("Waveform RAM loaded");
-- clk_delay(20);
----------------------------------------------------------------
-- Read back Pulse RAM.
----------------------------------------------------------------
v_ndata32 := 128; -- Time for first pulse
for NADDR in 0 to 255 loop
cpu_read_pulsedef(clk, NADDR*4, 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);
-- ----------------------------------------------------------------
-- -- Read back Waveform RAM
-- ----------------------------------------------------------------
-- v_ndata16 := 1; -- first waveform value
-- for NADDR in 0 to 511 loop
-- v_ndata32 := (((v_ndata16+1) * 65536) + v_ndata16);
-- cpu_read (clk, ADR_RAM_WAVE + NADDR , std_logic_vector(to_unsigned(v_ndata32, 32)) , cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
-- v_ndata16 := v_ndata16 + 2;
-- end loop;
-- Done reg write/read check
cpu_print_msg("RAM readback completed");
clk_delay(20);
----------------------------------------------------------------
-- Start the pulse outputs
----------------------------------------------------------------
clk_delay(5);
start <= '1';
clk_delay(5);
start <= '0';
-- Wait for cnt_time to reach last pulse start time + waveform size
for NCNT in 1 to (128 + 16*(1024+32)+ 1024) loop
cnt_time <= std_logic_vector(unsigned(cnt_time) + 1);
clk_delay(0);
end loop;
wait for 10 us;
cpu_print_msg("Simulation done");
clk_delay(5);
sim_done <= true;
wait;
end process;
end behave;

View File

@ -22,4 +22,20 @@ launch_runs synth_1
# Wait for the synthesis to complete # Wait for the synthesis to complete
wait_on_run synth_1 wait_on_run synth_1
# Generate the simulation models
proc recursive_glob {dir} {
set files [glob -nocomplain -type f -directory $dir *_sim_netlist.vhdl]
foreach subdir [glob -nocomplain -type d -directory $dir *] {
lappend files {*}[recursive_glob $subdir]
}
return $files
}
set src_dir ../../prj/zcu_pulse_channel.gen/sources_1/ip/
set files [recursive_glob $src_dir]
foreach file $files {
file copy -force $file ../../src/hdl/ip_gen
}
exit exit

View File

@ -1,20 +1,5 @@
vlib work vlib work
# proc recursive_glob {dir} {
# set files [glob -nocomplain -type f -directory $dir *_sim_netlist.vhdl]
# foreach subdir [glob -nocomplain -type d -directory $dir *] {
# lappend files {*}[recursive_glob $subdir]
# }
# return $files
# }
# set src_dir ../../prj/zcu_pulse_channel.gen
# set files [recursive_glob $src_dir]
# foreach file $files {
# file copy -force $file ../../src/hdl/ip_gen
# }
vcom ../../src/hdl/ip_gen/*.vhd* vcom ../../src/hdl/ip_gen/*.vhd*
vcom ../../src/hdl/pkg/*pkg.vhd vcom ../../src/hdl/pkg/*pkg.vhd
vcom ../../src/hdl/pkg/iopakp.vhd vcom ../../src/hdl/pkg/iopakp.vhd

View File

@ -254,10 +254,10 @@
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.IPCONTEXT">IP_Flow</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.IPCONTEXT">IP_Flow</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.IPREVISION">5</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.IPREVISION">5</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.MANAGED">TRUE</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.MANAGED">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../../zcu_pulse_channel.gen/sources_1/ip/bram_pulse_definition</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/bram_pulse_definition</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1.2</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue>
</spirit:configurableElementValues> </spirit:configurableElementValues>
<spirit:vendorExtensions> <spirit:vendorExtensions>

View File

@ -86,7 +86,7 @@
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/bram_pulseposition</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/bram_pulseposition</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1.2</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue>
</spirit:configurableElementValues> </spirit:configurableElementValues>
<spirit:vendorExtensions> <spirit:vendorExtensions>

View File

@ -257,7 +257,7 @@
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/bram_waveform</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/bram_waveform</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1.2</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue>
</spirit:configurableElementValues> </spirit:configurableElementValues>
<spirit:vendorExtensions> <spirit:vendorExtensions>

View File

@ -524,7 +524,7 @@
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/fifo_data_to_stream</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">../../../prj/zcu_pulse_channel.gen/sources_1/ip/fifo_data_to_stream</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1.2</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2022.1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue>
</spirit:configurableElementValues> </spirit:configurableElementValues>
<spirit:vendorExtensions> <spirit:vendorExtensions>