add state machine

This commit is contained in:
Eric Yu 2024-01-03 13:56:38 -08:00
parent c1daca2a0f
commit 6af4ea22d3
7 changed files with 337 additions and 69 deletions

1
.gitignore vendored
View File

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

View File

@ -35,13 +35,13 @@ port (
); );
end entity; end entity;
---------------------------------------------------------------- ---------------------------------------------------------------------------
-- Single channel pulse generator with two RAMs -- Single channel pulse generator with two RAMs
---------------------------------------------------------------- ---------------------------------------------------------------------------
architecture channel of qlaser_dacs_pulse_channel is architecture channel of qlaser_dacs_pulse_channel is
-- Constants declearations -- Constants declearations
constant C_RAM_SELECT : integer := 11; -- Select bit for which RAM for CPU read/write 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_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_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_START : integer := 12; -- Number of bits for starting address
@ -52,9 +52,11 @@ constant C_BITS_TIME_INT : integer := 14; -- Starting bit fo
constant C_BITS_TIME_FRAC : integer := 5; -- Starting bit for time fractional 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_BITS_ADDR_TOP : integer := 17; -- Number of bits for the "flat top", the top of the pulse
constant C_LENGTH_WAVEFORM : integer := 1024; -- Number of output data values from waveform RAM (1024x16-bit) constant C_LENGTH_WAVEFORM : integer := 4096; -- Number of output data values from waveform RAM (4kx16-bit)
constant C_BITS_ADDR_WAVE : integer := 10; -- Number of bits in address for waveform RAM 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 C_PC_INCR : integer := 4; -- Width of pulse counter increment
-- Signal declarations for pulse RAM -- Signal declarations for pulse RAM
@ -74,10 +76,13 @@ signal ram_waveform_addrb : std_logic_vector(11 downto 0); -- Address for wav
signal ram_waveform_doutb : std_logic_vector(15 downto 0); -- Data out from 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
-- TODO: add a fetch state to get four address from pd ram?
type t_sm_state is ( type t_sm_state is (
S_RESET, -- Wait for 'enable'. Stay here until JESD interface is up and running, S_RESET, -- Wait for 'enable'. Stay here until JESD interface is up and running,
S_IDLE, -- Wait for 'start' S_IDLE, -- Wait for 'start'
S_WAIT, -- Wait for cnt_time, external input, to match pulse position RAM output 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_UP, -- Output the rising edge of a waveform
S_WAVE_FLAT,-- Output the flat top part of a waveform S_WAVE_FLAT,-- Output the flat top part of a waveform
S_WAVE_DOWN -- Output the falling edge of a waveform S_WAVE_DOWN -- Output the falling edge of a waveform
@ -86,6 +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 : std_logic_vector(C_BITS_ADDR_LENGTH - 1 downto 0); -- Counter used for incremnet/decrement wave table addresses
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;
@ -93,6 +100,21 @@ signal cpu_rdata_dv_e2 : std_logic;
signal cpu_rdata_ramsel_d1 : std_logic; signal cpu_rdata_ramsel_d1 : std_logic;
signal cpu_rdata_ramsel_d2 : 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_pulse_time : std_logic_vector(31 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
signal reg_pulse_factors : std_logic_vector(31 downto 0); -- third register which stores the pulse's amplitude and time scale factors
signal reg_pulse_flattop : std_logic_vector(31 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;
signal enable_d1 : std_logic; signal enable_d1 : std_logic;
@ -264,4 +286,207 @@ begin
end if; end if;
end process; 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)
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_pulse_time <= (others=>'0');
reg_pulse_sizes <= (others=>'0');
reg_pulse_factors <= (others=>'0');
reg_pulse_flattop <= (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';
-- Actively read pulse definition RAM and update the variables
------------------------------------------------------------------------
-- 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 =>
-- Load the pulse channel RAM addresses and start the waveform output
sm_busy <= '1'; -- TODO: Eric: does is needed here? or should be inside the if-else loops
-- TODO: is it better to make a counter to count the quarter or just mod 4?
if (unsigned(ram_pulse_addrb) mod 4 = 0) then
ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
sm_state <= S_HOLD; -- stay in the load state to load the next address
reg_pulse_time <= ram_pulse_doutb;
pc <= std_logic_vector(unsigned(pc) + C_PC_INCR);
elsif (unsigned(ram_pulse_addrb) mod 4 = 1) then
ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
sm_state <= S_HOLD; -- stay in the load state to load the next address
reg_pulse_sizes <= ram_pulse_doutb;
elsif (unsigned(ram_pulse_addrb) mod 4 = 2) then
ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
sm_state <= S_HOLD; -- stay in the load state to load the next address
reg_pulse_factors <= ram_pulse_doutb;
elsif (unsigned(ram_pulse_addrb) mod 4 = 3) then
ram_pulse_addrb <= pc;
sm_state <= S_WAIT; -- go to the wait state to wait for the cnt_time to match the pulse time
reg_pulse_flattop <= ram_pulse_doutb;
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 =>
-- Start to output wave and increment pulse position RAM address
if (reg_pulse_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');
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_pulse_sizes(25 downto 16)) then
sm_state <= S_WAVE_FLAT;
-- reset counters for transitions
cnt_wave_len <= (others=>'0');
cnt_wave_top <= (others=>'0');
else
cnt_wave_len <= std_logic_vector(unsigned(cnt_wave_len) + 1);
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 =>
-- 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(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;
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?
-- TODO: convert the numbers below to constaint. right now just make sure I'm not confused
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 (ram_pulse_addrb = std_logic_vector(to_unsigned(C_LEN_PULSE-1, C_BITS_ADDR_PULSE))) 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);
-- the above line will now happen in the load state
sm_state <= S_LOAD;
end if;
-- Output waveform from RAM with decremented address
else
cnt_wave_len <= std_logic_vector(unsigned(cnt_wave_len) + 1);
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;
end channel; end channel;

View File

@ -361,19 +361,19 @@ begin
cpu_print_msg("Pulse RAM loaded"); cpu_print_msg("Pulse RAM loaded");
clk_delay(20); clk_delay(20);
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- -- Load waveform RAM with a simple ramp -- Load waveform RAM with a simple ramp
-- -- Write two 16-bit values with each write -- Write two 16-bit values with each write
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- 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 511 loop for NADDR in 0 to 2047 loop
-- v_ndata32 := (((v_ndata16+1) * 65536) + v_ndata16); 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"); cpu_print_msg("Waveform RAM loaded");
-- clk_delay(20); clk_delay(20);
---------------------------------------------------------------- ----------------------------------------------------------------
@ -385,34 +385,34 @@ begin
end loop; end loop;
clk_delay(20); 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 511 loop for NADDR in 0 to 2047 loop
-- v_ndata32 := (((v_ndata16+1) * 65536) + v_ndata16); 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);
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- -- Start the pulse outputs -- Start the pulse outputs
-- ---------------------------------------------------------------- ----------------------------------------------------------------
-- clk_delay(5); clk_delay(5);
-- start <= '1'; start <= '1';
-- clk_delay(5); clk_delay(5);
-- start <= '0'; start <= '0';
-- -- 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 + 16*(1024+32)+ 1024) loop 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;
wait for 10 us; wait for 10 us;

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_rw_cpu.do do waves_do/pp_sm.do
view wave view wave
view structure view structure

View File

@ -0,0 +1,42 @@
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reset
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/clk
add wave -noupdate /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 -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_addrb
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/sm_state
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_we
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/pc
add wave -noupdate -radix hexadecimal /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_pulse_sizes
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_pulse_factors
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reg_pulse_flattop
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {279215135747 fs} 0}
quietly wave cursor active 1
configure wave -namecolwidth 150
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 {278568705752 fs} {279501294248 fs}