added files

This commit is contained in:
Eric Yu 2023-12-04 15:53:11 -08:00
parent ef36daccae
commit 4a3b0bfedf
14 changed files with 18000 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.ini
*.wlf
work
transcript

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,582 @@
---------------------------------------------------------------
-- File : qlaser_dacs_pulse_channel.vhd
-- Description : Single channel of pulse output
----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.qlaser_pkg.all;
entity qlaser_dacs_pulse_channel is
port (
reset : in std_logic;
clk : in std_logic;
enable : in std_logic; -- Set when DAC interface is running
start : in std_logic; -- Set when pulse generation sequence begins (trigger)
cnt_time : in std_logic_vector(23 downto 0); -- Time since trigger.
busy : out std_logic; -- Status signal
-- CPU interface
cpu_addr : in std_logic_vector( 9 downto 0); -- Address input
cpu_wdata : in std_logic_vector(31 downto 0); -- Data input
cpu_wr : in std_logic; -- Write enable
cpu_sel : in std_logic; -- Block select
cpu_rdata : out std_logic_vector(31 downto 0); -- Data output
cpu_rdata_dv : out std_logic; -- Acknowledge output
-- AXI-stream output
axis_tready : in std_logic; -- axi_stream ready from downstream module
axis_tdata : out std_logic_vector(15 downto 0); -- axi stream output data
axis_tvalid : out std_logic; -- axi_stream output data valid
axis_tlast : out std_logic -- axi_stream output set on last data
);
end entity;
----------------------------------------------------------------
-- Single channel pulse generator with two RAMs and a FIFO
----------------------------------------------------------------
architecture rtl of qlaser_dacs_pulse_channel is
-- RAM, pulse position, CPU port, read/write
constant C_NUM_PULSE : integer := 16; -- Number of output data values from pulse RAM (16x24-bit)
signal ram_pulse_addra : std_logic_vector( 3 downto 0); -- 16 entry RAM
signal ram_pulse_dina : std_logic_vector(95 downto 0);
signal ram_pulse_douta : std_logic_vector(95 downto 0);
signal ram_pulse_douta_d1 : std_logic_vector(95 downto 0); -- Delay distrib RAM output to match pipeline of Block RAM
signal ram_pulse_we : std_logic;
-- RAM, pulse position, from state machine
constant C_BITS_GAIN_FACTOR : integer := 16; -- Number of bits in gain table
constant C_BITS_TIME_FACTOR : integer := 16; -- Number of bits in time table
constant C_BITS_TIME_INT : integer := 14; -- Starting bit for time integer part of the time factor, counting from MSB
constant C_BITS_TIME_FRAC : integer := 5; -- Starting bit for time fractional part of the time factor, counting from MSB
constant C_BITS_ADDR_START : integer := 10; -- Number of bits for starting address
constant C_BITS_ADDR_LENGTH : integer := 10; -- Number of bits for length address used by an edge of a pulse
constant C_BITS_ADDR_TOP : integer := 17; -- Number of bits for the "flat top", the top of the pulse
signal cnt_wave_top : std_logic_vector( C_BITS_ADDR_TOP - 1 downto 0); -- Counter for the top of the waveform
signal ram_pulse_addrb : std_logic_vector( 3 downto 0);
signal ram_pulse_doutb : std_logic_vector(95 downto 0);
signal cpu_rdata_dv_e1 : std_logic;
signal cpu_rdata_dv_e2 : std_logic;
signal cpu_rdata_ramsel_d1 : std_logic;
signal cpu_rdata_ramsel_d2 : std_logic;
signal cpu_wdata_top : std_logic_vector(31 downto 0); -- Top 32 bits of CPU write data (95:64)
signal cpu_wdata_mid : std_logic_vector(31 downto 0); -- Middle 32 bits of CPU write data (63:32)
-- Waveform RAM port connections.
-- NOTE: Port A is 32-bit data, port B is 16-bit
constant C_LENGTH_WAVEFORM : integer := 1024; -- Number of output data values from waveform RAM (1024x16-bit)
constant C_BITS_ADDR_WAVE : integer := 10; -- Number of bits in address for waveform RAM
signal ram_waveform_ena : std_logic;
signal ram_waveform_wea : std_logic_vector( 0 downto 0);
signal ram_waveform_addra : std_logic_vector( 8 downto 0);
signal ram_waveform_dina : std_logic_vector(31 downto 0);
signal ram_waveform_douta : std_logic_vector(31 downto 0);
signal ram_waveform_enb : std_logic := '0';
signal ram_waveform_web : std_logic_vector( 0 downto 0) := (others=>'0');
signal ram_waveform_addrb : std_logic_vector( 9 downto 0);
signal ram_waveform_dinb : std_logic_vector(15 downto 0) := (others=>'0');
signal ram_waveform_doutb : std_logic_vector(15 downto 0);
-- State variable type declaration for main state machine
type t_sm_state is (
S_RESET, -- Wait for 'enable'. Stay here until JESD interface is up and running,
S_IDLE, -- Wait for 'start'
S_WAIT, -- Wait for cnt_time, external input, to match pulse position RAM output
S_WAVE_UP, -- Output the rising edge of a waveform
S_WAVE_FLAT,-- Output the flat top part of a waveform
S_WAVE_DOWN -- Output the falling edge of a waveform
);
signal sm_state : t_sm_state;
signal sm_wavedata : std_logic_vector(15 downto 0); -- Waveform RAM data
signal sm_wavedata_dv : std_logic; -- Signal to indicate that waveform RAM data is valid
signal sm_busy : std_logic; -- Signal to indicate that s.m. is not idle
---- FIFO port connections
--signal fifo_wr_en : std_logic;
--signal fifo_full : std_logic;
--signal fifo_empty : std_logic;
--signal fifo_wr_rst_busy : std_logic;
--signal fifo_rd_rst_busy : std_logic;
--signal fifo_rd_en : std_logic;
---- FIFO status signals for debug purpose
--signal fifo_wr_ack : std_logic;
--signal fifo_overflow : std_logic;
--signal fifo_valid : std_logic;
--signal fifo_underflow : std_logic;
-- Pipeline delays
signal start_d1 : std_logic;
signal enable_d1 : std_logic;
begin
busy <= sm_busy;
----------------------------------------------------------------
-- Distributed RAM to hold 16 24-bit Pulse start times.
-- Synch write, Asynch read
-- Port A is for CPU read/write. 16x24-bit
-- Port B is for pulse time data output. 16x24-bit
----------------------------------------------------------------
u_ram_pulse : entity work.bram_pulseposition
port map(
clk => clk , -- input std_logic
a => ram_pulse_addra , -- input slv[3:0]
d => ram_pulse_dina , -- input slv[95 downto 0]
we => ram_pulse_we ,
spo => ram_pulse_douta , -- output slv(95 downto 0]
dpra => ram_pulse_addrb , -- input slv[3:0]
dpo => ram_pulse_doutb -- output slv(95 downto 0)
);
----------------------------------------------------------------
-- Waveform table Block RAM.
-- Synch write, Synch read
-- Port A is for CPU read/write. 512x32-bit
-- Port B is for waveform data. 1024x16-bit
----------------------------------------------------------------
u_ram_waveform : entity work.bram_waveform
port map (
-- Port A CPU Bus
clka => clk , -- input std_logic
ena => ram_waveform_ena , -- input std_logic
wea => ram_waveform_wea , -- input slv(0 downto 0)
addra => ram_waveform_addra , -- input slv(8 downto 0)
dina => ram_waveform_dina , -- input slv(31 downto 0)
douta => ram_waveform_douta , -- output slv(31 downto 0)
-- Port B waveform output
clkb => clk , -- input std_logic
enb => ram_waveform_enb , -- input std_logic
web => (others=>'0') , -- input slv(0 downto 0)
addrb => ram_waveform_addrb , -- input slv(9 downto 0)
dinb => (others=>'0') , -- input slv(15 downto 0)
doutb => ram_waveform_doutb -- output slv(15 downto 0)
);
----------------------------------------------------------------
-- State machine:
-- Compares cnt_time input against current output from pulse position RAM.
-- When values match iti incremnts the pulse postion RAM address to
-- retrieve the next pulse position and also starts reading the
-- entire waveform table, one value every clock cycle, until it reaches the end.
-- Once the pulse is complete it waits for the next cnt_time match.
-- Repeat until all pulse position RAM times have triggered a pulse output
-- or until the maximum counter time has been reached.
----------------------------------------------------------------
pr_sm : process (reset, clk)
-- TODO: those bitwidth are not correct, we could optimize it later and find out how many bits each variable should be. But for now just make it big
variable v_ram_waveform_addrb : unsigned(95 downto 0);
begin
if (reset = '1') then
sm_state <= S_IDLE; -- TODO: Eric: Should this be S_RESET since we reset the JEDS interface as well?
ram_pulse_addrb <= (others=>'0');
ram_waveform_addrb <= (others=>'0');
sm_wavedata <= (others=>'0');
sm_wavedata_dv <= '0';
sm_busy <= '0';
ram_waveform_enb <= '0';
elsif rising_edge(clk) then
-- Pipeline delays to use for rising edge detection
enable_d1 <= enable;
start_d1 <= start;
-- Default
sm_wavedata <= (others=>'0');
sm_wavedata_dv <= '0';
------------------------------------------------------------------------
-- Main state machine
------------------------------------------------------------------------
case sm_state is
------------------------------------------------------------------------
-- Wait for rising edge of enable
-- This is set when the JESD interface is aligned and functional.
-- Send a zero value to initialize the DAC then go to idle.
------------------------------------------------------------------------
when S_RESET =>
if (enable = '1') and (enable_d1 = '0') then
sm_wavedata <= (others=>'0');
sm_wavedata_dv <= '1';
sm_state <= S_IDLE;
end if;
sm_busy <= '0';
ram_waveform_enb <= '0';
------------------------------------------------------------------------
-- Wait for rising edge of 'start'.
-- No data output.
------------------------------------------------------------------------
when S_IDLE =>
if (start = '1') and (start_d1 = '0') then
sm_state <= S_WAIT;
sm_busy <= '1';
else
sm_busy <= '0';
end if;
ram_waveform_enb <= '0';
------------------------------------------------------------------------
-- Wait for cnt_time, external input, to match pulse position RAM output
-- Return to idle state if max time is reached. Output waveform value zero.
------------------------------------------------------------------------
when S_WAIT =>
-- Start to output wave and increment pulse position RAM address
if (ram_pulse_doutb(93 downto C_BITS_TIME_FACTOR) = cnt_time) then
sm_state <= S_WAVE_UP;
-- set the wavetable's address to the starting address defined from the pulse ram
ram_waveform_addrb <= ram_pulse_doutb(C_BITS_GAIN_FACTOR - 1 downto C_BITS_ADDR_START);
elsif (cnt_time = X"FFFFFF") then
sm_state <= S_IDLE;
end if;
ram_waveform_enb <= '1';
------------------------------------------------------------------------
-- Output the raising edge of a waveform
-- Hold the last address when complete
------------------------------------------------------------------------
when S_WAVE_UP =>
-- Check if is end of rise of the waveform, and hold the address
if (ram_waveform_addrb = std_logic_vector(unsigned(ram_pulse_doutb(C_BITS_GAIN_FACTOR - 1 downto C_BITS_ADDR_START)) + unsigned(ram_pulse_doutb(C_BITS_ADDR_START - 1 downto C_BITS_ADDR_LENGTH)))) then
sm_state <= S_WAVE_FLAT;
-- initialize the counter for the flat top of the waveform
cnt_wave_top <= std_logic_vector(to_unsigned(0, C_BITS_ADDR_TOP));
else
-- Output waveform from RAM with rounded gain factor
v_ram_waveform_addrb := ((unsigned(ram_waveform_addrb) + 1) * unsigned(ram_pulse_doutb(C_BITS_TIME_FACTOR - 1 downto C_BITS_GAIN_FACTOR)));
ram_waveform_addrb <= std_logic_vector(v_ram_waveform_addrb(C_BITS_TIME_INT downto C_BITS_TIME_FRAC));
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
end if;
when S_WAVE_FLAT =>
if (cnt_wave_top = ram_pulse_doutb(C_BITS_ADDR_TOP - 1 downto 0)) then
sm_state <= S_WAVE_DOWN;
else
cnt_wave_top <= std_logic_vector(unsigned(cnt_wave_top) + 1);
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
end if;
when S_WAVE_DOWN =>
-- End of waveform?
if (ram_waveform_addrb = std_logic_vector(to_unsigned(C_LENGTH_WAVEFORM-1,10))) then
-- If the end of the pulse table is reached then go to idle
if (ram_pulse_addrb = std_logic_vector(to_unsigned(C_NUM_PULSE-1,10))) then
ram_pulse_addrb <= (others=>'0');
sm_state <= S_IDLE;
else -- Increment pulse address. Wait for next pulse start time
ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
sm_state <= S_WAIT;
end if;
-- Output waveform from RAM with decremented address
else
v_ram_waveform_addrb := (unsigned(ram_waveform_addrb) - 1) * unsigned(ram_pulse_doutb(C_BITS_TIME_FACTOR - 1 downto C_BITS_GAIN_FACTOR));
ram_waveform_addrb <= std_logic_vector(v_ram_waveform_addrb(C_BITS_TIME_INT downto C_BITS_TIME_FRAC));
sm_wavedata <= ram_waveform_doutb;
sm_wavedata_dv <= '1';
end if;
------------------------------------------------------------------------
-- Default
------------------------------------------------------------------------
when others =>
sm_state <= S_IDLE;
end case;
end if;
end process;
-- AXI-Stream output.
-- TBD: This should come from a FIFO
-- TODO: the bits are not correct, should be top bits (C_BITS_GAIN_FACTOR + 16 downto C_BITS_GAIN_FACTOR), but for now just make it this way so modelsim can simulate
-- TODO: apply scaling factor to the output
axis_tdata <= sm_wavedata; -- axi stream output data, this output should be multiplied by the gain factor, then take the top 16 bits
axis_tvalid <= sm_wavedata_dv; -- axi_stream output data valid
-- TBD : Generate in state machine?
axis_tlast <= '0'; -- axi_stream output last
----------------------------------------------------------------
-- **** TBD : ADD FIFO ****
----------------------------------------------------------------
-- FIFO for waveform data
-- connect to external output to whatever we want to connect
----------------------------------------------------------------
--u_data_to_stream : entity work.fifo_data_to_stream
--port map (
-- clk => clk, -- input std_logic
-- srst => reset, -- input std_logic
-- rd_en => fifo_rd_en, -- input std_logic
-- wr_en => fifo_wr_en, -- input std_logic
-- empty => fifo_empty, -- output std_logic
-- full => fifo_full, -- output std_logic
-- din => ram_waveform_doutb, -- input slv(15 downto 0)
-- dout => fifo_dout, -- output slv(15 downto 0)
--
-- -- FIFO signals, some of then are for debug purpose
-- wr_ack => fifo_wr_ack, -- output std_logic
-- overflow => fifo_overflow, -- output std_logic
-- valid => fifo_valid, -- output std_logic
-- underflow => fifo_underflow, -- output std_logic
-- wr_rst_busy => fifo_wr_rst_busy, -- output std_logic
-- rd_rst_busy => fifo_rd_rst_busy -- output std_logic
--);
----------------------------------------------------------------
-- CPU Read/Write RAM
-- MSB of cpu_addr is used to select one of the two RAMs
-- to read/write, and the remainder are a 9-bit or 4-bit RAM address.
----------------------------------------------------------------
pr_ram_rw : process (reset, clk)
begin
if (reset = '1') then
ram_pulse_addra <= (others=>'0');
ram_pulse_dina <= (others=>'0');
ram_pulse_we <= '0';
ram_waveform_ena <= '0';
ram_waveform_wea <= (others=>'0');
ram_waveform_addra <= (others=>'0');
ram_waveform_dina <= (others=>'0');
cpu_rdata <= (others=>'0');
cpu_rdata_dv <= '0';
cpu_rdata_dv_e1 <= '0';
cpu_rdata_dv_e2 <= '0';
cpu_rdata_ramsel_d1 <= '0';
cpu_rdata_ramsel_d2 <= '0';
elsif rising_edge(clk) then
ram_waveform_ena <= '0';
-------------------------------------------------
-- CPU writing RAM
-------------------------------------------------
if (cpu_wr = '1') and (cpu_sel = '1') then
-- 0 for pulse position, 1 for waveform table
if (cpu_addr(9) = '1') then
ram_pulse_addra <= (others=>'0');
ram_pulse_dina <= (others=>'0');
ram_pulse_we <= '0';
ram_waveform_wea(0) <= '1';
ram_waveform_ena <= '1';
ram_waveform_addra <= cpu_addr(8 downto 0);
ram_waveform_dina <= cpu_wdata;
else
ram_pulse_addra <= cpu_addr(5 downto 2);
-- select which part of the 96-bit data to write
if (cpu_addr(1 downto 0) = "00") then
ram_pulse_dina(31 downto 0) <= cpu_wdata;
elsif (cpu_addr(1 downto 0) = "01") then
ram_pulse_dina(63 downto 32) <= cpu_wdata;
elsif (cpu_addr(1 downto 0) = "10") then
ram_pulse_dina(95 downto 64) <= cpu_wdata;
ram_pulse_we <= '1'; -- Write on the thrid cycle
end if;
ram_waveform_ena <= '0';
ram_waveform_wea <= (others=>'0');
ram_waveform_addra <= (others=>'0');
ram_waveform_dina <= (others=>'0');
end if;
cpu_rdata_dv_e1 <= '0';
cpu_rdata_dv_e2 <= '0';
cpu_rdata_ramsel_d1 <= '0';
cpu_rdata_ramsel_d2 <= '0';
-------------------------------------------------
-- CPU read
-------------------------------------------------
elsif (cpu_wr = '0') and (cpu_sel = '1') then
if (cpu_addr(9) = '1') then -- Waveform
ram_waveform_ena <= '1';
ram_pulse_addra <= (others=>'0');
ram_waveform_addra <= cpu_addr(8 downto 0);
else -- Pulse
ram_pulse_addra <= cpu_addr(5 downto 2);
ram_pulse_douta_d1 <= ram_pulse_douta; -- Delay distrib RAM output to match pipeline of Block RAM
ram_waveform_addra <= (others=>'0');
end if;
ram_pulse_we <= '0';
ram_waveform_wea(0) <= '0';
cpu_rdata_dv_e2 <= '1'; -- DV for cycle, when RAM output occurs
cpu_rdata_dv_e1 <= cpu_rdata_dv_e2; -- DV for next cycle
cpu_rdata_ramsel_d1 <= cpu_addr(9); -- Save the select bit one cycle later
cpu_rdata_ramsel_d2 <= cpu_rdata_ramsel_d1;
else
ram_pulse_addra <= (others=>'0');
ram_pulse_we <= '0';
ram_waveform_addra <= (others=>'0');
ram_waveform_wea(0) <= '0';
cpu_rdata_dv_e2 <= '0';
cpu_rdata_dv_e1 <= cpu_rdata_dv_e2; -- DV for next cycle
cpu_rdata_ramsel_d1 <= '0';
cpu_rdata_ramsel_d2 <= cpu_rdata_ramsel_d1;
end if;
-------------------------------------------------
-- Output the delayed RAM data
-- This adds a pipeline delay to the cpu_rdata_dv to account for
-- the delay in reading data from the RAM
-------------------------------------------------
if (cpu_rdata_dv_e1 = '1') then
cpu_rdata_dv <= '1';
-- Select source of output data
if (cpu_rdata_ramsel_d2 = '1') then -- Output is from waveform table
cpu_rdata <= ram_waveform_douta;
elsif (cpu_rdata_ramsel_d2 = '0') then
-- cpu_rdata <= X"00" & ram_pulse_douta_d1;
-- select which part of the 96-bit data to read
if (cpu_addr(1 downto 0) = "00") then
cpu_rdata <= ram_pulse_douta_d1(31 downto 0);
elsif (cpu_addr(1 downto 0) = "01") then
cpu_rdata <= ram_pulse_douta_d1(63 downto 32);
elsif (cpu_addr(1 downto 0) = "10") then
cpu_rdata <= ram_pulse_douta_d1(95 downto 64);
end if;
end if;
else
cpu_rdata <= (others=>'0');
cpu_rdata_dv <= '0';
end if;
end if;
end process;
-- ----------------------------------------------------------------
-- -- Read time from RAM to generate pulses
-- -- When input cnt_time equals RAM time output then set dout
-- -- to RAM amplitude output and read next set of RAM data.
-- -- Keep reading waveform RAM every clock cycle until the end of the RAM
-- ----------------------------------------------------------------
-- pr_ram_pulse : process(reset, clk)
-- begin
-- if (reset = '1') then
--
-- ram_pulse_addrb <= (others => '0');
-- start_pulse <= '0';
-- dout_dv <= '0';
--
-- elsif rising_edge(clk) then
--
-- -- dout <= ram_amplitude;
--
-- if (cnt_time = X"000000") then -- Not triggered
-- ram_pulse_addrb <= (others=>'0');
-- dout_dv <= '0';
-- start_pulse <= '0';
--
-- elsif (ram_time = cnt_time) then
--
-- ram_pulse_addrb <= std_logic_vector(unsigned(ram_pulse_addrb) + 1);
-- dout_dv <= '1';
-- start_pulse <= '1';
--
-- else
-- dout_dv <= '0';
-- start_pulse <= '0';
-- end if;
--
-- end if;
--
-- end process;
--
--
-- ----------------------------------------------------------------
-- -- Read amplitude from Waveform RAM to generate pulses
-- -- When start_pulse is asserted, and when FIFO is not full, write
-- -- amplitude to FIFO.
-- ----------------------------------------------------------------
-- pr_ram_wavetable : process(reset, clk)
-- begin
-- if (reset = '1') then
-- fifo_wr_en <= '0';
-- ram_waveform_addrb <= (others => '0');
-- ram_waveform_enb <= '0';
-- busy <= '0';
-- elsif rising_edge(clk) then
-- if (read_table = '1') then -- start_pulse get asserted
-- busy <= '1';
-- -- TODO EricToGeoff : This condition may not satisfy all cases of a fifo_ready, maybe also utilize fifo_wr_ack or just a simple FSM?
-- if (fifo_full = '0') then
-- fifo_wr_en <= '1';
-- ram_waveform_addrb <= std_logic_vector(unsigned(ram_waveform_addrb) + 1);
-- ram_waveform_enb <= '1';
-- else
-- fifo_wr_en <= '0';
-- -- FIFO is full, wait
-- ram_waveform_addrb <= ram_waveform_addrb;
-- ram_waveform_enb <= '0';
-- end if;
-- else
-- fifo_wr_en <= '0';
-- ram_waveform_addrb <= (others => '0');
-- ram_waveform_enb <= '0';
-- end if;
-- end if;
--
-- end process;
--
-- -- For new versions, ram_doutb are differnt RAMs b port outputs, ram_amplitude should go thought a FIFO first from RAM
-- ram_time <= ram_doutb;
-- read_table <= start_pulse;
--
-- fifo_rd_en <= axi_tready and fifo_full;
end rtl;

9531
src/hdl/pkg/iopakb.vhd Normal file

File diff suppressed because it is too large Load Diff

2596
src/hdl/pkg/iopakp.vhd Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
----------------------------------------------------------------------------------------
-- Project : qlaser FPGA
-- File : qlaser_dac_dc_pkg.vhd
-- Description : Version package file.
-- Author : akozyra
----------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
package qlaser_dac_dc_pkg is
----------------------------------------------------------------------------------------
-- Constants
----------------------------------------------------------------------------------------
-- Addresses
constant C_ADDR_SPI0 : std_logic_vector(2 downto 0) := "000";
constant C_ADDR_SPI1 : std_logic_vector(2 downto 0) := "001";
constant C_ADDR_SPI2 : std_logic_vector(2 downto 0) := "010";
constant C_ADDR_SPI3 : std_logic_vector(2 downto 0) := "011";
constant C_ADDR_SPI_ALL : std_logic_vector(2 downto 0) := "100";
constant C_ADDR_INTERNAL_REF : std_logic_vector(2 downto 0) := "101";
constant C_ADDR_POWER_ON : std_logic_vector(2 downto 0) := "110";
-- Commands
constant C_CMD_DAC_DC_WR : std_logic_vector(3 downto 0) := "0011";
constant C_CMD_DAC_DC_INTERNAL_REF : std_logic_vector(3 downto 0) := "1000";
constant C_CMD_DAC_DC_POWER : std_logic_vector(3 downto 0) := "0100";
end package qlaser_dac_dc_pkg;

146
src/hdl/pkg/qlaser_pkg.vhd Normal file
View File

@ -0,0 +1,146 @@
-------------------------------------------------------------------------------
-- Filename : qlaser_pkg.vhd
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.qlaser_dac_dc_pkg.all;
-- use work.qlaser_dac_ac_pkg.all;
--------------------------------------------------------------------------------
-- FPGA constant definitions
-------------------------------------------------------------------------------
package qlaser_pkg is
-- FPGA internal (PLL) clock freq expressed in MHz
constant C_CLK_FREQ_MHZ : real := 100.0;
-- Clock period
constant C_CLK_PERIOD : time := integer(1.0E+6/(C_CLK_FREQ_MHZ)) * 1 ps;
constant C_NUM_CHAN_DC : integer := 32; -- Number of DC channels
constant C_NUM_CHAN_AC : integer := 32; -- Number of AC (pulse) channels
--------------------------------------------------------------------------------
-- FPGA Addresses
-- Main blocks. Decoded from upper 4 bits of address [15:12]
--------------------------------------------------------------------------------
constant ADR_BASE_DC : std_logic_vector( 3 downto 0) := X"0"; -- Registers to load DC DAC values
constant ADR_BASE_PULSE : std_logic_vector( 3 downto 0) := X"1"; -- RAMs for Pulse output start/stop times
constant ADR_BASE_MISC : std_logic_vector( 3 downto 0) := X"2"; -- Misc, LEDs, switches, power control
--------------------------------------------------------------------------------
-- Define the number of internal blocks that are addressed by the CPU
--------------------------------------------------------------------------------
constant C_NUM_BLOCKS : integer := 3;
type t_arr_cpu_dout is array (0 to C_NUM_BLOCKS-1) of std_logic_vector(31 downto 0);
type t_arr_dout_ac is array (0 to C_NUM_CHAN_AC-1) of std_logic_vector(15 downto 0);
--------------------------------------------------------------------------------------------------------------------------
-- 'DC' DAC block registers. 32 16-bit DAC outputs [5:3]
constant C_ADDR_CH_SPI0 : std_logic_vector(2 downto 0) := "000";
constant C_ADDR_CH_SPI1 : std_logic_vector(2 downto 0) := "001";
constant C_ADDR_CH_SPI2 : std_logic_vector(2 downto 0) := "010";
constant C_ADDR_CH_SPI3 : std_logic_vector(2 downto 0) := "011";
constant C_ADDR_CH_SPI_ALL : std_logic_vector(2 downto 0) := "100";
constant C_ADDR_INTERNAL_REF : std_logic_vector(2 downto 0) := "101";
constant C_ADDR_POWER_ON : std_logic_vector(2 downto 0) := "110";
--------------------------------------------------------------------------------------------------------------------------
-- Individual DAC data registers
constant ADR_DAC_DC0 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "000"; --
constant ADR_DAC_DC1 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "001"; --
constant ADR_DAC_DC2 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "010"; --
constant ADR_DAC_DC3 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "011"; --
constant ADR_DAC_DC4 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "100"; --
constant ADR_DAC_DC5 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "101"; --
constant ADR_DAC_DC6 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "110"; --
constant ADR_DAC_DC7 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI0 & "111"; --
constant ADR_DAC_DC8 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI1 & "000"; --
constant ADR_DAC_DC9 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI1 & "001"; --
-- constant ADR_DAC_DC6 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI2 & "000"; --
-- constant ADR_DAC_DC7 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI2 & "001"; --
-- etc. etc.
-- constant ADR_DAC_DC6 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI3 & "110"; --
-- constant ADR_DAC_DC7 : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_SPI3 & "111"; --
constant ADR_DAC_DC30 : std_logic_vector(15 downto 0) := ADR_BASE_DC & X"01E"; --
constant ADR_DAC_DC31 : std_logic_vector(15 downto 0) := ADR_BASE_DC & X"01F"; --
constant ADR_DAC_DC_ALL : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_CH_SPI_ALL & "000"; -- Write all channels
constant ADR_DAC_DC_IREF : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_INTERNAL_REF & "000"; --
constant ADR_DAC_DC_POWER_ON : std_logic_vector(15 downto 0) := ADR_BASE_DC & "000000" & C_ADDR_POWER_ON & "000"; --
constant ADR_DAC_DC_STATUS : std_logic_vector(15 downto 0) := ADR_BASE_DC & X"000"; -- Reading any address returns SPI interface busy status (this was 32 bit, but decleared as 16, so I changed to 16)
--------------------------------------------------------------------------------------------------------------------------
-- 'Pulse' DAC block registers.
-- The block has a set of block registers and contains 16 'channels'
-- Each channel has a 40-bit memory to specify 24-bit time and a 16-bit level.
-- Initially just using the MSB of the level to drive a single pin output
--
--------------------------------------------------------------------------------------------------------------------------
-- Block-level registers
-- CPU_ADDR(11) = '0' selects local regs
-- CPU_ADDR(11) = '1' selects the channel specified in reg_ctrl(3 :0)
-- Then CPU_ADDR(10:1) selects RAM word address (1024 address MAX)
-- CPU_ADDR(0) selects MSB or LSB of 40-bit RAM word (time or amplitude)
--------------------------------------------------------------------------------------------------------------------------
-- Addresses for block-level registers.
-------------------------------------------------------------------------------------------------------------------------
constant ADR_DAC_PULSE_CTRL : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"800"; -- 4:0 select channel RAM for CPU read/write. Bit 8 is rising edge internal trigger
constant ADR_DAC_PULSE_STATUS : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"801"; -- R/O Level status for output of each channel
constant ADR_DAC_PULSE_RUNTIME : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"802"; -- Max time for pulse train
constant ADR_DAC_PULSE_CH_EN : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"803"; -- Enable bit for each individual channel
constant ADR_DAC_PULSE_TIMER : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"804"; -- R/O Current timer value (used by all channels)
-------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------
-- Pulse Channel offsets
--------------------------------------------------------------------------------------------------------------------------
constant ADR_DAC_PULSE0 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"000"; -- Base address of a 16-word x 40-bit RAM
constant ADR_DAC_PULSE1 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"040"; --
constant ADR_DAC_PULSE2 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"080"; --
constant ADR_DAC_PULSE3 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"0C0"; --
--
constant ADR_DAC_PULSE4 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"100"; --
constant ADR_DAC_PULSE5 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"140"; --
constant ADR_DAC_PULSE6 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"180"; --
constant ADR_DAC_PULSE7 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"1C0"; --
--
constant ADR_DAC_PULSE8 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"200"; --
constant ADR_DAC_PULSE9 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"240"; --
constant ADR_DAC_PULSE10 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"280"; --
constant ADR_DAC_PULSE11 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"2C0"; --
--
constant ADR_DAC_PULSE12 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"300"; --
constant ADR_ADC_PULSE13 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"340"; --
constant ADR_DAC_PULSE14 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"380"; --
constant ADR_DAC_PULSE15 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"3C0"; --
--
-- etc. etc.
constant ADR_DAC_PULSE28 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"700"; --
constant ADR_DAC_PULSE29 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"740"; --
constant ADR_DAC_PULSE30 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"780"; --
constant ADR_DAC_PULSE31 : std_logic_vector(15 downto 0) := ADR_BASE_PULSE & X"7C0"; --
--------------------------------------------------------------------------------------------------------------------------
-- Misc block registers
--------------------------------------------------------------------------------------------------------------------------
constant ADR_MISC_VERSION : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"000"; -- HDL code version
constant ADR_MISC_LEDS : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"001"; -- LEDs
constant ADR_MISC_LEDS_EN : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"002"; -- LEDs enable
constant ADR_MISC_SW_IN : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"003"; -- Read board switch settings (if present)
constant ADR_MISC_DEBUG_CTRL : std_logic_vector(15 downto 0) := ADR_BASE_MISC & X"004"; -- Select debug output from top level to pins
end package;
package body qlaser_pkg is
end package body;

