unchecked updated main module cpu rw and its tb
This commit is contained in:
parent
c5f60594ac
commit
bad218fbf3
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
|
@ -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;
|
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue