Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Whitney Knitter
Published © GPL3+

DSP for FPGA: Custom AXI4-Stream FIR filter IP in Vivado

Using Vivado's built in AXI wrapper tool, this project goes over how to add an AXI4Stream interface to a custom FIR filter in Verilog.

AdvancedFull instructions provided2 hours7,139
DSP for FPGA: Custom AXI4-Stream FIR filter IP in Vivado

Things used in this project

Story

Read more

Code

fir.v

Verilog
`timescale 1ns / 1ps

module FIR(
    input clk,
    input reset,
    input enable_fir,
    input signed [15:0] fir_data_in,
    output reg signed [31:0] fir_data_out 
    );
    
    // 15-tap FIR 
    reg signed [15:0] buff0, buff1, buff2, buff3, buff4, buff5, buff6, buff7, buff8, buff9, buff10, buff11, buff12, buff13, buff14;
    wire signed [15:0] tap0, tap1, tap2, tap3, tap4, tap5, tap6, tap7, tap8, tap9, tap10, tap11, tap12, tap13, tap14; 
    reg signed [31:0] acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7, acc8, acc9, acc10, acc11, acc12, acc13, acc14; 

    
    /* Taps for LPF running @ 100MSps with passband from 0 Hz - 10 MHz */
    assign tap0 = 16'hfe64;
    assign tap1 = 16'hfc8a; 
    assign tap2 = 16'hfc04; 
    assign tap3 = 16'hff93; 
    assign tap4 = 16'h0883; 
    assign tap5 = 16'h14ef; 
    assign tap6 = 16'h1ff7; 
    assign tap7 = 16'h2463; 
    assign tap8 = 16'h1ff7; 
    assign tap9 = 16'h14ef;
    assign tap10 = 16'h0883; 
    assign tap11 = 16'hff93; 
    assign tap12 = 16'hfc04; 
    assign tap13 = 16'hfc8a; 
    assign tap14 = 16'hfe64;

	/* Circular buffer w/ multiply stage of FIR */    
	always @ (posedge clk)
        begin
            if(enable_fir == 1'b1)
                begin
                    buff0 <= fir_data_in;
                    acc0 <= tap0 * buff0;
                    
                    buff1 <= buff0;  
                    acc1 <= tap1 * buff1;
                          
                    buff2 <= buff1; 
                    acc2 <= tap2 * buff2;
                            
                    buff3 <= buff2;     
                    acc3 <= tap3 * buff3;
                     
                    buff4 <= buff3;  
                    acc4 <= tap4 * buff4;
                        
                    buff5 <= buff4; 
                    acc5 <= tap5 * buff5;
                          
                    buff6 <= buff5;  
                    acc6 <= tap6 * buff6;
                      
                    buff7 <= buff6; 
                    acc7 <= tap7 * buff7;
                          
                    buff8 <= buff7;  
                    acc8 <= tap8 * buff8;
                         
                    buff9 <= buff8;     
                    acc9 <= tap9 * buff9;
                      
                    buff10 <= buff9;   
                    acc10 <= tap10 * buff10;
                         
                    buff11 <= buff10;    
                    acc11 <= tap11 * buff11;
                       
                    buff12 <= buff11;    
                    acc12 <= tap12 * buff12;
                       
                    buff13 <= buff12;  
                    acc13 <= tap13 * buff13;  
                       
                    buff14 <= buff13;  
                    acc14 <= tap14 * buff14;  
                end
        end   
        
    /* Accumulate stage of FIR */   
    always @ (posedge clk) 
        begin
            if (enable_fir == 1'b1)
                begin
                    fir_data_out <= acc0 + acc1 + acc2 + acc3 + acc4 + acc5 + acc6 + acc7 + acc8 + acc9 + acc10 + acc11 + acc12 + acc13 + acc14;
                end
        end 
    
endmodule

AXIS_FIR_v1_0.v

Verilog
`timescale 1 ns / 1 ps

module AXIS_FIR_v1_0 # 
    (
        // Users to add parameters here
        
        // User parameters ends
        // Do not modify the parameters beyond this line
        
        
        // Parameters of Axi Slave Bus Interface S_AXIS
        parameter integer C_S_AXIS_TDATA_WIDTH	= 16,
        
        // Parameters of Axi Master Bus Interface M_AXIS
        parameter integer C_M_AXIS_TDATA_WIDTH	= 32,
        parameter integer C_M_AXIS_START_COUNT	= 32
    )
    (
        // Users to add ports here
        
        input wire [3:0] s_axis_tkeep,
        output wire [3:0] m_axis_tkeep,
        
        // User ports ends
        // Do not modify the ports beyond this line
        
        
        // Ports of Axi Slave Bus Interface S_AXIS
        input wire  s_axis_aclk,
        input wire  s_axis_aresetn,
        output wire  s_axis_tready,
        input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] s_axis_tdata,
        input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] s_axis_tstrb,
        input wire  s_axis_tlast,
        input wire  s_axis_tvalid,
        
        // Ports of Axi Master Bus Interface M_AXIS
        input wire  m_axis_aclk,
        input wire  m_axis_aresetn,
        output wire  m_axis_tvalid,
        output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] m_axis_tdata,
        output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] m_axis_tstrb,
        output wire  m_axis_tlast,
        input wire  m_axis_tready
    );
    
    wire [C_S_AXIS_TDATA_WIDTH-1 : 0] fir_data_in;
    wire [C_M_AXIS_TDATA_WIDTH-1 : 0] fir_data_out;

    // Instantiation of Axi Bus Interface S_AXIS
    AXIS_FIR_v1_0_S_AXIS # ( 
        .C_S_AXIS_TDATA_WIDTH(C_S_AXIS_TDATA_WIDTH)
    ) AXIS_FIR_v1_0_S_AXIS_inst (
        .s_axis_tkeep(s_axis_tkeep),
        .enable_fir(enable_fir),
        .fir_data_in(fir_data_in),
        .S_AXIS_ACLK(s_axis_aclk),
        .S_AXIS_ARESETN(s_axis_aresetn),
        .S_AXIS_TREADY(s_axis_tready),
        .S_AXIS_TDATA(s_axis_tdata),
        .S_AXIS_TSTRB(s_axis_tstrb),
        .S_AXIS_TLAST(s_axis_tlast),
        .S_AXIS_TVALID(s_axis_tvalid)
    );

    // Instantiation of Axi Bus Interface M_AXIS
    AXIS_FIR_v1_0_M_AXIS # ( 
        .C_M_AXIS_TDATA_WIDTH(C_M_AXIS_TDATA_WIDTH),
        .C_M_START_COUNT(C_M_AXIS_START_COUNT)
    ) AXIS_FIR_v1_0_M_AXIS_inst (
        .m_axis_tkeep(m_axis_tkeep),
        .enable_fir(enable_fir),
        .fir_data_out(fir_data_out),
        .M_AXIS_ACLK(s_axis_aclk),
        .M_AXIS_ARESETN(s_axis_aresetn),
        .M_AXIS_TVALID(m_axis_tvalid),
        .M_AXIS_TDATA(m_axis_tdata),
        .M_AXIS_TSTRB(m_axis_tstrb),
        .M_AXIS_TLAST(m_axis_tlast),
        .M_AXIS_TREADY(m_axis_tready)
    );

    // Add user logic here	
    FIR LPF_FIR_inst (
        .clk(s_axis_aclk),
        .reset(s_axis_aresetn),
        .enable_fir(enable_fir),
        .fir_data_in(fir_data_in), //16
        .fir_data_out(fir_data_out) //32 
    );
    
    // User logic ends

endmodule

AXIS_FIR_v1_0_M_AXIS.v

Verilog
`timescale 1ns / 1ps

module AXIS_FIR_v1_0_M_AXIS #
    (
        // Users to add parameters here
        
        // User parameters ends
        // Do not modify the parameters beyond this line
        
        // Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
        parameter integer C_M_AXIS_TDATA_WIDTH	= 32,
        // Start count is the number of clock cycles the master will wait before initiating/issuing any transaction.
        parameter integer C_M_START_COUNT	= 32
    )
	(
        // Users to add ports here
        output reg [3:0] m_axis_tkeep,
        input wire enable_fir,
        input wire [C_M_AXIS_TDATA_WIDTH-1 : 0] fir_data_out,
        
        // User ports ends
        // Do not modify the ports beyond this line
        
        // Global ports
        input wire  M_AXIS_ACLK,
        // 
        input wire  M_AXIS_ARESETN,
        // Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted. 
        output wire  M_AXIS_TVALID,
        // TDATA is the primary payload that is used to provide the data that is passing across the interface from the master.
        output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA,
        // TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte.
        output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB,
        // TLAST indicates the boundary of a packet.
        output wire  M_AXIS_TLAST,
        // TREADY indicates that the slave can accept a transfer in the current cycle.
        input wire  M_AXIS_TREADY 
	);
	
	// Total number of output data                                                 
	localparam NUMBER_OF_OUTPUT_WORDS = 8;                                               
	                                                                                     
	// function called clogb2 that returns an integer which has the value of the ceiling of the log base 2.                                           
	function integer clogb2 (input integer bit_depth);                                   
        begin                                                                              
            for(clogb2=0; bit_depth>0; clogb2=clogb2+1)                                      
                bit_depth = bit_depth >> 1;                                                    
        end                                                                                
	endfunction                                                                          
	                                                                                     
	// WAIT_COUNT_BITS is the width of the wait counter.                                 
	localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1);                      
	                                                                                     
	// bit_num gives the minimum number of bits needed to address 'depth' size of FIFO.  
	localparam bit_num  = clogb2(NUMBER_OF_OUTPUT_WORDS);                                
	                                                                                     
	// Define the states of state machine                                                
	// The control state machine oversees the writing of input streaming data to the FIFO, and outputs the streaming data from the FIFO                                      
	parameter [1:0] IDLE          = 2'b00, // This is the initial/idle state                                                                                  
	                INIT_COUNTER  = 2'b01, // This state initializes the counter, once the counter reaches C_M_START_COUNT count, the state machine changes state to SEND_STREAM     
	                SEND_STREAM   = 2'b10; // In this state the stream data is output through M_AXIS_TDATA   
	
	// State variable                                                                    
	reg [1:0] mst_exec_state;  
	                                                          
	// Example design FIFO read pointer                                                  
	reg [bit_num-1:0] read_pointer;                                                      

	// AXI Stream internal signals
	//wait counter. The master waits for the user defined number of clock cycles before initiating a transfer.
	reg [WAIT_COUNT_BITS-1 : 0] count;
	
	//streaming data valid
	wire axis_tvalid;
	
	//streaming data valid delayed by one clock cycle
	reg axis_tvalid_delay;
	
	//Last of the streaming data 
	wire axis_tlast;
	
	//Last of the streaming data delayed by one clock cycle
	reg axis_tlast_delay;
	
	//FIFO implementation signals
	reg [C_M_AXIS_TDATA_WIDTH-1 : 0] stream_data_out;
	wire tx_en;
	
	//The master has issued all the streaming data stored in FIFO
	reg tx_done;


	// I/O Connections assignments
	assign M_AXIS_TVALID = axis_tvalid_delay;
	assign M_AXIS_TDATA	 = stream_data_out;
	assign M_AXIS_TLAST	 = axis_tlast_delay;
	assign M_AXIS_TSTRB	 = {(C_M_AXIS_TDATA_WIDTH/8){1'b1}};


    // Control state machine implementation                             
    always @(posedge M_AXIS_ACLK)                                             
        begin                                                                     
            if (!M_AXIS_ARESETN)                                                    
                // Synchronous reset (active low)                                       
                begin                                                                 
                    mst_exec_state <= IDLE;                                             
                    count    <= 0;                                                      
                end                                                                   
            else                                                                    
                case (mst_exec_state)                                                 
                    IDLE:                                                               
                        // The slave starts accepting tdata when there tvalid is asserted to mark the presence of valid streaming data                               
                        //if (count == 0)                                                 
                            //begin                                                           
                                mst_exec_state <= INIT_COUNTER;                              
                            //end                                                             
                        //else                                                              
                            //begin                                                           
                                //mst_exec_state <= IDLE;                                      
                            //end                                                             
                                                                          
                    INIT_COUNTER:                                                       
                        // The slave starts accepting tdata when there tvalid is asserted to mark the presence of valid streaming data                               
                        if (count == C_M_START_COUNT - 1)                               
                            begin                                                           
                                mst_exec_state <= SEND_STREAM;                               
                            end                                                             
                        else                                                              
                            begin                                                           
                                count <= count + 1;                                           
                                mst_exec_state <= INIT_COUNTER;                              
                            end                                                             
                                                                          
                    SEND_STREAM:                                                        
                        // The example design streaming master functionality starts when the master drives output tdata from the FIFO and the slave
                        // has finished storing the S_AXIS_TDATA                          
                        if (tx_done)                                                      
                            begin                                                           
//                                mst_exec_state <= IDLE;  
                                mst_exec_state <= INIT_COUNTER;
                                count <= 0;                                     
                            end                                                             
                        else                                                              
                            begin                                                           
                                mst_exec_state <= SEND_STREAM;                                
                            end                                                             
                endcase                                                               
        end                                                                       


	//tvalid generation
	//axis_tvalid is asserted when the control state machine's state is SEND_STREAM and number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
//	assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
    assign axis_tvalid = (mst_exec_state != IDLE);
	                                                                                               
	// AXI tlast generation                                                                        
	// axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1(0 to NUMBER_OF_OUTPUT_WORDS-1)                                                             
	assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);                                
                                                                              
	// Delay the axis_tvalid and axis_tlast signal by one clock cycle to match the latency of M_AXIS_TDATA                                                        
    always @(posedge M_AXIS_ACLK)                                                                  
        begin                                                                                          
            if (!M_AXIS_ARESETN)                                                                         
                begin                                                                                      
                    axis_tvalid_delay <= 1'b0;                                                               
                    axis_tlast_delay <= 1'b0;                                                                
                end                                                                                        
            else                                                                                         
                begin                                                                                      
                    axis_tvalid_delay <= axis_tvalid;                                                        
                    axis_tlast_delay <= axis_tlast;                                                          
                end                                                                                        
        end                                                                                            


	//read_pointer pointer
    always@(posedge M_AXIS_ACLK)                                               
        begin                                                                            
            if(!M_AXIS_ARESETN)                                                            
                begin                                                                        
                    read_pointer <= 0;                                                         
                    tx_done <= 1'b0;                                                           
                end                                                                          
            else                                                                           
            if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1)                                
                begin                                                                      
                    if (tx_en)                                                               
                        // read pointer is incremented after every read from the FIFO when FIFO read signal is enabled.                                   
                        begin                                                                  
                            read_pointer <= read_pointer + 1;                                    
                            tx_done <= 1'b0;                                                     
                        end                                                                    
                end                                                                        
            else if (read_pointer == NUMBER_OF_OUTPUT_WORDS)                             
                begin                                                                      
                    // tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers of streaming data has been out.                                                         
                    tx_done <= 1'b1;   
                    read_pointer <= 0; // added this line so that an M_AXIS_ARESETN event isn't needed to start another transfer of NUMBER_OF_OUTPUT_WORDS                                                   
                end                                                                        
        end                                                                              


	//FIFO read enable generation 
	assign tx_en = M_AXIS_TREADY && axis_tvalid;   
	                                                     
    // Streaming output data is read from FIFO       
    always @( posedge M_AXIS_ACLK )                  
        begin                                            
            if(!M_AXIS_ARESETN)                            
                begin                                        
                    stream_data_out <= 1;                      
                end                                          
            else if (tx_en)// && M_AXIS_TSTRB[byte_index]  
                begin                                        
                    stream_data_out <= fir_data_out; //read_pointer + 32'b1;   
                end                                          
        end                                              

    // Add user logic here
    always @ (posedge M_AXIS_ACLK)
        begin
            if (enable_fir == 1'b1 && M_AXIS_ARESETN == 1'b1)
                begin
                    m_axis_tkeep <= 4'hf;
                end
            else
                begin
                    m_axis_tkeep <= 4'h0;
                end
        end    

	// User logic ends 
	
endmodule

AXIS_FIR_v1_0_S_AXIS.v

Verilog
`timescale 1 ns / 1 ps

module AXIS_FIR_v1_0_S_AXIS #
    (
        // Users to add parameters here
        
        // User parameters ends
        // Do not modify the parameters beyond this line
        
        // AXI4Stream sink: Data Width
        parameter integer C_S_AXIS_TDATA_WIDTH	= 16
    )
    (
        // Users to add ports here
        input wire [3:0] s_axis_tkeep,
        output reg enable_fir,
        output reg [C_S_AXIS_TDATA_WIDTH-1 : 0] fir_data_in,
        
        // User ports ends
        // Do not modify the ports beyond this line
        
        // AXI4Stream sink: Clock
        input wire  S_AXIS_ACLK,
        // AXI4Stream sink: Reset
        input wire  S_AXIS_ARESETN,
        // Ready to accept data in
        output wire  S_AXIS_TREADY,
        // Data in
        input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA,
        // Byte qualifier
        input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB,
        // Indicates boundary of last packet
        input wire  S_AXIS_TLAST,
        // Data is in valid
        input wire  S_AXIS_TVALID
    );
    
    // function called clogb2 that returns an integer which has the value of the ceiling of the log base 2.
    function integer clogb2 (input integer bit_depth);
        begin
            for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
                bit_depth = bit_depth >> 1;
        end
    endfunction

    // Total number of input data.
    localparam NUMBER_OF_INPUT_WORDS  = 8;
    
    // bit_num gives the minimum number of bits needed to address 'NUMBER_OF_INPUT_WORDS' size of FIFO.
    localparam bit_num  = clogb2(NUMBER_OF_INPUT_WORDS-1);
    
    // Define the states of state machine
    // The control state machine oversees the writing of input streaming data to the FIFO, and outputs the streaming data from the FIFO
    parameter [1:0] IDLE        = 1'b0, // This is the initial/idle state 
                    WRITE_FIFO  = 1'b1; // In this state FIFO is written with the input stream data S_AXIS_TDATA 
                    
