Compare commits

..

No commits in common. "v_amp_scale" and "main" have entirely different histories.

18 changed files with 6754 additions and 7475 deletions

1
.gitignore vendored
View File

@ -2,7 +2,6 @@
*.jou *.jou
*.ini *.ini
*.wlf *.wlf
*.vstf
wlft* wlft*
work work
transcript transcript

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,6 @@ port (
cnt_time : in std_logic_vector(23 downto 0); -- Time since trigger. cnt_time : in std_logic_vector(23 downto 0); -- Time since trigger.
busy : out std_logic; -- Status signal busy : out std_logic; -- Status signal
-- TODO: Add another status signal to indicate any errors?
-- CPU interface -- CPU interface
cpu_addr : in std_logic_vector(11 downto 0); -- Address input cpu_addr : in std_logic_vector(11 downto 0); -- Address input
@ -92,8 +91,8 @@ 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
signal cnt_wave_len : unsigned(C_BITS_ADDR_LENGTH - 1 downto 0); -- Counter used for incremnet/decrement wave table addresses signal cnt_wave_len : std_logic_vector(C_BITS_ADDR_LENGTH - 1 downto 0); -- Counter used for incremnet/decrement wave table addresses
signal cnt_wave_top : unsigned(C_BITS_ADDR_TOP - 1 downto 0); -- Counter for the flat top of the waveform signal cnt_wave_top : std_logic_vector(C_BITS_ADDR_TOP - 1 downto 0); -- Counter for the flat top of the waveform
-- Misc signals -- Misc signals
signal cpu_rdata_dv_e1 : std_logic; signal cpu_rdata_dv_e1 : std_logic;
@ -112,11 +111,9 @@ signal pc : std_logic_vector(C_BITS_ADDR_PULSE - 1 downto 0);
-- 4. Flat-top 17-bit. [16:0] -- 4. Flat-top 17-bit. [16:0]
---------------------------------------------------------------- ----------------------------------------------------------------
signal reg_pulse_time : std_logic_vector(31 downto 0); -- first register which stores the pulse's start time signal reg_pulse_time : std_logic_vector(31 downto 0); -- first register which stores the pulse's start time
signal reg_wave_start_addr : std_logic_vector(C_BITS_ADDR_START -1 downto 0); -- the start address of the wavetable signal reg_pulse_sizes : std_logic_vector(31 downto 0); -- second register which stores the pulse's length, the bit width should increase with the amount of addresses the wavetable has, and its start address
signal reg_wave_length : unsigned( 9 downto 0); -- the length of the wavetable signal reg_pulse_factors : std_logic_vector(31 downto 0); -- third register which stores the pulse's amplitude and time scale factors
signal reg_scale_gain : unsigned(15 downto 0); -- scale factor for the gain, amplitude signal reg_pulse_flattop : std_logic_vector(31 downto 0); -- fourth register which stores the pulse's flat top value
signal reg_scale_time : unsigned(15 downto 0); -- scale factor for the time, length
signal reg_pulse_flattop : unsigned(C_BITS_ADDR_TOP - 1 downto 0); -- fourth register which stores the pulse's flat top value
-- Pipeline delays -- Pipeline delays
signal start_d1 : std_logic; signal start_d1 : std_logic;
@ -301,8 +298,7 @@ begin
-- or until the maximum counter time has been reached. -- or until the maximum counter time has been reached.
---------------------------------------------------------------- ----------------------------------------------------------------
pr_sm : process (reset, clk) pr_sm : process (reset, clk)
-- Temp variables for waveform output
variable v_ram_waveform_doutb_multiplied : std_logic_vector(C_BITS_GAIN_FACTOR + 15 downto 0);
begin begin
if (reset = '1') then if (reset = '1') then
@ -313,11 +309,10 @@ begin
sm_wavedata <= (others=>'0'); sm_wavedata <= (others=>'0');
sm_wavedata_dv <= '0'; sm_wavedata_dv <= '0';
sm_busy <= '0'; sm_busy <= '0';
reg_wave_start_addr <= (others=>'0');
reg_wave_length <= (others=>'0');
reg_scale_gain <= (others=>'0');
reg_scale_time <= (others=>'0');
reg_pulse_time <= (others=>'0'); reg_pulse_time <= (others=>'0');
reg_pulse_sizes <= (others=>'0');
reg_pulse_factors <= (others=>'0');
reg_pulse_flattop <= (others=>'0'); reg_pulse_flattop <= (others=>'0');
pc <= (others=>'0'); pc <= (others=>'0');
@ -353,7 +348,7 @@ begin
sm_wavedata_dv <= '1'; sm_wavedata_dv <= '1';
sm_state <= S_IDLE; sm_state <= S_IDLE;
end if; end if;
sm_busy <= '0'; sm_busy <= '0';
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Wait for rising edge of 'start'. -- Wait for rising edge of 'start'.
@ -374,16 +369,21 @@ begin
when S_LOAD => when S_LOAD =>
-- TODO: Eric: does is needed here? or should be inside the if-else loops -- TODO: Eric: does is needed here? or should be inside the if-else loops
-- Load the pulse channel RAM addresses and start the waveform output -- Load the pulse channel RAM addresses and start the waveform output
sm_busy <= '1'; sm_busy <= '1';
-- Pipline the pulse definition address -- Pipline the pulse definition address
-- TODO: is it better to make a counter to count the quarter or just mod 4?
-- TODO: maybe C-slow around the pulse ram to get it down to 1 cycle??
if (unsigned(ram_pulse_addrb) mod 4 = 0) then if (unsigned(ram_pulse_addrb) mod 4 = 0) then
ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 1); ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 1);
sm_state <= S_LOAD; sm_state <= S_LOAD;
-- first quarter of the pulse definition, no register is loaded -- first quarter of the pulse definition, no register is loaded
-- reg_pulse_time <= ram_pulse_doutb;
elsif (unsigned(ram_pulse_addrb) mod 4 = 1) then elsif (unsigned(ram_pulse_addrb) mod 4 = 1) then
ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 2); ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 2);
sm_state <= S_LOAD; sm_state <= S_LOAD;
-- reg_pulse_sizes <= ram_pulse_doutb;
-- second quarter of the pulse definition, the start time is loaded -- second quarter of the pulse definition, the start time is loaded
reg_pulse_time <= ram_pulse_doutb; reg_pulse_time <= ram_pulse_doutb;
@ -391,17 +391,19 @@ begin
elsif (unsigned(ram_pulse_addrb) mod 4 = 2) then elsif (unsigned(ram_pulse_addrb) mod 4 = 2) then
ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 3); ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 3);
sm_state <= S_LOAD; sm_state <= S_LOAD;
-- reg_pulse_factors <= ram_pulse_doutb;
-- third quarter of the pulse definition, the length and start address of the wavetable are loaded -- third quarter of the pulse definition, the length and start address of the wavetable are loaded
reg_wave_start_addr <= ram_pulse_doutb(C_BITS_ADDR_START - 1 downto 0); reg_pulse_sizes <= ram_pulse_doutb;
reg_wave_length <= unsigned(ram_pulse_doutb(25 downto 16)); -- TODO: make this a constant
elsif (unsigned(ram_pulse_addrb) mod 4 = 3) then elsif (unsigned(ram_pulse_addrb) mod 4 = 3) then
-- ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 4);
sm_state <= S_WAIT; -- address is on the forth word of the entry, the loading process is complete. Moving onto the next state sm_state <= S_WAIT; -- address is on the forth word of the entry, the loading process is complete. Moving onto the next state
-- hold the last pulse definition address as it will be used in the next state -- hold the last pulse definition address as it will be used in the next state
-- reg_pulse_flattop <= ram_pulse_doutb;
pc <= std_logic_vector(unsigned(pc) + C_PC_INCR); -- incremnet the pulse counter and start waiting to output the wave pc <= std_logic_vector(unsigned(pc) + C_PC_INCR); -- incremnet the pulse counter and start waiting to output the wave
-- forth quarter of the pulse definition, the scale factors are loaded -- forth quarter of the pulse definition, the scale factors are loaded
reg_scale_gain <= unsigned(ram_pulse_doutb(31 downto 16)); reg_pulse_factors <= ram_pulse_doutb;
reg_scale_time <= unsigned(ram_pulse_doutb(15 downto 0));
end if; end if;
@ -418,12 +420,12 @@ begin
------------------------------------------------------------------------ ------------------------------------------------------------------------
when S_WAIT => when S_WAIT =>
-- read the last word of the pulse definition, the flat top value -- read the last word of the pulse definition, the flat top value
reg_pulse_flattop <= unsigned(ram_pulse_doutb(C_BITS_ADDR_TOP - 1 downto 0)); reg_pulse_flattop <= ram_pulse_doutb;
-- Start to output wave and increment pulse position RAM address -- Start to output wave and increment pulse position RAM address
if (reg_pulse_time(C_START_TIME - 1 downto 0) = cnt_time) then if (reg_pulse_time(C_START_TIME - 1 downto 0) = cnt_time) then
sm_state <= S_WAVE_UP; sm_state <= S_WAVE_UP;
-- set the wavetable's address to the starting address defined from the pulse ram -- set the wavetable's address to the starting address defined from the pulse ram
ram_waveform_addrb <= reg_wave_start_addr; ram_waveform_addrb <= reg_pulse_sizes(C_BITS_ADDR_START - 1 downto 0);
-- reset the wave lenth counter -- reset the wave lenth counter
cnt_wave_len <= (others=>'0'); cnt_wave_len <= (others=>'0');
elsif (cnt_time = X"FFFFFF") then elsif (cnt_time = X"FFFFFF") then
@ -438,32 +440,18 @@ begin
when S_WAVE_UP => when S_WAVE_UP =>
-- Check if is end of rise of the waveform, and hold the address -- Check if is end of rise of the waveform, and hold the address
-- TODO: convert the numbers below to constaint. right now just make sure I'm not confused -- TODO: convert the numbers below to constaint. right now just make sure I'm not confused
if (cnt_wave_len = reg_wave_length) then if (cnt_wave_len = reg_pulse_sizes(25 downto 16)) then
-- skip the flat top state if the flat top value is zero sm_state <= S_WAVE_FLAT;
if (reg_pulse_flattop = 0) then -- reset counters for transitions
sm_state <= S_WAVE_DOWN; cnt_wave_len <= (others=>'0');
-- reset the counter for the next transition cnt_wave_top <= (others=>'0');
cnt_wave_len <= (others=>'0');
else
sm_state <= S_WAVE_FLAT;
-- reset the counter for the next transition
cnt_wave_len <= (others=>'0');
cnt_wave_top <= (others=>'0');
end if;
-- -- reset counters for transitions
-- cnt_wave_len <= (others=>'0');
-- cnt_wave_top <= (others=>'0');
else else
cnt_wave_len <= cnt_wave_len + 1; cnt_wave_len <= std_logic_vector(unsigned(cnt_wave_len) + 1);
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1); ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1);
end if; end if;
-- sm_wavedata <= std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain)(31 downto 16); sm_wavedata <= ram_waveform_doutb;
-- Modelsim Cannot synthesize this above line, so we *have to* seperate them into two lines sm_wavedata_dv <= '1';
-- # ** Error: Prefix of slice name cannot be type conversion (STD_LOGIC_VECTOR) expression.
v_ram_waveform_doutb_multiplied := std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain);
sm_wavedata <= v_ram_waveform_doutb_multiplied(30 downto 15);
sm_wavedata_dv <= '1';
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Hold the last address and output its data -- Hold the last address and output its data
@ -471,16 +459,15 @@ begin
------------------------------------------------------------------------ ------------------------------------------------------------------------
when S_WAVE_FLAT => when S_WAVE_FLAT =>
-- count the 17-bit flat top, if the counter reaches the flat top value, then go to the next state -- count the 17-bit flat top, if the counter reaches the flat top value, then go to the next state
if (cnt_wave_top = reg_pulse_flattop) then if (cnt_wave_top = reg_pulse_flattop(C_BITS_ADDR_TOP - 1 downto 0)) then
sm_state <= S_WAVE_DOWN; sm_state <= S_WAVE_DOWN;
-- reset the counter for the next transition -- reset the counter for the next transition
cnt_wave_top <= (others=>'0'); cnt_wave_top <= (others=>'0');
else else
cnt_wave_top <= cnt_wave_top + 1; cnt_wave_top <= std_logic_vector(unsigned(cnt_wave_top) + 1);
end if; end if;
v_ram_waveform_doutb_multiplied := std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain); sm_wavedata <= ram_waveform_doutb;
sm_wavedata <= v_ram_waveform_doutb_multiplied(30 downto 15); sm_wavedata_dv <= '1';
sm_wavedata_dv <= '1';
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Output the falling edge of a waveform -- Output the falling edge of a waveform
@ -490,7 +477,7 @@ begin
-- End of waveform? -- End of waveform?
-- TODO: convert the numbers below to constaint. right now just make sure I'm not confused -- TODO: convert the numbers below to constaint. right now just make sure I'm not confused
if (cnt_wave_len = reg_wave_length) then if (cnt_wave_len = reg_pulse_sizes(25 downto 16)) then
-- If the end of the pulse table is reached then go to idle, increment pulse address for the next waveform otherwise -- If the end of the pulse table is reached then go to idle, increment pulse address for the next waveform otherwise
if (ram_pulse_addrb = std_logic_vector(to_unsigned(C_LEN_PULSE-1, C_BITS_ADDR_PULSE))) then if (ram_pulse_addrb = std_logic_vector(to_unsigned(C_LEN_PULSE-1, C_BITS_ADDR_PULSE))) then
@ -507,31 +494,20 @@ begin
-- Output waveform from RAM with decremented address -- Output waveform from RAM with decremented address
else else
cnt_wave_len <= cnt_wave_len + 1; cnt_wave_len <= std_logic_vector(unsigned(cnt_wave_len) + 1);
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) - 1); ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) - 1);
end if; end if;
v_ram_waveform_doutb_multiplied := std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain); sm_wavedata <= ram_waveform_doutb;
sm_wavedata <= v_ram_waveform_doutb_multiplied(30 downto 15); sm_wavedata_dv <= '1';
sm_wavedata_dv <= '1';
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Default -- Default
------------------------------------------------------------------------ ------------------------------------------------------------------------
when others => when others =>
sm_state <= S_IDLE; sm_state <= S_IDLE;
end case; end case;
end if; end if;
end process; 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
-- TODO: data valid bit is not aligned with the data
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
end channel; end channel;