View File

@ -0,0 +1,394 @@
-----------------------------------------------------------
-- File : tb_cpubus_dacs_pulse_channel.vhd
-----------------------------------------------------------
--
-- Testbench for CPU bus peripheral.
--
-- Description : Pulse output control of Qlaser FPGA
-- Block drives AXI-stream to JESD DACs
--
----------------------------------------------------------
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use std.textio.all;
use work.std_iopak.all;
entity tb_cpubus_dacs_pulse_channel is
end tb_cpubus_dacs_pulse_channel;
architecture behave of tb_cpubus_dacs_pulse_channel is
signal clk : std_logic;
signal reset : std_logic;
signal enable : std_logic;
signal start : std_logic;
signal cnt_time : std_logic_vector(23 downto 0);
signal busy : std_logic;
signal cpu_wr : std_logic;
signal cpu_sel : std_logic;
signal cpu_addr : std_logic_vector(15 downto 0);
signal cpu_wdata : std_logic_vector(31 downto 0);
signal cpu_rdata : std_logic_vector(31 downto 0);
signal cpu_rdata_dv : std_logic;
-- AXI-stream output interface
signal axis_tready : std_logic := '1'; -- Always ready
signal axis_tdata : std_logic_vector(15 downto 0);
signal axis_tvalid : std_logic;
signal axis_tlast : std_logic;
-- Halts simulation by stopping clock when set true
signal sim_done : boolean := false;
-- Crystal clock freq expressed in MHz
constant CLK_FREQ_MHZ : real := 100.0;
-- Clock period
constant CLK_PER : time := integer(1.0E+6/(CLK_FREQ_MHZ)) * 1 ps;
-- Block registers
constant ADR_RAM_PULSE : integer := 0; -- base address for pulse RAM, TODO: this constant should eventually go to qlaser_pkg
constant ADR_RAM_WAVE : integer := 512; --
-------------------------------------------------------------
-- CPU write procedure. Address in decimal. Data in hex
-------------------------------------------------------------
procedure cpu_write(
signal clk : in std_logic;
constant a : in integer;
constant d : in std_logic_vector(31 downto 0);
signal cpu_sel : out std_logic;
signal cpu_wr : out std_logic;
signal cpu_addr : out std_logic_vector(15 downto 0);
signal cpu_wdata : out std_logic_vector(31 downto 0)
) is
begin
wait until clk'event and clk='0';
cpu_sel <= '1';
cpu_wr <= '1';
cpu_addr <= std_logic_vector(to_unsigned(a, 16));
cpu_wdata <= std_logic_vector(d);
wait until clk'event and clk='0';
cpu_sel <= '0';
cpu_wr <= '0';
cpu_addr <= (others=>'0');
cpu_wdata <= (others=>'0');
wait until clk'event and clk='0';
end;
-------------------------------------------------------------
-- CPU write pulse definition RAM
-- Use 96 bit data to make three 32-bit writes
-------------------------------------------------------------
procedure cpu_write_pulsedef(
signal clk : in std_logic;
constant num_entry : in integer;
-- TODO: Partial ? list of parameters
constant pulsetime : in integer; -- Pulse time in clock cycles
constant timefactor : in real; -- Fixed point time scale factor
constant gainfactor : in real; -- Fixed point gain value. Max value 1.0 is hex X"8000". Gain 0.5 is therefore X"4000"
constant wavestartaddr : in integer; -- Start address in waveform RAM
constant wavesteps : in integer; -- Number of steps in waveform rise and fall
constant wavetopwidth : in integer; -- Number of clock cycles in waveform top between end of rise and start of fall
signal cpu_sel : out std_logic;
signal cpu_wr : out std_logic;
signal cpu_addr : out std_logic_vector(15 downto 0);
signal cpu_wdata : out std_logic_vector(31 downto 0)
) is
-- Vectors for converted values
variable slv_pulsetime : std_logic_vector(23 downto 0); -- For 24-bit pulse time
variable slv_timefactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point timestep
variable slv_gainfactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point gain
variable slv_wavestartaddr : std_logic_vector( 9 downto 0); -- For 10-bit address i.e. 1024 point waveform RAM
variable slv_wavesteps : std_logic_vector( 9 downto 0); -- For 10-bit number of steps i.e. 0 = 1 step, X"3FF" = 1024 points
variable slv_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit number of clock cycles in top of waveform
variable slv_entry_data : std_logic_vector(95 downto 0); -- Vector for entire memory entry
-- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg
-- Define the number of fractional bits
constant BIT_FRAC : integer := 4; -- TODO: this should be defined in qlaser_pkg
begin
-- Convert each field into its std_logic_vector equivalent
slv_pulsetime := std_logic_vector(to_unsigned(pulsetime, 24));
slv_timefactor := std_logic_vector(to_unsigned(integer(timefactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
slv_gainfactor := std_logic_vector(to_unsigned(integer(gainfactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
slv_wavestartaddr := std_logic_vector(to_unsigned(wavestartaddr, 10));
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
--etc, etc.
-- Build full entry out of component fields. Final length should be 96 bits.
slv_entry_data := "000" & slv_pulsetime & slv_timefactor & slv_gainfactor & slv_wavestartaddr & slv_wavesteps & slv_wavetopwidth; -- This might not correct
-- Write 96-bit entry in 3 writes. (Address is an integer)
cpu_write(clk, ADR_RAM_PULSE+(4*num_entry) , slv_entry_data(31 downto 0), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(4*num_entry)+1 , slv_entry_data(63 downto 32), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
cpu_write(clk, ADR_RAM_PULSE+(4*num_entry)+2 , slv_entry_data(95 downto 64), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
end;
-------------------------------------------------------------
-- CPU write procedure. Address and Data in decimal
-------------------------------------------------------------
procedure cpu_write(
signal clk : in std_logic;
constant a : in integer;
constant d : in integer;
signal cpu_sel : out std_logic;
signal cpu_wr : out std_logic;
signal cpu_addr : out std_logic_vector(15 downto 0);
signal cpu_wdata : out std_logic_vector(31 downto 0)
) is
begin
cpu_write(clk, a , std_logic_vector(to_unsigned(d,32)), cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
end;
-------------------------------------------------------------
-- CPU read procedure
-------------------------------------------------------------
procedure cpu_read(
signal clk : in std_logic;
constant a : in integer;
constant exp_d : in std_logic_vector(31 downto 0);
signal cpu_sel : out std_logic;
signal cpu_wr : out std_logic;
signal cpu_addr : out std_logic_vector(15 downto 0);
signal cpu_wdata : out std_logic_vector(31 downto 0);
signal cpu_rdata : in std_logic_vector(31 downto 0);
signal cpu_rdata_dv : in std_logic
) is
variable v_bdone : boolean := false;
variable str_out : string(1 to 256);
begin
wait until clk'event and clk='0';
cpu_sel <= '1';
cpu_wr <= '0';
cpu_addr <= std_logic_vector(to_unsigned(a, 16));
cpu_wdata <= (others=>'0');
while (v_bdone = false) loop
wait until clk'event and clk='0';
cpu_sel <= '1';
if (cpu_rdata_dv = '1') then
if (cpu_rdata /= exp_d) then
fprint(str_out, "Read exp: 0x%s actual: 0x%s\n", to_string(to_bitvector(exp_d),"%08X"), to_string(to_bitvector(cpu_rdata),"%08X"));
report str_out severity error;
end if;
v_bdone := true;
cpu_sel <= '0';
cpu_addr <= (others=>'0');
end if;
end loop;
wait until clk'event and clk='0';
wait until clk'event and clk='0';
end;
-------------------------------------------------------------
-- CPU read pulse definition RAM
-- Use 96 bit data to make three 32-bit writes
-------------------------------------------------------------
procedure cpu_read_pulsedef(
signal clk : in std_logic;
constant num_entry : in integer;
-- TODO: Partial ? list of parameters
constant pulsetime : in integer; -- Pulse time in clock cycles
constant timefactor : in real; -- Fixed point time scale factor
constant gainfactor : in real; -- Fixed point gain value. Max value 1.0 is hex X"8000". Gain 0.5 is therefore X"4000"
constant wavestartaddr : in integer; -- Start address in waveform RAM
constant wavesteps : in integer; -- Number of steps in waveform rise and fall
constant wavetopwidth : in integer; -- Number of clock cycles in waveform top between end of rise and start of fall
signal cpu_sel : out std_logic;
signal cpu_wr : out std_logic;
signal cpu_addr : out std_logic_vector(15 downto 0);
signal cpu_wdata : out std_logic_vector(31 downto 0)
) is
-- Vectors for converted values
variable slv_pulsetime : std_logic_vector(23 downto 0); -- For 24-bit pulse time
variable slv_timefactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point timestep
variable slv_gainfactor : std_logic_vector(15 downto 0); -- For 16-bit fixed point gain
variable slv_wavestartaddr : std_logic_vector( 9 downto 0); -- For 10-bit address i.e. 1024 point waveform RAM
variable slv_wavesteps : std_logic_vector( 9 downto 0); -- For 10-bit number of steps i.e. 0 = 1 step, X"3FF" = 1024 points
variable slv_wavetopwidth : std_logic_vector(16 downto 0); -- For 17-bit number of clock cycles in top of waveform
variable slv_entry_data : std_logic_vector(95 downto 0); -- Vector for entire memory entry
-- constant ADR_PULSE_DEF : integer := to_integer(unsigned(X"?????")); -- Use address of pulse definition RAM from qlaser_pkg
-- Define the number of fractional bits
constant BIT_FRAC : integer := 4; -- TODO: this should be defined in qlaser_pkg
begin
-- Convert each field into its std_logic_vector equivalent
slv_pulsetime := std_logic_vector(to_unsigned(pulsetime, 24));
slv_timefactor := std_logic_vector(to_unsigned(integer(timefactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
slv_gainfactor := std_logic_vector(to_unsigned(integer(gainfactor * real(2**BIT_FRAC)), 16)); -- Convert real to std_logic_vector keeping the fractional part
slv_wavestartaddr := std_logic_vector(to_unsigned(wavestartaddr, 10));
slv_wavesteps := std_logic_vector(to_unsigned(wavesteps, 10));
slv_wavetopwidth := std_logic_vector(to_unsigned(wavetopwidth, 17));
--etc, etc.
-- Build full entry out of component fields. Final length should be 96 bits.
slv_entry_data := "000" & slv_pulsetime & slv_timefactor & slv_gainfactor & slv_wavestartaddr & slv_wavesteps & slv_wavetopwidth; -- This might not correct
-- Write 96-bit entry in 3 writes. (Address is an integer)
cpu_read(clk, ADR_RAM_PULSE+(4*num_entry), slv_entry_data(31 downto 0), cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
cpu_read(clk, ADR_RAM_PULSE+(4*num_entry) + 1, slv_entry_data(63 downto 32), cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
cpu_read(clk, ADR_RAM_PULSE+(4*num_entry) + 2, slv_entry_data(95 downto 64), cpu_sel, cpu_wr, cpu_addr, cpu_wdata, cpu_rdata, cpu_rdata_dv);
end;
-------------------------------------------------------------
-- Delay
-------------------------------------------------------------
procedure clk_delay(
constant nclks : in integer
) is
begin
for I in 0 to nclks loop
wait until clk'event and clk ='0';
end loop;
end;
----------------------------------------------------------------
-- Print a string with no time or instance path.
----------------------------------------------------------------
procedure cpu_print_msg(
constant msg : in string
) is
variable line_out : line;
begin
write(line_out, msg);
writeline(output, line_out);
end procedure cpu_print_msg;
begin
-------------------------------------------------------------
-- Unit Under Test
-------------------------------------------------------------
u_dac_pulse : entity work.qlaser_dacs_pulse_channel
port map (
clk => clk , -- in std_logic;
reset => reset , -- in std_logic;
enable => enable , -- out std_logic;
start => start , -- out std_logic;
cnt_time => cnt_time , -- out std_logic_vector(23 downto 0); -- Set to '1' while SPI interface is busy
busy => busy , -- out std_logic; -- Set to '1' while SPI interface is busy
-- CPU interface
cpu_wr => cpu_wr , -- in std_logic;
cpu_sel => cpu_sel , -- in std_logic;
cpu_addr => cpu_addr( 9 downto 0) , -- in std_logic_vector(11 downto 0);
cpu_wdata => cpu_wdata , -- in std_logic_vector(31 downto 0);
cpu_rdata => cpu_rdata , -- out std_logic_vector(31 downto 0);
cpu_rdata_dv => cpu_rdata_dv , -- out std_logic;
-- AXI-Stream interface
axis_tready => axis_tready , -- in std_logic; -- Clock (50 MHz max)
axis_tdata => axis_tdata , -- out std_logic_vector(15 downto 0);
axis_tvalid => axis_tvalid , -- out std_logic; -- Master out, Slave in. (Data to DAC)
axis_tlast => axis_tlast -- out std_logic; -- Active low chip select (sync_n)
);
-------------------------------------------------------------
-- Generate system clock. Halt when sim_done is true.
-------------------------------------------------------------
pr_clk : process
begin
clk <= '0';
wait for (CLK_PER/2);
clk <= '1';
wait for (CLK_PER-CLK_PER/2);
if (sim_done=true) then
wait;
end if;
end process;
-------------------------------------------------------------
-- Reset and drive CPU bus
-------------------------------------------------------------
pr_main : process
variable v_ndata32 : integer := 0;
variable v_ndata16 : integer := 0;
begin
-- Reset
reset <= '1';
enable <= '0';
start <= '0';
cnt_time <= (others=>'0');
cpu_sel <= '0';
cpu_wr <= '0';
cpu_wdata <= (others=>'0');
cpu_addr <= (others=>'0');
cpu_print_msg("Simulation start");
clk_delay(5);
reset <= '0';
clk_delay(5);
enable <= '1';
clk_delay(20);
----------------------------------------------------------------
-- Load pulse RAM with a series of pulse start times
----------------------------------------------------------------
v_ndata32 := 128; -- Time for first pulse
cpu_print_msg("Load pulse RAM");
for NADDR in 0 to 15 loop
-- cpu_write(clk, ADR_RAM_PULSE + NADDR , v_ndata32 + (NADDR*(1024+32)), cpu_sel, cpu_wr, cpu_addr, cpu_wdata); -- TODO: rn don't know how to make it write three difference places, for now I', just gonna manually write it
cpu_write_pulsedef(clk, NADDR, v_ndata32 + (NADDR*(1024+32)), 1.0, 1.0, 0, NADDR*32, 512, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
end loop;
cpu_print_msg("Pulse RAM loaded");
clk_delay(20);
----------------------------------------------------------------
-- Read back Pulse RAM.
----------------------------------------------------------------
v_ndata32 := 128; -- Time for first pulse
for NADDR in 0 to 15 loop
cpu_read_pulsedef(clk, NADDR, v_ndata32 + (NADDR*(1024+32)), 1.0, 1.0, 0, NADDR*32, 512, cpu_sel, cpu_wr, cpu_addr, cpu_wdata);
end loop;
clk_delay(20);
wait for 10 us;
cpu_print_msg("Simulation done");
clk_delay(5);
sim_done <= true;
wait;
end process;
end behave;

View File

@ -1 +1,2 @@
Please put your modelsim.ini file in this directory and compile modelsim in this directory.

2
tools/sim/compile.bat Normal file
View File

@ -0,0 +1,2 @@
echo off
vsim -c -quiet -do compile.do

8
tools/sim/compile.do Normal file
View File

@ -0,0 +1,8 @@
vlib work
vcom ../../src/hdl/ip_gen/*.vhd*
vcom ../../src/hdl/pkg/*pkg.vhd
vcom ../../src/hdl/pkg/iopakp.vhd
vcom ../../src/hdl/pkg/iopakb.vhd
vcom ../../src/hdl/modules/*.vhd*
vcom ../../src/hdl/tb/*.vhd*

13
tools/sim/run.do Normal file
View File

@ -0,0 +1,13 @@
do compile.do
vsim -voptargs="+acc" -lib work tb_cpubus_dacs_pulse_channel
do waves_do/pp_rw_cpu.do
view wave
view structure
view signals
run -all
# End

View File

@ -0,0 +1,34 @@
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/reset
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/clk
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cnt_time
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/busy
add wave -noupdate -radix binary /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_addr
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_wdata
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_wr
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_sel
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_rdata
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/cpu_rdata_dv
add wave -noupdate -radix unsigned /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_addra
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_dina
add wave -noupdate -radix hexadecimal /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_douta
add wave -noupdate /tb_cpubus_dacs_pulse_channel/u_dac_pulse/ram_pulse_we
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {480433536 fs} 0}
quietly wave cursor active 1
configure wave -namecolwidth 150
configure wave -valuecolwidth 172
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits fs
update
WaveRestoreZoom {0 fs} {1953088753 fs}