//    wire axis_tready;
    reg axis_tready;
    
    // State variable
    reg mst_exec_state; 
     
    // FIFO implementation signals
    genvar byte_index;   
      
    // FIFO write enable
    wire fifo_wren;
    
    // FIFO full flag
    reg fifo_full_flag;
    
    // FIFO write pointer
    reg [bit_num-1:0] write_pointer;
    
    // sink has accepted all the streaming data and stored in FIFO
    reg writes_done;
    
    // I/O Connections assignments
    assign S_AXIS_TREADY = axis_tready;
    
    // Control state machine implementation
    always @ (posedge S_AXIS_ACLK) 
        begin  
            if (!S_AXIS_ARESETN) 
                // Synchronous reset (active low)
                begin
                  mst_exec_state <= IDLE;
                  axis_tready <= 1'b0;
                end  
            else
                case (mst_exec_state)
                    IDLE: 
                        // The sink starts accepting tdata when there tvalid is asserted to mark the presence of valid streaming data 
                        if (S_AXIS_TVALID)
                            begin
                                mst_exec_state <= WRITE_FIFO;
                                axis_tready <= 1'b1; // added to prevent one low clock cycle of tready so tvalid from DDS compiler isn't deasserted, causing dropped samples input to FIR
                            end
                        else
                            begin
                                mst_exec_state <= IDLE;
                                axis_tready <= 1'b0; // added to prevent one low clock cycle of tready so tvalid from DDS compiler isn't deasserted, causing dropped samples input to FIR
                            end
                    WRITE_FIFO: 
                        // When the sink has accepted all the streaming input data, the interface swiches functionality to a streaming master
                        if (writes_done)
                            begin
                                mst_exec_state <= IDLE;
                            end
                        else
                            begin
                                // The sink accepts and stores tdata into FIFO
                                mst_exec_state <= WRITE_FIFO;
                            end
                
                endcase
        end
        
    // AXI Streaming Sink 
    // 
    // The example design sink is always ready to accept the S_AXIS_TDATA  until the FIFO is not filled with NUMBER_OF_INPUT_WORDS number of input words.
    //assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1));
    // above is commented out to prevent one low clock cycle of tready so tvalid from DDS compiler isn't deasserted, causing dropped samples input to FIR

    always@(posedge S_AXIS_ACLK)
        begin
            if(!S_AXIS_ARESETN)
                begin
                    write_pointer <= 0;
                    writes_done <= 1'b0;
                end  
            else
                if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
                    begin
                        if (fifo_wren)
                            begin
                                // write pointer is incremented after every write to the FIFO when FIFO write signal is enabled.
                                write_pointer <= write_pointer + 1;
                                writes_done <= 1'b0;
                            end
                        if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
                            begin
                                // reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
                                writes_done <= 1'b1;
                            end
                    end  
        end

    // FIFO write enable generation
    assign fifo_wren = S_AXIS_TVALID && axis_tready;
    
    // FIFO Implementation
    generate 
        for (byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
            begin:FIFO_GEN
            
                reg  [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];
            
                // Streaming input data is stored in FIFO
                always @ (posedge S_AXIS_ACLK)
                    begin
                        if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
                            begin
                                stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
                            end  
                    end  
            end		
    endgenerate

    // Add user logic here  
    
    always @ (posedge S_AXIS_ACLK)
        begin  
            if (!S_AXIS_ARESETN)
                begin 
                    enable_fir <= 1'b0;
                    fir_data_in <= 16'd0;
                end
            else if (fifo_wren)
                begin
                    enable_fir <= 1'b1;
                    fir_data_in <= S_AXIS_TDATA;
                end
            else 
                begin 
                    enable_fir <= enable_fir;
                    fir_data_in <= fir_data_in;
                end
        end  

    // User logic ends 
    
endmodule

sp701_bd_tb.v

Verilog
`timescale 1ns / 1ps

module sp701_bd_tb;

    reg clk_p, clk_n, reset;
    
    always begin
        clk_p = 1; clk_n = 0; #5;
        clk_p = 0; clk_n = 1; #5;
    end
    
    always begin
        reset = 1; #40;
        reset = 0; #1000000000;
    end
       
    sp701_bd sp701_bd_i (
        .reset(reset),
        .sys_diff_clock_clk_n(clk_p),
        .sys_diff_clock_clk_p(clk_n)
    );

endmodule

phase_inc_sm.v

Verilog
`timescale 1ns / 1ps

module phase_inc_sm(
    input clk,
    input reset,
    output reg m_axis_phase_tvalid,
    output reg m_axis_phase_tlast,
    input m_axis_phase_tready,
    output reg [31:0] m_axis_phase_tdata
    );

    wire [31:0] carrier_freq_100k;
    wire [31:0] carrier_period_100k;    
    wire [31:0] carrier_freq_200k;
    wire [31:0] carrier_period_200k;
    wire [31:0] carrier_freq_500k;
    wire [31:0] carrier_period_500k; 
    wire [31:0] carrier_freq_750k;
    wire [31:0] carrier_period_750k; 
    wire [31:0] carrier_freq_1m;
    wire [31:0] carrier_period_1m;    
    wire [31:0] carrier_freq_10m;
    wire [31:0] carrier_period_10m;
    wire [31:0] carrier_freq_20m;
    wire [31:0] carrier_period_20m; 
    wire [31:0] carrier_freq_45m;
    wire [31:0] carrier_period_45m;
    wire [31:0] carrier_freq_50m;
    wire [31:0] carrier_period_50m; 
    reg [31:0] carrier_freq;
    reg [31:0] carrier_period;           
    
    // 100 kHz
    assign carrier_freq_100k = 32'h83126;  //32'h418937;
    assign carrier_period_100k = 32'd1000;       
    
    // 200 kHz
    assign carrier_freq_200k = 32'h10624D; //32'h83126e;
    assign carrier_period_200k = 32'd500;
    
    // 500 kHz 
    assign carrier_freq_500k = 32'h28F5C2; //32'h147ae14;
    assign carrier_period_500k = 32'd200;
    
    // 750 kHz C0000000
    assign carrier_freq_750k = 32'h3D70A3; //32'h1eb851e;
    assign carrier_period_750k = 32'd133;
    
    // 1 MHz
    assign carrier_freq_1m = 32'h51EB85; //32'h28F5C28;
    assign carrier_period_1m = 32'd100; 
    
    // 10 MHz
    assign carrier_freq_10m = 32'h3333333; //32'h19999999;
    assign carrier_period_10m = 32'd10; 
    
    // 20 MHz
    assign carrier_freq_20m = 32'h6666666; //32'h33333333;
    assign carrier_period_20m = 32'd5;
    
    // 45 MHz
    assign carrier_freq_45m = 32'hE666666; //32'h73333333;
    assign carrier_period_45m = 32'd3;
    
    // 50 MHz
    assign carrier_freq_50m = 32'h10000000; //32'h80000000;
    assign carrier_period_50m = 32'd2;
    
    reg [2:0] state_reg;
    reg [31:0] period_wait_cnt;
    reg [3:0] cycle_cnt;
    
    parameter init               = 3'd0;
    parameter SetCarrierFreq     = 3'd1;
    parameter SetTvalidHigh      = 3'd2;
    parameter SetSlavePhaseValue = 3'd3;
    parameter CheckTready        = 3'd4;
    parameter WaitState          = 3'd5;   
    parameter SetTlastHigh       = 3'd6;
    parameter SetTlastLow        = 3'd7;
    
    initial 
        begin
            state_reg = 3'd0;
            m_axis_phase_tlast = 1'b0;
            m_axis_phase_tvalid = 1'b0;
            m_axis_phase_tdata = 32'd0;
        end
    
        
    
    always @ (posedge clk)
        begin                    
            // Default Outputs   
            
            if (reset == 1'b0)
                begin
                    m_axis_phase_tdata[31:0] <= 32'd0;
                    m_axis_phase_tlast <= 1'b0;
                    m_axis_phase_tvalid <= 1'b0;
                    cycle_cnt <= 4'd0;
                    state_reg <= init;
                end
            else
                begin
                    case(state_reg)
                        init : //0
                            begin
                                cycle_cnt <= 4'd0;
                                period_wait_cnt <= 32'd0;
                                m_axis_phase_tlast <= 1'b0;
                                m_axis_phase_tvalid <= 1'b0;
                                carrier_freq <= carrier_freq_1m;
                                state_reg <= SetCarrierFreq;// WaitForStart;
                            end
                            
                        SetCarrierFreq : //1
                            begin         
                                if (carrier_freq > carrier_freq_20m)
                                    begin
                                        carrier_freq <= carrier_freq_1m;
                                    end
                                else
                                    begin
                                        carrier_freq <= carrier_freq + carrier_freq_1m;
                                    end
                                
                                carrier_period <= carrier_period_1m;
                                state_reg <= SetTvalidHigh;
                            end
                            
                        SetTvalidHigh : //2
                            begin
                                m_axis_phase_tvalid <= 1'b1; //per PG141 - tvalid is set before tready goes high
                                state_reg <= SetSlavePhaseValue;
                            end
                            
                        SetSlavePhaseValue : //3
                            begin
                                m_axis_phase_tdata[31:0] <= carrier_freq;
                                state_reg <= CheckTready;
                            end
                            
                        CheckTready : //4
                            begin
                                if (m_axis_phase_tready == 1'b1)
                                    begin
                                        state_reg <= WaitState;
                                    end
                                else    
                                    begin
                                        state_reg <= CheckTready;
                                    end
                            end
                            
                        WaitState : //5
                            begin
                                if (period_wait_cnt >= carrier_period)
                                    begin
                                        period_wait_cnt <= 32'd0; 
                                        state_reg <= SetTlastHigh;
                                    end
                                else
                                    begin
                                        period_wait_cnt <= period_wait_cnt + 1;
                                        state_reg <= WaitState;
                                    end
                            end
                            
                        SetTlastHigh : //6
                            begin
                                m_axis_phase_tlast <= 1'b1;
                                state_reg <= SetTlastLow;
                            end
                            
                        SetTlastLow : //7
                            begin
                                m_axis_phase_tlast <= 1'b0;
                                state_reg <= SetCarrierFreq; 
                            end
                            
                    endcase 
                end
        end
        
endmodule

mem_dump_sm.v

Verilog
`timescale 1ns / 1ps

module mem_dump_sm(
    input clk,
    input reset,
    input signed [31:0] s_axis_mem_tdata,
    input [3:0] s_axis_mem_tkeep,
    input s_axis_mem_tlast,
    input s_axis_mem_tvalid,
    output s_axis_mem_tready
    );
    
    assign s_axis_mem_tready = 1'b1;
    
    reg signed [31:0] mem_location;
    
    always @ (posedge clk)
        begin
            if (s_axis_mem_tkeep == 4'hf && s_axis_mem_tvalid == 1'b1)
                begin
                    mem_location <= s_axis_mem_tdata;
                end
            else
                begin
                    mem_location <= mem_location;
                end
        end
endmodule

Credits

Whitney Knitter

Whitney Knitter

169 projects • 1726 followers
All thoughts/opinions are my own and do not reflect those of any company/entity I currently/previously associate with.

Comments