View File

@ -1,35 +0,0 @@
----------------------------------------------------------------------------------------
-- Project : qlaser FPGA
-- File : qlaser_dacs_pulse_channel.vhd
-- Description : Pulse Channel package file specifying constants
-- Author : eyhc
----------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
package qlaser_dacs_pulse_channel_pkg 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)
constant C_START_TIME : integer := 24; -- Start time for pulse generation
constant C_BITS_ADDR_START : integer := 12; -- 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_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_TOP : integer := 17; -- Number of bits for the "flat top", the top of the pulse
constant C_LENGTH_WAVEFORM : integer := 4096; -- Number of output data values from waveform RAM (4kx16-bit)
constant C_BITS_ADDR_WAVE : integer := 16; -- Number of bits in address for waveform RAM
constant C_BITS_ADDR_PULSE : integer := 10; -- Number of bits in address for pulse definition RAM
constant C_LEN_PULSE : integer := 2**C_BITS_ADDR_PULSE; -- Numbers of address for pulse definition RAM
constant C_PC_INCR : integer := 4;
-- Width of pulse counter increment
constant BIT_FRAC : integer := 4; -- Define the number of fractional bits
constant BIT_FRAC_GAIN : integer := C_BITS_GAIN_FACTOR - 1; -- Define the number of fractional bits of the gain
end package qlaser_dacs_pulse_channel_pkg;

View File

@ -14,7 +14,6 @@ use ieee.std_logic_1164.all;
use std.textio.all; use std.textio.all;
use work.std_iopak.all; use work.std_iopak.all;
use work.qlaser_dacs_pulse_channel_pkg.all;
entity tb_cpubus_dacs_pulse_channel is entity tb_cpubus_dacs_pulse_channel is
@ -132,12 +131,13 @@ variable slv_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit numb
-- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg -- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg
-- Define the number of fractional bits -- Define the number of fractional bits
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, 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_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_GAIN)), 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_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));
@ -146,8 +146,8 @@ begin
--etc, etc. --etc, etc.
-- 4 writes. (Address is an integer) -- 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 , x"00" & slv_pulsetime, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(num_entry+1) , "00" & x"0" & slv_wavesteps & x"0" & slv_wavestartaddr, 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_gainfactor & slv_timefactor, 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); cpu_write(clk, ADR_RAM_PULSE+(num_entry+3) , "0000000" & x"00" & slv_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
end; end;
@ -224,12 +224,13 @@ variable slv_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit numb
-- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg -- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg
-- Define the number of fractional bits -- Define the number of fractional bits
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, 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_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_GAIN)), 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_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));
@ -239,7 +240,7 @@ begin
-- 4 writes. (Address is an integer) -- 4 writes. (Address is an integer)
cpu_read(clk, ADR_RAM_PULSE+num_entry, x"00" & slv_pulsetime, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv); cpu_read(clk, ADR_RAM_PULSE+num_entry, x"00" & slv_pulsetime, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
cpu_read(clk, ADR_RAM_PULSE+(num_entry+1), "00" & x"00" & slv_wavesteps & slv_wavestartaddr, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv); cpu_read(clk, ADR_RAM_PULSE+(num_entry+1), "00" & x"00" & slv_wavesteps & slv_wavestartaddr, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
cpu_read(clk, ADR_RAM_PULSE+(num_entry+2), slv_gainfactor & slv_timefactor, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv); cpu_read(clk, ADR_RAM_PULSE+(num_entry+2), slv_timefactor & slv_gainfactor, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
cpu_read(clk, ADR_RAM_PULSE+(num_entry+3), "0000000" & x"00" & slv_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv); cpu_read(clk, ADR_RAM_PULSE+(num_entry+3), "0000000" & x"00" & slv_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
end; end;
@ -324,19 +325,8 @@ begin
-- Reset and drive CPU bus -- Reset and drive CPU bus
------------------------------------------------------------- -------------------------------------------------------------
pr_main : process pr_main : process
variable v_ndata32 : integer := 0; variable v_ndata32 : integer := 0;
variable v_ndata16 : integer := 0; variable v_ndata16 : integer := 0;
-- "global" variables for base definitions of each pulses, all pulses are based on these but scaled/offset a bit
variable v_pulseaddr : integer := 0; -- manually set the pulse address, 0 to 255
variable v_waveaddr : integer := 0; -- manually set the wave address, 0 to 2047
variable v_pulsetime : integer := 0; -- For 24-bit pulse time
variable v_timefactor : real := 0.0; -- For 16-bit fixed point timestep
variable v_gainfactor : real := 0.0; -- For 16-bit fixed point gain
variable v_wavestartaddr : integer := 0; -- For 12-bit address i.e. 1024 point waveform RAM
variable v_wavesteps : integer := 0; -- For 10-bit number of steps i.e. 0 = 1 step, X"3FF" = 1024 points
variable v_wavetopwidth : integer := 0; -- For 17-bit number of clock cycles in top of waveform
begin begin
-- Reset -- Reset
reset <= '1'; reset <= '1';
@ -365,41 +355,9 @@ begin
---------------------------------------------------------------- ----------------------------------------------------------------
v_ndata32 := 128; -- Time for first pulse v_ndata32 := 128; -- Time for first pulse
cpu_print_msg("Load pulse RAM"); cpu_print_msg("Load pulse RAM");
-- for NADDR in 0 to 255 loop for NADDR in 0 to 255 loop
-- -- TODO: In the real setting should we have the python script to check those parameters to make sure they are valid and non-overlapping? cpu_write_pulsedef(clk, NADDR*4, v_ndata32 + (NADDR*(1024+32)), 1.0, 1.0, 0, NADDR*32, 128, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- v_pulsetime := v_ndata32 + (NADDR*(4096+32)); -- todo: what is this math doing? end loop;
-- v_timefactor := 1.0;
-- v_gainfactor := 1.0/real(NADDR + 1);
-- v_wavestartaddr := 0; -- TODO: EricToGeoff/Sara: I assume we want starting address of each wave to be different and non-overlapping, right?
-- v_wavesteps := NADDR*32;
-- v_wavetopwidth := NADDR;
-- -- cpu_write_pulsedef(clk, NADDR*4, v_ndata32 + (NADDR*(1024+32)), 1.0, 1.0, 0, NADDR*32, 128, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- cpu_write_pulsedef(clk, NADDR*4, v_pulsetime, v_timefactor, v_gainfactor, v_wavestartaddr, v_wavesteps, v_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- end loop;
----------------------------------------------------------------
-- Load pulse RAM with a series of pulse start times MANUALLY
---------------------------------------------------------------
v_pulseaddr := 0;
v_pulsetime := 7;
v_timefactor := 1.0;
v_gainfactor := 1.0;
v_wavestartaddr := 1; -- TODO: EricToGeoff/Sara: I assume we want starting address of each wave to be different and non-overlapping, right?
v_wavesteps := 4;
v_wavetopwidth := 1;
cpu_write_pulsedef(clk, v_pulseaddr*4, v_pulsetime, v_timefactor, v_gainfactor, v_wavestartaddr, v_wavesteps, v_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
v_pulseaddr := 1;
v_pulsetime := 69;
v_timefactor := 1.0;
v_gainfactor := 1.0;
v_wavestartaddr := 4; -- TODO: EricToGeoff/Sara: I assume we want starting address of each wave to be different and non-overlapping, right?
v_wavesteps := 6;
v_wavetopwidth := 9;
cpu_write_pulsedef(clk, v_pulseaddr*4, v_pulsetime, v_timefactor, v_gainfactor, v_wavestartaddr, v_wavesteps, v_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_print_msg("Pulse RAM loaded"); cpu_print_msg("Pulse RAM loaded");
clk_delay(20); clk_delay(20);
@ -410,41 +368,36 @@ begin
cpu_print_msg("Load waveform RAM"); cpu_print_msg("Load waveform RAM");
v_ndata16 := 1; -- first waveform value v_ndata16 := 1; -- first waveform value
for NADDR in 0 to 2047 loop for NADDR in 0 to 2047 loop
v_ndata32 := (((v_ndata16) * 2**C_BITS_ADDR_WAVE) + (v_ndata16 - 1)); -- Write two 16-bit values with each write 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); cpu_write(clk, (ADR_RAM_WAVE + NADDR) , v_ndata32, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
v_ndata16 := v_ndata16 + 2; v_ndata16 := v_ndata16 + 2;
end loop; end loop;
cpu_print_msg("Waveform RAM loaded");
clk_delay(20);
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- -- Read back Pulse RAM. -- Read back Pulse RAM.
-- -- Comment out if not needed to check CPU R/W ----------------------------------------------------------------
-- ---------------------------------------------------------------- v_ndata32 := 128; -- Time for first pulse
-- v_ndata32 := 128; -- Time for first pulse for NADDR in 0 to 255 loop
-- 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, 128, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- v_pulsetime := v_ndata32 + (NADDR*(1024+32)); end loop;
-- v_timefactor := 1.0; clk_delay(20);
-- v_gainfactor := 1.0;
-- v_wavestartaddr := 0;
-- v_wavesteps := NADDR*32;
-- v_wavetopwidth := 0;
-- cpu_read_pulsedef(clk, NADDR*4, v_pulsetime, v_timefactor, v_gainfactor, v_wavestartaddr, v_wavesteps, v_wavetopwidth, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
-- end loop;
-- clk_delay(20);
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- -- Read back Waveform RAM -- Read back Waveform RAM
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- v_ndata16 := 1; -- first waveform value v_ndata16 := 1; -- first waveform value
-- for NADDR in 0 to 2047 loop for NADDR in 0 to 2047 loop
-- v_ndata32 := (((v_ndata16) * 2**C_BITS_ADDR_WAVE) + (v_ndata16 - 1)); 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); 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; v_ndata16 := v_ndata16 + 2;
-- end loop; end loop;
-- -- Done reg write/read check -- Done reg write/read check
-- cpu_print_msg("RAM readback completed"); cpu_print_msg("RAM readback completed");
-- clk_delay(20); clk_delay(20);
---------------------------------------------------------------- ----------------------------------------------------------------
@ -455,9 +408,8 @@ begin
clk_delay(5); clk_delay(5);
start <= '0'; start <= '0';
-- TODO: we may need to modify the for loop to make sure the simulation time is long enough to cover all the pulses
-- Wait for cnt_time to reach last pulse start time + waveform size -- Wait for cnt_time to reach last pulse start time + waveform size
for NCNT in 1 to (128 + 256*(1024+32)+ 4096) loop -- TODO: EricToGeoff/Sara: in the real settings do we have a constant amount of time or the total time also vary? if so, how much? for NCNT in 1 to (128 + 16*(1024+32)+ 1024) loop
cnt_time <= std_logic_vector(unsigned(cnt_time) + 1); cnt_time <= std_logic_vector(unsigned(cnt_time) + 1);
clk_delay(0); clk_delay(0);
end loop; end loop;

View File

@ -1,530 +0,0 @@
---------------------------------------------------------------
-- 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;
use work.qlaser_dacs_pulse_channel_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(11 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
---------------------------------------------------------------------------
architecture channel of qlaser_dacs_pulse_channel is
-- Signal declarations for pulse RAM
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
signal ram_pulse_dina : std_logic_vector(31 downto 0); -- Data for pulse RAM
signal ram_pulse_douta : std_logic_vector(31 downto 0); -- Data out from pulse RAM
signal ram_pulse_addrb : std_logic_vector( 9 downto 0); -- Address for pulse RAM
signal ram_pulse_doutb : std_logic_vector(31 downto 0); -- Data out from pulse RAM
-- Signal declarations 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_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
-- TODO: add a fetch state to get four address from pd ram?
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_LOAD, -- Load the pulse channel RAM addresses and start the waveform output
S_HOLD, -- Hold the last pulse definition address and output its data
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
signal cnt_wave_len : unsigned(C_BITS_ADDR_LENGTH - 1 downto 0); -- Counter used for incremnet/decrement wave table addresses
signal cnt_wave_top : unsigned(C_BITS_ADDR_TOP - 1 downto 0); -- Counter for the flat top of the waveform
-- Misc signals
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 pc : std_logic_vector(C_BITS_ADDR_PULSE - 1 downto 0); -- pulse counter, used to count the number of pulses generated
----------------------------------------------------------------
-- Assign values from the pulse definition ram to regfiles (?) with the following:
-- 1. Start time 24 bits. [23:0]
-- 2. Wave start addr 12 bit at [11:0]
-- Wave length 10-bit at [25:16]
-- 3. Scale factors 16, 16. [31:16] [15:0]
-- 4. Flat-top 17-bit. [16:0]
----------------------------------------------------------------
signal reg_start_time : std_logic_vector(23 downto 0); -- first register which stores the pulse's start time
signal reg_pulse_sizes : std_logic_vector(31 downto 0); -- second register which stores the pulse's length, the bit width should increase with the amount of addresses the wavetable has, and its start address
-- TODO: replace the above one w/ below two
signal reg_wave_start_addr : std_logic_vector(11 downto 0); -- the start address of the wavetable
signal reg_wave_length : unsigned(9 downto 0); -- the length of the wavetable
signal reg_pulse_factors : std_logic_vector(31 downto 0); -- third register which stores the pulse's amplitude and time scale factors
-- TODO: replace the above one w/ below two
signal reg_scale_gain : unsigned(15 downto 0); -- scale factor for the gain, amplitude
signal reg_scale_time : unsigned(15 downto 0); -- scale factor for the time, length
signal reg_flattop : std_logic_vector(16 downto 0); -- fourth register which stores the pulse's flat top value
-- Pipeline delays
signal start_d1 : std_logic;
signal enable_d1 : std_logic;
begin
----------------------------------------------------------------
-- Pulse Definition Block RAM.
-- Synch write, Synch read
-- Port A is for CPU read/write. 1024x32-bit
-- Port B is for pulse time data output. 1024x32-bit
----------------------------------------------------------------
u_ram_pulse : entity work.bram_pulse_definition
port map(
-- Port A CPU Bus
clka => clk, -- input std_logic
wea => ram_pulse_we, -- input slv( 0 to 0 )
addra => ram_pulse_addra, -- input slv( 9 downto 0 )
dina => ram_pulse_dina, -- input slv( 31 downto 0 )
douta => ram_pulse_douta, -- output slv( 31 downto 0 ),
-- Port B waveform input
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.
-- Synch write, Synch read
-- Port A is for CPU read/write. 2048x32-bit
-- Port B is for waveform data. 4096x16-bit
----------------------------------------------------------------
u_ram_waveform : entity work.bram_waveform
port map (
-- Port A CPU Bus
clka => clk , -- input std_logic
wea => ram_waveform_wea , -- input slv(0 downto 0)
addra => ram_waveform_addra , -- input slv(10 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
web => (others=>'0') , -- input slv(0 downto 0)
addrb => ram_waveform_addrb , -- input slv(11 downto 0)
dinb => (others=>'0') , -- input slv(15 downto 0)
doutb => ram_waveform_doutb -- output slv(15 downto 0)
);
----------------------------------------------------------------
-- 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 <= (others=>'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
-------------------------------------------------
-- CPU writing RAM
-------------------------------------------------
if (cpu_wr = '1') and (cpu_sel = '1') then
-- 0 for pulse definition, 1 for waveform table
if (cpu_addr(C_RAM_SELECT) = '1') then
ram_pulse_addra <= (others=>'0');
ram_pulse_dina <= (others=>'0');
ram_pulse_we <= (others=>'0');
ram_waveform_wea(0) <= '1';
ram_waveform_addra <= cpu_addr(10 downto 0);
ram_waveform_dina <= cpu_wdata;
else
ram_pulse_addra <= cpu_addr(9 downto 0);
ram_pulse_dina <= cpu_wdata;
ram_pulse_we(0) <= '1';
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(C_RAM_SELECT) = '1') then -- Waveform
ram_pulse_addra <= (others=>'0');
ram_waveform_addra <= cpu_addr(10 downto 0);
else -- Pulse
ram_pulse_addra <= cpu_addr(9 downto 0);
ram_waveform_addra <= (others=>'0');
end if;
ram_pulse_we <= (others=>'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(C_RAM_SELECT); -- Save the select bit one cycle later
cpu_rdata_ramsel_d2 <= cpu_rdata_ramsel_d1;
else
ram_pulse_addra <= (others=>'0');
ram_pulse_we <= (others=>'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 <= ram_pulse_douta;
end if;
else
cpu_rdata <= (others=>'0');
cpu_rdata_dv <= '0';
end if;
end if;
end process;
----------------------------------------------------------------
-- 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)
variable v_amp_factor : std_logic_vector(C_BITS_GAIN_FACTOR - 1 downto 0);
variable v_time_factor : std_logic_vector(C_BITS_TIME_FACTOR - 1 downto 0);
-- Temp variables for waveform output
variable v_ram_waveform_doutb_multiplied : std_logic_vector(C_BITS_GAIN_FACTOR + 15 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';
reg_start_time <= (others=>'0');
reg_pulse_sizes <= (others=>'0');
reg_pulse_factors <= (others=>'0');
reg_flattop <= (others=>'0');
reg_scale_gain <= (others=>'0');
reg_scale_time <= (others=>'0');
pc <= (others=>'0');
cnt_wave_len <= (others=>'0');
cnt_wave_top <= (others=>'0');
elsif rising_edge(clk) then
-- Pipeline delays to use for rising edge detection
enable_d1 <= enable;
start_d1 <= start;
-- Default
sm_wavedata <= (others=>'0');
sm_wavedata_dv <= '0';
------------------------------------------------------------------------
-- Main state machine
------------------------------------------------------------------------
case sm_state is
------------------------------------------------------------------------
-- Wait for rising edge of enable
-- This is set when the JESD interface is aligned and functional.
-- Send a zero value to initialize the DAC then go to idle.
------------------------------------------------------------------------
when S_RESET =>
if (enable = '1') and (enable_d1 = '0') then
sm_wavedata <= (others=>'0');
sm_wavedata_dv <= '1';
sm_state <= S_IDLE;
end if;
sm_busy <= '0';
------------------------------------------------------------------------
-- Wait for rising edge of 'start'.
-- No data output.
------------------------------------------------------------------------
when S_IDLE =>
if (start = '1') and (start_d1 = '0') then
sm_state <= S_LOAD;
sm_busy <= '1';
else
sm_busy <= '0';
end if;
------------------------------------------------------------------------
-- Load four addresses from pulse definition RAM into four 32 bits regesters
------------------------------------------------------------------------
when S_LOAD =>
-- TODO: Eric: does is needed here? or should be inside the if-else loops
-- Load the pulse channel RAM addresses and start the waveform output
sm_busy <= '1';
-- Pipline the pulse definition address
-- TODO: is it better to make a counter to count the quarter or just mod 4?
-- TODO: maybe C-slow around the pulse ram to get it down to 1 cycle??
if (unsigned(ram_pulse_addrb) mod 4 = 0) then
ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 1);
sm_state <= S_LOAD;
-- first quarter of the pulse definition, no register is loaded
-- reg_start_time <= ram_pulse_doutb;
elsif (unsigned(ram_pulse_addrb) mod 4 = 1) then
ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 2);
sm_state <= S_LOAD;
-- reg_pulse_sizes <= ram_pulse_doutb;
-- second quarter of the pulse definition, the start time is loaded
reg_start_time <= ram_pulse_doutb;
elsif (unsigned(ram_pulse_addrb) mod 4 = 2) then
ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 3);
sm_state <= S_LOAD;
-- reg_pulse_factors <= ram_pulse_doutb;
-- third quarter of the pulse definition, the length and start address of the wavetable are loaded
reg_pulse_sizes <= ram_pulse_doutb;
elsif (unsigned(ram_pulse_addrb) mod 4 = 3) then
-- ram_pulse_addrb <= std_logic_vector(unsigned(pc) + 4);
sm_state <= S_WAIT; -- address is on the forth word of the entry, the loading process is complete. Moving onto the next state
-- hold the last pulse definition address as it will be used in the next state
-- reg_flattop <= ram_pulse_doutb;
pc <= std_logic_vector(unsigned(pc) + C_PC_INCR); -- incremnet the pulse counter and start waiting to output the wave
-- forth quarter of the pulse definition, the scale factors are loaded
reg_pulse_factors <= ram_pulse_doutb;
reg_scale_gain <= unsigned(ram_pulse_doutb(31 downto 16));
reg_scale_time <= unsigned(ram_pulse_doutb(15 downto 0));
end if;
-- ------------------------------------------------------------------------
-- -- Hold the last pulse definition address and output its data for one more clock cycle
-- ------------------------------------------------------------------------
-- when S_HOLD =>
-- sm_state <= S_LOAD;
------------------------------------------------------------------------
-- 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 =>
-- read the last word of the pulse definition, the flat top value
reg_flattop <= ram_pulse_doutb;
-- Start to output wave and increment pulse position RAM address
if (reg_start_time(C_START_TIME - 1 downto 0) = 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 <= reg_pulse_sizes(C_BITS_ADDR_START - 1 downto 0);
-- reset the wave lenth counter
cnt_wave_len <= (others=>'0');
-- parse the scale factors from reg_pulse_factors register
v_time_factor := reg_pulse_factors(C_BITS_TIME_FACTOR - 1 downto 0);
v_amp_factor := reg_pulse_factors(31 downto 16);
elsif (cnt_time = X"FFFFFF") then
sm_state <= S_IDLE;
end if;
------------------------------------------------------------------------
-- 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
-- TODO: convert the numbers below to constaint. right now just make sure I'm not confused
if (cnt_wave_len = reg_wave_length) then
sm_state <= S_WAVE_FLAT;
-- reset counters for transitions
cnt_wave_len <= (others=>'0');
cnt_wave_top <= (others=>'0');
-- TODO: toSara: do we need to consider the even of no flat top?
else
cnt_wave_len <= cnt_wave_len + 1;
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1);
end if;
v_ram_waveform_doutb_multiplied := std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain);
sm_wavedata <= std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain)(31 downto 16);
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- Hold the last address and output its data
-- decrement from this address when finished waiting
------------------------------------------------------------------------
when S_WAVE_FLAT =>
-- count the 17-bit flat top, if the counter reaches the flat top value, then go to the next state
if (cnt_wave_top = reg_flattop(C_BITS_ADDR_TOP - 1 downto 0)) then
sm_state <= S_WAVE_DOWN;
-- reset the counter for the next transition
cnt_wave_top <= (others=>'0');
else
cnt_wave_top <= std_logic_vector(unsigned(cnt_wave_top) + 1);
end if;
v_ram_waveform_doutb_multiplied := std_logic_vector(unsigned(ram_waveform_doutb) * unsigned(v_amp_factor));
sm_wavedata <= std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain)(31 downto 16); ;
sm_wavedata_dv <= '1';
------------------------------------------------------------------------
-- Output the falling edge of a waveform
-- Hold the start address when complete
------------------------------------------------------------------------
when S_WAVE_DOWN =>
-- End of waveform?
-- TODO: convert the numbers below to constaint. right now just make sure I'm not confused
if (cnt_wave_len = reg_wave_length) then
-- If the end of the pulse table is reached then go to idle, increment pulse address for the next waveform otherwise
if (ram_pulse_addrb = std_logic_vector(to_unsigned(C_LEN_PULSE-1, C_BITS_ADDR_PULSE))) then
ram_pulse_addrb <= (others=>'0');
pc <= (others=>'0');
sm_state <= S_IDLE;
else -- increment pulse address for the next waveform
ram_pulse_addrb <= pc;
-- the above line will now happen in the load state
-- pc <= std_logic_vector(unsigned(pc) + C_PC_INCR);
sm_state <= S_LOAD;
end if;
-- Output waveform from RAM with decremented address
else
cnt_wave_len <= cnt_wave_len + 1;
ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) - 1);
end if;
sm_wavedata <= std_logic_vector(unsigned(ram_waveform_doutb) * reg_scale_gain)(31 downto 16);
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
end channel;

View File

@ -2,7 +2,7 @@ do compile.do
vsim -voptargs="+acc" -lib work tb_cpubus_dacs_pulse_channel vsim -voptargs="+acc" -lib work tb_cpubus_dacs_pulse_channel
do waves_do/pp_sm_wavetables.do do waves_do/pp_sm.do
view wave view wave
view structure view structure

View File

@ -1,24 +0,0 @@
# Current time Mon Jan 15 15:15:21 2024
# ModelSim - Intel FPGA Edition Stack Trace
# Program = vsim
# Id = "10.5b"
# Version = "2016.10"
# Date = "Oct 5 2016"
# Platform = win32pe
# Signature = a4da31216fa3031746f0a74423efc007
# 0 0x004d3b4a: '<unknown (@0x4d3b4a)>'
# End of Stack Trace
# Current time Mon Jan 22 14:57:15 2024
# ModelSim - Intel FPGA Edition Stack Trace
# Program = vsim
# Id = "10.5b"
# Version = "2016.10"
# Date = "Oct 5 2016"
# Platform = win32pe
# Signature = a4da31216fa3031746f0a74423efc007
# 0 0x005d9fc7: '<unknown (@0x5d9fc7)>'
# End of Stack Trace

View File

@ -1,59 +0,0 @@
onerror {resume}
quietly virtual signal -install /tb_cpubus_dacs_pulse_channel/u_dac_pulse { /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_pulse_time(31 downto 16)} reg_pulse_time_31_16
quietly virtual signal -install /tb_cpubus_dacs_pulse_channel/u_dac_pulse { /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_pulse_time(15 downto 0)} reg_pulse_time_15_0
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/clk
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/start
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reset
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/busy
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cnt_time
add wave -noupdate -radix binary /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_addr
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_wdata
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_wr
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_sel
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_rdata
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_rdata_dv
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_addra
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_dina
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_douta
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_we
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/sm_state
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/pc
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_addrb
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_doutb
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_pulse_time
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_scale_gain
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_scale_time
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_wave_start_addr
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_wave_length
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_pulse_flattop
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_waveform_wea
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_waveform_addra
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_waveform_dina
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_waveform_douta
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_waveform_addrb
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_waveform_doutb
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/sm_wavedata
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/sm_wavedata_dv
add wave -noupdate -format Analog-Step -height 74 -max 204.0 -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/axis_tdata
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/axis_tvalid
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/axis_tlast
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/axis_tready
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 2} {62275000000 fs} 0}
quietly wave cursor active 1
configure wave -namecolwidth 163
configure wave -valuecolwidth 99
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits fs
update
WaveRestoreZoom {61852729312 fs} {62817270688 fs}

View File

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

View File

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

View File

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

View File

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