Full Code of alexforencich/verilog-dsp for AI

master 67c3ed7be5dc cached
43 files
191.2 KB
46.8k tokens
66 symbols
1 requests
Download .txt
Showing preview only (203K chars total). Download the full file or copy to clipboard to get everything.
Repository: alexforencich/verilog-dsp
Branch: master
Commit: 67c3ed7be5dc
Files: 43
Total size: 191.2 KB

Directory structure:
gitextract_6r_l5_gw/

├── .gitignore
├── .travis.yml
├── AUTHORS
├── COPYING
├── README.md
├── rtl/
│   ├── cic_decimator.v
│   ├── cic_interpolator.v
│   ├── dsp_iq_mult.v
│   ├── dsp_mult.v
│   ├── i2s_ctrl.v
│   ├── i2s_rx.v
│   ├── i2s_tx.v
│   ├── iq_join.v
│   ├── iq_split.v
│   ├── phase_accumulator.v
│   ├── sine_dds.v
│   └── sine_dds_lut.v
└── tb/
    ├── axis_ep.py
    ├── i2s_ep.py
    ├── test_cic_decimator.py
    ├── test_cic_decimator.v
    ├── test_cic_interpolator.py
    ├── test_cic_interpolator.v
    ├── test_dsp_iq_mult.py
    ├── test_dsp_iq_mult.v
    ├── test_dsp_mult.py
    ├── test_dsp_mult.v
    ├── test_i2s_ctrl.py
    ├── test_i2s_ctrl.v
    ├── test_i2s_rx.py
    ├── test_i2s_rx.v
    ├── test_i2s_tx.py
    ├── test_i2s_tx.v
    ├── test_iq_join.py
    ├── test_iq_join.v
    ├── test_iq_split.py
    ├── test_iq_split.v
    ├── test_phase_accumulator.py
    ├── test_phase_accumulator.v
    ├── test_sine_dds.py
    ├── test_sine_dds.v
    ├── test_sine_dds_lut.py
    └── test_sine_dds_lut.v

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*~
*.lxt
*.pyc
*.vvp
*.kate-swp



================================================
FILE: .travis.yml
================================================
language: python
python:
  - "3.4"
before_install:
  - export d=`pwd`
  - export PYTHON_EXE=`which python`
  - sudo apt-get update -qq
  - sudo apt-get install -y iverilog
  - git clone https://github.com/jandecaluwe/myhdl.git
  - cd $d/myhdl && sudo $PYTHON_EXE setup.py install
  - cd $d/myhdl/cosimulation/icarus && make && sudo install -m 0755 -D ./myhdl.vpi /usr/lib/ivl/myhdl.vpi
  - cd $d
script:
  - cd tb && py.test




================================================
FILE: AUTHORS
================================================
Alex Forencich <alex@alexforencich.com>


================================================
FILE: COPYING
================================================
Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.




================================================
FILE: README.md
================================================
Verilog DSP




================================================
FILE: rtl/cic_decimator.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Cascaded integrator-comb (CIC) Decimator
 */
module cic_decimator #(
    parameter WIDTH = 16,
    parameter RMAX = 2,
    parameter M = 1,
    parameter N = 2,
    parameter REG_WIDTH = WIDTH+$clog2((RMAX*M)**N)
)
(
    input  wire                      clk,
    input  wire                      rst,

    /*
     * AXI stream input
     */
    input  wire [WIDTH-1:0]          input_tdata,
    input  wire                      input_tvalid,
    output wire                      input_tready,

    /*
     * AXI stream output
     */
    output wire [REG_WIDTH-1:0]      output_tdata,
    output wire                      output_tvalid,
    input  wire                      output_tready,

    /*
     * Configuration
     */
    input  wire [$clog2(RMAX+1)-1:0] rate
);

/*
 * CIC decimator architecture
 *
 *                       ,---.
 * IN -->(+)--------+--->| V |----+------->(-)--- OUT
 *        ^         |    `---'    |         ^
 *        |         |             |         |
 *        +-- z-1 --+             +-- z-M --+
 *
 *       \___________/           \___________/
 *             N                       N
 *
 *         Integrate    Decimate     Comb
 *
 */

reg [$clog2(RMAX+1)-1:0] cycle_reg = 0;

reg [REG_WIDTH-1:0] int_reg[N-1:0];

wire [REG_WIDTH-1:0] int_reg_0 = int_reg[0];
wire [REG_WIDTH-1:0] int_reg_1 = int_reg[1];

reg [REG_WIDTH-1:0] comb_reg[N-1:0];

wire [REG_WIDTH-1:0] comb_reg_0 = comb_reg[0];
wire [REG_WIDTH-1:0] comb_reg_1 = comb_reg[1];

assign input_tready = output_tready | (cycle_reg != 0);

assign output_tdata = comb_reg[N-1];
assign output_tvalid = input_tvalid & cycle_reg == 0;

genvar k;
integer i;

initial begin
    for (i = 0; i < N; i = i + 1) begin
        int_reg[i] <= 0;
        comb_reg[i] <= 0;
    end
end

// integrator stages
generate

for (k = 0; k < N; k = k + 1) begin : integrator
    always @(posedge clk) begin
        if (rst) begin
            int_reg[k] <= 0;
        end else begin
            if (input_tready & input_tvalid) begin
                if (k == 0) begin
                    int_reg[k] <= $signed(int_reg[k]) + $signed(input_tdata);
                end else begin
                    int_reg[k] <= $signed(int_reg[k]) + $signed(int_reg[k-1]);
                end
            end
        end
    end
end

endgenerate

// comb stages
generate

for (k = 0; k < N; k = k + 1) begin : comb
    reg [REG_WIDTH-1:0] delay_reg[M-1:0];

    initial begin
        for (i = 0; i < M; i = i + 1) begin
            delay_reg[i] <= 0;
        end
    end

    always @(posedge clk) begin
        if (rst) begin
            for (i = 0; i < M; i = i + 1) begin
                delay_reg[i] <= 0;
            end
            comb_reg[k] <= 0;
        end else begin
            if (output_tready & output_tvalid) begin
                if (k == 0) begin
                    delay_reg[0] <= $signed(int_reg[N-1]);
                    comb_reg[k] <= $signed(int_reg[N-1]) - $signed(delay_reg[M-1]);
                end else begin
                    delay_reg[0] <= $signed(comb_reg[k-1]);
                    comb_reg[k] <= $signed(comb_reg[k-1]) - $signed(delay_reg[M-1]);
                end

                for (i = 0; i < M-1; i = i + 1) begin
                    delay_reg[i+1] <= delay_reg[i];
                end
            end
        end
    end
end

endgenerate

always @(posedge clk) begin
    if (rst) begin
        cycle_reg <= 0;
    end else begin
        if (input_tready & input_tvalid) begin
            if (cycle_reg < RMAX - 1 && cycle_reg < rate - 1) begin
                cycle_reg <= cycle_reg + 1;
            end else begin
                cycle_reg <= 0;
            end
        end
    end
end

endmodule


================================================
FILE: rtl/cic_interpolator.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Cascaded integrator-comb (CIC) Interpolator
 */
module cic_interpolator #(
    parameter WIDTH = 16,
    parameter RMAX = 2,
    parameter M = 1,
    parameter N = 2,
    parameter REG_WIDTH = WIDTH+$max(N, $clog2(((RMAX*M)**N)/RMAX))
)
(
    input  wire                      clk,
    input  wire                      rst,

    /*
     * AXI stream input
     */
    input  wire [WIDTH-1:0]          input_tdata,
    input  wire                      input_tvalid,
    output wire                      input_tready,

    /*
     * AXI stream output
     */
    output wire [REG_WIDTH-1:0]      output_tdata,
    output wire                      output_tvalid,
    input  wire                      output_tready,

    /*
     * Configuration
     */
    input  wire [$clog2(RMAX+1)-1:0] rate
);

/*
 * CIC interpolator architecture
 *
 *                       ,---.
 * IN ----+------->(-)-->| ^ |-->(+)--------+---- OUT
 *        |         ^    `---'    ^         |
 *        |         |             |         |
 *        +-- z-M --+             +-- z-1 --+
 *
 *       \___________/           \___________/
 *             N                       N
 *
 *           Comb      Upconvert   Integrate
 *
 */

reg [$clog2(RMAX+1)-1:0] cycle_reg = 0;

reg [REG_WIDTH-1:0] comb_reg[N-1:0];

reg [REG_WIDTH-1:0] int_reg[N-1:0];

assign input_tready = output_tready & (cycle_reg == 0);

assign output_tdata = int_reg[N-1];
assign output_tvalid = input_tvalid | (cycle_reg != 0);

genvar k;
integer i;

initial begin
    for (i = 0; i < N; i = i + 1) begin
        comb_reg[i] <= 0;
        int_reg[i] <= 0;
    end
end

// comb stages
generate

for (k = 0; k < N; k = k + 1) begin : comb
    reg [REG_WIDTH-1:0] delay_reg[M-1:0];

    initial begin
        for (i = 0; i < M; i = i + 1) begin
            delay_reg[i] <= 0;
        end
    end

    always @(posedge clk) begin
        if (rst) begin
            for (i = 0; i < M; i = i + 1) begin
                delay_reg[i] <= 0;
            end
            comb_reg[k] <= 0;
        end else begin
            if (input_tready & input_tvalid) begin
                if (k == 0) begin
                    delay_reg[0] <= $signed(input_tdata);
                    comb_reg[k] <= $signed(input_tdata) - $signed(delay_reg[M-1]);
                end else begin
                    delay_reg[0] <= $signed(comb_reg[k-1]);
                    comb_reg[k] <= $signed(comb_reg[k-1]) - $signed(delay_reg[M-1]);
                end

                for (i = 0; i < M-1; i = i + 1) begin
                    delay_reg[i+1] <= delay_reg[i];
                end
            end
        end
    end
end

endgenerate

// integrator stages
generate

for (k = 0; k < N; k = k + 1) begin : integrator
    always @(posedge clk) begin
        if (rst) begin
            int_reg[k] <= 0;
        end else begin
            if (output_tready & output_tvalid) begin
                if (k == 0) begin
                    if (cycle_reg == 0) begin
                        int_reg[k] <= $signed(int_reg[k]) + $signed(comb_reg[N-1]);
                    end
                end else begin
                    int_reg[k] <= $signed(int_reg[k]) + $signed(int_reg[k-1]);
                end
            end
        end
    end
end

endgenerate

always @(posedge clk) begin
    if (rst) begin
        cycle_reg <= 0;
    end else begin
        if (output_tready & output_tvalid) begin
            if (cycle_reg < RMAX - 1 && cycle_reg < rate - 1) begin
                cycle_reg <= cycle_reg + 1;
            end else begin
                cycle_reg <= 0;
            end
        end
    end
end

endmodule


================================================
FILE: rtl/dsp_iq_mult.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * IQ Multiplier - computes a*b
 */
module dsp_iq_mult #
(
    parameter WIDTH = 16
)
(
    input  wire                  clk,
    input  wire                  rst,

    /*
     * AXI stream inputs
     */
    input  wire [WIDTH-1:0]      input_a_i_tdata,
    input  wire [WIDTH-1:0]      input_a_q_tdata,
    input  wire                  input_a_tvalid,
    output wire                  input_a_tready,

    input  wire [WIDTH-1:0]      input_b_i_tdata,
    input  wire [WIDTH-1:0]      input_b_q_tdata,
    input  wire                  input_b_tvalid,
    output wire                  input_b_tready,

    /*
     * AXI stream output
     */
    output wire [(WIDTH*2)-1:0]  output_i_tdata,
    output wire [(WIDTH*2)-1:0]  output_q_tdata,
    output wire                  output_tvalid,
    input  wire                  output_tready
);

reg [WIDTH-1:0] input_a_i_reg_0 = 0;
reg [WIDTH-1:0] input_a_q_reg_0 = 0;
reg [WIDTH-1:0] input_a_i_reg_1 = 0;
reg [WIDTH-1:0] input_a_q_reg_1 = 0;

reg [WIDTH-1:0] input_b_i_reg_0 = 0;
reg [WIDTH-1:0] input_b_q_reg_0 = 0;
reg [WIDTH-1:0] input_b_i_reg_1 = 0;
reg [WIDTH-1:0] input_b_q_reg_1 = 0;

reg [(WIDTH*2)-1:0] output_i_reg_0 = 0;
reg [(WIDTH*2)-1:0] output_q_reg_0 = 0;
reg [(WIDTH*2)-1:0] output_i_reg_1 = 0;
reg [(WIDTH*2)-1:0] output_q_reg_1 = 0;

wire transfer = input_a_tvalid & input_b_tvalid & output_tready;

assign input_a_tready = input_b_tvalid & output_tready;
assign input_b_tready = input_a_tvalid & output_tready;

assign output_i_tdata = output_i_reg_1;
assign output_q_tdata = output_q_reg_1;
assign output_tvalid = input_a_tvalid & input_b_tvalid;

always @(posedge clk) begin
    if (rst) begin
        input_a_i_reg_0 <= 0;
        input_a_q_reg_0 <= 0;
        input_a_i_reg_1 <= 0;
        input_a_q_reg_1 <= 0;

        input_b_i_reg_0 <= 0;
        input_b_q_reg_0 <= 0;
        input_b_i_reg_1 <= 0;
        input_b_q_reg_1 <= 0;

        output_i_reg_0 <= 0;
        output_q_reg_0 <= 0;
        output_i_reg_1 <= 0;
        output_q_reg_1 <= 0;
    end else begin
        if (transfer) begin
            // pipeline for Xilinx DSP slice

            // register
            input_a_i_reg_0 <= input_a_i_tdata;
            input_a_q_reg_0 <= input_a_q_tdata;
            input_b_i_reg_0 <= input_b_i_tdata;
            input_b_q_reg_0 <= input_b_q_tdata;

            // pipeline
            input_a_i_reg_1 <= input_a_i_reg_0;
            input_a_q_reg_1 <= input_a_q_reg_0;
            input_b_i_reg_1 <= input_b_i_reg_0;
            input_b_q_reg_1 <= input_b_q_reg_0;

            // multiply
            output_i_reg_0 <= $signed(input_a_i_reg_1) * $signed(input_b_i_reg_1);
            output_q_reg_0 <= $signed(input_a_q_reg_1) * $signed(input_b_q_reg_1);

            // pipeline
            output_i_reg_1 <= output_i_reg_0;
            output_q_reg_1 <= output_q_reg_0;
        end
    end
end

endmodule


================================================
FILE: rtl/dsp_mult.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Multiplier - computes a*b
 */
module dsp_mult #
(
    parameter WIDTH = 16
)
(
    input  wire                  clk,
    input  wire                  rst,

    /*
     * AXI stream inputs
     */
    input  wire [WIDTH-1:0]      input_a_tdata,
    input  wire                  input_a_tvalid,
    output wire                  input_a_tready,

    input  wire [WIDTH-1:0]      input_b_tdata,
    input  wire                  input_b_tvalid,
    output wire                  input_b_tready,

    /*
     * AXI stream output
     */
    output wire [(WIDTH*2)-1:0]  output_tdata,
    output wire                  output_tvalid,
    input  wire                  output_tready
);

reg [WIDTH-1:0] input_a_reg_0 = 0;
reg [WIDTH-1:0] input_a_reg_1 = 0;

reg [WIDTH-1:0] input_b_reg_0 = 0;
reg [WIDTH-1:0] input_b_reg_1 = 0;

reg [(WIDTH*2)-1:0] output_reg_0 = 0;
reg [(WIDTH*2)-1:0] output_reg_1 = 0;

wire transfer = input_a_tvalid & input_b_tvalid & output_tready;

assign input_a_tready = input_b_tvalid & output_tready;
assign input_b_tready = input_a_tvalid & output_tready;

assign output_tdata = output_reg_1;
assign output_tvalid = input_a_tvalid & input_b_tvalid;

always @(posedge clk) begin
    if (rst) begin
        input_a_reg_0 <= 0;
        input_a_reg_1 <= 0;

        input_b_reg_0 <= 0;
        input_b_reg_1 <= 0;

        output_reg_0 <= 0;
        output_reg_1 <= 0;
    end else begin
        if (transfer) begin
            // pipeline for Xilinx DSP slice

            // register
            input_a_reg_0 <= input_a_tdata;
            input_b_reg_0 <= input_b_tdata;

            // pipeline
            input_a_reg_1 <= input_a_reg_0;
            input_b_reg_1 <= input_b_reg_0;

            // multiply
            output_reg_0 <= $signed(input_a_reg_1) * $signed(input_b_reg_1);

            // pipeline
            output_reg_1 <= output_reg_0;
        end
    end
end

endmodule


================================================
FILE: rtl/i2s_ctrl.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * I2S control
 */
module i2s_ctrl #
(
    parameter WIDTH = 16
)
(
    input  wire              clk,
    input  wire              rst,

    /*
     * I2S interface
     */
    output wire              sck,
    output wire              ws,

    /*
     * Configuration
     */
    input  wire [15:0]       prescale
);

reg [15:0] prescale_cnt = 0;
reg [$clog2(WIDTH)-1:0] ws_cnt = 0;

reg sck_reg = 0;
reg ws_reg = 0;

assign sck = sck_reg;
assign ws = ws_reg;

always @(posedge clk) begin
    if (rst) begin
        prescale_cnt <= 0;
        ws_cnt <= 0;
        sck_reg <= 0;
        ws_reg <= 0;
    end else begin
        if (prescale_cnt > 0) begin
            prescale_cnt <= prescale_cnt - 1;
        end else begin
            prescale_cnt <= prescale;
            if (sck_reg) begin
                sck_reg <= 0;
                if (ws_cnt > 0) begin
                    ws_cnt <= ws_cnt - 1;
                end else begin
                    ws_cnt <= WIDTH-1;
                    ws_reg <= ~ws_reg;
                end
            end else begin
                sck_reg <= 1;
            end
        end
    end
end

endmodule


================================================
FILE: rtl/i2s_rx.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * I2S RX
 */
module i2s_rx #
(
    parameter WIDTH = 16
)
(
    input  wire              clk,
    input  wire              rst,

    /*
     * I2S interface
     */
    input  wire              sck,
    input  wire              ws,
    input  wire              sd,

    /*
     * AXI stream output
     */
    output wire [WIDTH-1:0]  output_l_tdata,
    output wire [WIDTH-1:0]  output_r_tdata,
    output wire              output_tvalid,
    input  wire              output_tready
);

reg [WIDTH-1:0] l_data_reg = 0;
reg [WIDTH-1:0] r_data_reg = 0;

reg l_data_valid_reg = 0;
reg r_data_valid_reg = 0;

reg [WIDTH-1:0] sreg = 0;

reg [$clog2(WIDTH)-1:0] bit_cnt = 0;

reg last_sck = 0;
reg last_ws = 0;
reg last_ws2 = 0;

assign output_l_tdata = l_data_reg;
assign output_r_tdata = r_data_reg;
assign output_tvalid = l_data_valid_reg & r_data_valid_reg;

always @(posedge clk) begin
    if (rst) begin
        l_data_reg <= 0;
        r_data_reg <= 0;
        l_data_valid_reg <= 0;
        r_data_valid_reg <= 0;
        sreg <= 0;
        bit_cnt <= 0;
        last_sck <= 0;
        last_ws <= 0;
        last_ws2 <= 0;
    end else begin
        if (output_tready & output_tvalid) begin
            l_data_valid_reg <= 0;
            r_data_valid_reg <= 0;
        end

        last_sck <= sck;

        if (~last_sck & sck) begin
            // rising edge sck
            last_ws <= ws;
            last_ws2 <= last_ws;

            if (last_ws2 != last_ws) begin
                bit_cnt <= WIDTH-1;
                sreg <= {{WIDTH-1{1'b0}}, sd};
            end else begin
                if (bit_cnt > 0) begin
                    bit_cnt <= bit_cnt - 1;
                    if (bit_cnt > 1) begin
                        sreg <= {sreg[WIDTH-2:0], sd};
                    end else if (last_ws2) begin
                        r_data_reg <= {sreg[WIDTH-2:0], sd};
                        r_data_valid_reg <= l_data_valid_reg;
                    end else begin
                        l_data_reg <= {sreg[WIDTH-2:0], sd};
                        l_data_valid_reg <= 1;
                    end
                end
            end
        end
    end
end

endmodule


================================================
FILE: rtl/i2s_tx.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * I2S TX
 */
module i2s_tx #
(
    parameter WIDTH = 16
)
(
    input  wire              clk,
    input  wire              rst,

    /*
     * AXI stream input
     */
    input  wire [WIDTH-1:0]  input_l_tdata,
    input  wire [WIDTH-1:0]  input_r_tdata,
    input  wire              input_tvalid,
    output wire              input_tready,

    /*
     * I2S interface
     */
    input  wire              sck,
    input  wire              ws,
    output wire              sd
);

reg [WIDTH-1:0] l_data_reg = 0;
reg [WIDTH-1:0] r_data_reg = 0;

reg l_data_valid_reg = 0;
reg r_data_valid_reg = 0;

reg [WIDTH-1:0] sreg = 0;

reg [$clog2(WIDTH+1)-1:0] bit_cnt = 0;

reg last_sck = 0;
reg last_ws = 0;
reg sd_reg = 0;

assign input_tready = ~l_data_valid_reg & ~r_data_valid_reg;

assign sd = sd_reg;

always @(posedge clk) begin
    if (rst) begin
        l_data_reg <= 0;
        r_data_reg <= 0;
        l_data_valid_reg <= 0;
        r_data_valid_reg <= 0;
        sreg <= 0;
        bit_cnt <= 0;
        last_sck <= 0;
        last_ws <= 0;
        sd_reg <= 0;
    end else begin
        if (input_tready & input_tvalid) begin
            l_data_reg <= input_l_tdata;
            r_data_reg <= input_r_tdata;
            l_data_valid_reg <= 1;
            r_data_valid_reg <= 1;
        end

        last_sck <= sck;

        if (~last_sck & sck) begin
            // rising edge sck
            last_ws <= ws;

            if (last_ws != ws) begin
                bit_cnt <= WIDTH;
                if (ws) begin
                    sreg <= r_data_reg;
                    r_data_valid_reg <= 0;
                end else begin
                    sreg <= l_data_reg;
                    l_data_valid_reg <= 0;
                end
            end
        end

        if (last_sck & ~sck) begin
            // falling edge sck
            if (bit_cnt > 0) begin
                bit_cnt <= bit_cnt - 1;
                {sd_reg, sreg} <= {sreg[WIDTH-1:0], 1'b0};
            end
        end
    end
end

endmodule


================================================
FILE: rtl/iq_join.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * IQ joiner
 */
module iq_join #
(
    parameter WIDTH = 16
)
(
    input  wire              clk,
    input  wire              rst,

    /*
     * AXI stream inputs
     */
    input  wire [WIDTH-1:0]  input_i_tdata,
    input  wire              input_i_tvalid,
    output wire              input_i_tready,

    input  wire [WIDTH-1:0]  input_q_tdata,
    input  wire              input_q_tvalid,
    output wire              input_q_tready,

    /*
     * AXI stream output
     */
    output wire [WIDTH-1:0]  output_i_tdata,
    output wire [WIDTH-1:0]  output_q_tdata,
    output wire              output_tvalid,
    input  wire              output_tready
);

reg [WIDTH-1:0] i_data_reg = 0;
reg [WIDTH-1:0] q_data_reg = 0;

reg i_valid_reg = 0;
reg q_valid_reg = 0;

assign input_i_tready = ~i_valid_reg | (output_tready & output_tvalid);
assign input_q_tready = ~q_valid_reg | (output_tready & output_tvalid);

assign output_i_tdata = i_data_reg;
assign output_q_tdata = q_data_reg;
assign output_tvalid = i_valid_reg & q_valid_reg;

always @(posedge clk) begin
    if (rst) begin
        i_data_reg <= 0;
        q_data_reg <= 0;
        i_valid_reg <= 0;
        q_valid_reg <= 0;
    end else begin
        if (input_i_tready & input_i_tvalid) begin
            i_data_reg <= input_i_tdata;
            i_valid_reg <= 1;
        end else if (output_tready & output_tvalid) begin
            i_valid_reg <= 0;
        end
        if (input_q_tready & input_q_tvalid) begin
            q_data_reg <= input_q_tdata;
            q_valid_reg <= 1;
        end else if (output_tready & output_tvalid) begin
            q_valid_reg <= 0;
        end
    end
end

endmodule


================================================
FILE: rtl/iq_split.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * IQ splitter
 */
module iq_split #
(
    parameter WIDTH = 16
)
(
    input  wire              clk,
    input  wire              rst,

    /*
     * AXI stream input
     */
    input  wire [WIDTH-1:0]  input_i_tdata,
    input  wire [WIDTH-1:0]  input_q_tdata,
    input  wire              input_tvalid,
    output wire              input_tready,

    /*
     * AXI stream outputs
     */
    output wire [WIDTH-1:0]  output_i_tdata,
    output wire              output_i_tvalid,
    input  wire              output_i_tready,

    output wire [WIDTH-1:0]  output_q_tdata,
    output wire              output_q_tvalid,
    input  wire              output_q_tready
);

reg [WIDTH-1:0] i_data_reg = 0;
reg [WIDTH-1:0] q_data_reg = 0;

reg i_valid_reg = 0;
reg q_valid_reg = 0;

assign input_tready = (~i_valid_reg | (output_i_tready & output_i_tvalid)) & (~q_valid_reg | (output_q_tready & output_q_tvalid));

assign output_i_tdata = i_data_reg;
assign output_i_tvalid = i_valid_reg;

assign output_q_tdata = q_data_reg;
assign output_q_tvalid = q_valid_reg;

always @(posedge clk) begin
    if (rst) begin
        i_data_reg <= 0;
        q_data_reg <= 0;
        i_valid_reg <= 0;
        q_valid_reg <= 0;
    end else begin
        if (input_tready & input_tvalid) begin
            i_data_reg <= input_i_tdata;
            q_data_reg <= input_q_tdata;
            i_valid_reg <= 1;
            q_valid_reg <= 1;
        end else begin
            if (output_i_tready) begin
                i_valid_reg <= 0;
            end
            if (output_q_tready) begin
                q_valid_reg <= 0;
            end
        end
    end
end

endmodule


================================================
FILE: rtl/phase_accumulator.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Phase accumulator
 */
module phase_accumulator #
(
    parameter WIDTH = 32,
    parameter INITIAL_PHASE = 0,
    parameter INITIAL_PHASE_STEP = 0
)
(
    input  wire             clk,
    input  wire             rst,

    /*
     * AXI stream phase input
     */
    input  wire [WIDTH-1:0] input_phase_tdata,
    input  wire             input_phase_tvalid,
    output wire             input_phase_tready,

    /*
     * AXI stream phase step input
     */
    input  wire [WIDTH-1:0] input_phase_step_tdata,
    input  wire             input_phase_step_tvalid,
    output wire             input_phase_step_tready,

    /*
     * AXI stream phase output
     */
    output wire [WIDTH-1:0] output_phase_tdata,
    output wire             output_phase_tvalid,
    input  wire             output_phase_tready
);

reg [WIDTH-1:0] phase_reg = INITIAL_PHASE;
reg [WIDTH-1:0] phase_step_reg = INITIAL_PHASE_STEP;

assign input_phase_tready = output_phase_tready;
assign input_phase_step_tready = 1;
assign output_phase_tdata = phase_reg;
assign output_phase_tvalid = 1;

always @(posedge clk) begin
    if (rst) begin
        phase_reg <= INITIAL_PHASE;
        phase_step_reg <= INITIAL_PHASE_STEP;
    end else begin
        if (input_phase_tready & input_phase_tvalid) begin
            phase_reg <= input_phase_tdata;
        end else if (output_phase_tready) begin
            phase_reg <= phase_reg + phase_step_reg;
        end

        if (input_phase_step_tvalid) begin
            phase_step_reg <= input_phase_step_tdata;
        end
    end
end

endmodule


================================================
FILE: rtl/sine_dds.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Sine DDS
 */
module sine_dds #
(
    parameter PHASE_WIDTH = 32,
    parameter OUTPUT_WIDTH = 16,
    parameter INITIAL_PHASE = 0,
    parameter INITIAL_PHASE_STEP = 0
)
(
    input  wire                    clk,
    input  wire                    rst,

    /*
     * AXI stream phase input
     */
    input  wire [PHASE_WIDTH-1:0]  input_phase_tdata,
    input  wire                    input_phase_tvalid,
    output wire                    input_phase_tready,

    /*
     * AXI stream phase step input
     */
    input  wire [PHASE_WIDTH-1:0]  input_phase_step_tdata,
    input  wire                    input_phase_step_tvalid,
    output wire                    input_phase_step_tready,

    /*
     * AXI stream sample output
     */
    output wire [OUTPUT_WIDTH-1:0] output_sample_i_tdata,
    output wire [OUTPUT_WIDTH-1:0] output_sample_q_tdata,
    output wire                    output_sample_tvalid,
    input  wire                    output_sample_tready
);

wire [PHASE_WIDTH-1:0] phase_tdata;
wire phase_tvalid;
wire phase_tready;

phase_accumulator #(
    .WIDTH(PHASE_WIDTH),
    .INITIAL_PHASE(INITIAL_PHASE),
    .INITIAL_PHASE_STEP(INITIAL_PHASE_STEP)
)
phase_accumulator_inst (
    .clk(clk),
    .rst(rst),
    
    .input_phase_tdata(input_phase_tdata),
    .input_phase_tvalid(input_phase_tvalid),
    .input_phase_tready(input_phase_tready),

    .input_phase_step_tdata(input_phase_step_tdata),
    .input_phase_step_tvalid(input_phase_step_tvalid),
    .input_phase_step_tready(input_phase_step_tready),

    .output_phase_tdata(phase_tdata),
    .output_phase_tvalid(phase_tvalid),
    .output_phase_tready(phase_tready)
);

sine_dds_lut #(
    .INPUT_WIDTH(OUTPUT_WIDTH+2),
    .OUTPUT_WIDTH(OUTPUT_WIDTH)
)
sine_dds_inst (
    .clk(clk),
    .rst(rst),

    .input_phase_tdata(phase_tdata[PHASE_WIDTH-1:PHASE_WIDTH-OUTPUT_WIDTH-2]),
    .input_phase_tvalid(phase_tvalid),
    .input_phase_tready(phase_tready),

    .output_sample_i_tdata(output_sample_i_tdata),
    .output_sample_q_tdata(output_sample_q_tdata),
    .output_sample_tvalid(output_sample_tvalid),
    .output_sample_tready(output_sample_tready)
);

endmodule


================================================
FILE: rtl/sine_dds_lut.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Sine DDS look up table
 */
module sine_dds_lut #
(
    parameter OUTPUT_WIDTH = 16,
    parameter INPUT_WIDTH = OUTPUT_WIDTH+2
)
(
    input  wire                    clk,
    input  wire                    rst,

    /*
     * AXI stream phase input
     */
    input  wire [INPUT_WIDTH-1:0]  input_phase_tdata,
    input  wire                    input_phase_tvalid,
    output wire                    input_phase_tready,

    /*
     * AXI stream sample output
     */
    output wire [OUTPUT_WIDTH-1:0] output_sample_i_tdata,
    output wire [OUTPUT_WIDTH-1:0] output_sample_q_tdata,
    output wire                    output_sample_tvalid,
    input  wire                    output_sample_tready
);

localparam W = (INPUT_WIDTH-2)/2;

reg [INPUT_WIDTH-1:0] phase_reg = 0;

integer i;

// coarse sine and cosine LUTs
reg [OUTPUT_WIDTH-1:0] coarse_c_lut[2**(W+1)-1:0];
reg [OUTPUT_WIDTH-1:0] coarse_s_lut[2**(W+1)-1:0];

initial begin
    for (i = 0; i < 2**(W+1); i = i + 1) begin
        coarse_c_lut[i] = $cos(2*3.1415926535*i/2**(W+2))*(2**(OUTPUT_WIDTH-1)-1);
        coarse_s_lut[i] = $sin(2*3.1415926535*i/2**(W+2))*(2**(OUTPUT_WIDTH-1)-1);
    end
end

// fine sine LUT
reg [(OUTPUT_WIDTH/2)-1:0] fine_s_lut[2**W-1:0];

initial begin
    for (i = 0; i < 2**W; i = i + 1) begin
        fine_s_lut[i] = $sin(2*3.1415926535*(i-2**(W-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1);
    end
end

reg [OUTPUT_WIDTH-1:0] sample_i_reg = 0;
reg [OUTPUT_WIDTH-1:0] sample_q_reg = 0;

wire SIGN = phase_reg[INPUT_WIDTH-1];
wire SLOPE = phase_reg[INPUT_WIDTH-2];
wire [W:0] A = phase_reg[INPUT_WIDTH-2:W];
wire [W-1:0] B = phase_reg[W-1:0];

reg sign_reg_1 = 0;
reg sign_reg_2 = 0;
reg sign_reg_3 = 0;
reg sign_reg_4 = 0;

reg [OUTPUT_WIDTH-1:0] ccs_reg_1 = 0, ccs_reg_2 = 0, ccs_reg_3 = 0;
reg [OUTPUT_WIDTH-1:0] css_reg_1 = 0, css_reg_2 = 0, css_reg_3 = 0;
reg [(OUTPUT_WIDTH/2)-1:0] fss_reg_1 = 0, fss_reg_2 = 0;

reg [(OUTPUT_WIDTH*2)-1:0] cp_reg_1 = 0;
reg [(OUTPUT_WIDTH*2)-1:0] sp_reg_1 = 0;

reg [OUTPUT_WIDTH-1:0] cs_reg_1 = 0;
reg [OUTPUT_WIDTH-1:0] ss_reg_1 = 0;

assign input_phase_tready = output_sample_tready;
assign output_sample_i_tdata = sample_i_reg;
assign output_sample_q_tdata = sample_q_reg;
assign output_sample_tvalid = input_phase_tvalid;

always @(posedge clk) begin
    if (rst) begin
        phase_reg <= 0;
    end else begin
        if (input_phase_tready & input_phase_tvalid) begin
            phase_reg <= input_phase_tdata;
        end
    end

    if (input_phase_tready & input_phase_tvalid) begin
        // pipeline sits primarily in DSP slice
        // sin(A+B) = sin(A) + cos(A)*sin(B)
        // cos(A+B) = cos(A) - sin(A)*sin(B)
        
        // read samples
        sign_reg_1 <= SIGN;
        ccs_reg_1 <= coarse_c_lut[A];
        css_reg_1 <= coarse_s_lut[A];
        fss_reg_1 <= fine_s_lut[B];

        // pipeline
        sign_reg_2 <= sign_reg_1;
        ccs_reg_2 <= ccs_reg_1;
        css_reg_2 <= css_reg_1;
        fss_reg_2 <= fss_reg_1;

        // multiply
        sign_reg_3 <= sign_reg_2;
        ccs_reg_3 <= ccs_reg_2;
        css_reg_3 <= css_reg_2;
        cp_reg_1 <= $signed(css_reg_2) * $signed(fss_reg_2);
        sp_reg_1 <= $signed(ccs_reg_2) * $signed(fss_reg_2);

        // add
        sign_reg_4 <= sign_reg_3;
        cs_reg_1 <= ccs_reg_3 - (cp_reg_1 >> (OUTPUT_WIDTH-1));
        ss_reg_1 <= css_reg_3 + (sp_reg_1 >> (OUTPUT_WIDTH-1));

        // negate output samples
        sample_i_reg <= sign_reg_4 ? -cs_reg_1 : cs_reg_1;
        sample_q_reg <= sign_reg_4 ? -ss_reg_1 : ss_reg_1;
    end
end

endmodule


================================================
FILE: tb/axis_ep.py
================================================
"""

Copyright (c) 2014-2018 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *

skip_asserts = False

class AXIStreamFrame(object):
    def __init__(self, data=b'', keep=None, id=None, dest=None, user=None, last_cycle_user=None):
        self.B = 0
        self.N = 8
        self.M = 1
        self.WL = 8
        self.data = b''
        self.keep = None
        self.id = 0
        self.dest = 0
        self.user = None
        self.last_cycle_user = None

        if type(data) in (bytes, bytearray):
            self.data = bytearray(data)
            self.keep = keep
            self.id = id
            self.dest = dest
            self.user = user
            self.last_cycle_user = last_cycle_user
        elif type(data) is AXIStreamFrame:
            self.N = data.N
            self.WL = data.WL
            if type(data.data) is bytearray:
                self.data = bytearray(data.data)
            else:
                self.data = list(data.data)
            if data.keep is not None:
                self.keep = list(data.keep)
            if data.id is not None:
                if type(data.id) in (int, bool):
                    self.id = data.id
                else:
                    self.id = list(data.id)
            if data.dest is not None:
                if type(data.dest) in (int, bool):
                    self.dest = data.dest
                else:
                    self.dest = list(data.dest)
            if data.user is not None:
                if type(data.user) in (int, bool):
                    self.user = data.user
                else:
                    self.user = list(data.user)
            self.last_cycle_user = data.last_cycle_user
        else:
            self.data = list(data)
            self.keep = keep
            self.id = id
            self.dest = dest
            self.user = user
            self.last_cycle_user = last_cycle_user

    def build(self):
        if self.data is None:
            return

        f = list(self.data)
        tdata = []
        tkeep = []
        tid = []
        tdest = []
        tuser = []
        i = 0

        while len(f) > 0:
            if self.B == 0:
                data = 0
                keep = 0
                for j in range(self.M):
                    data = data | (f.pop(0) << (j*self.WL))
                    keep = keep | (1 << j)
                    if len(f) == 0: break
                tdata.append(data)

                if self.keep is None:
                    tkeep.append(keep)
                else:
                    tkeep.append(self.keep[i])
            else:
                # multiple tdata signals
                data = 0
                tdata.append(f.pop(0))
                tkeep.append(0)

            if self.id is None:
                tid.append(0)
            elif type(self.id) is int:
                tid.append(self.id)
            else:
                tid.append(self.id[i])

            if self.dest is None:
                tdest.append(0)
            elif type(self.dest) is int:
                tdest.append(self.dest)
            else:
                tdest.append(self.dest[i])

            if self.user is None:
                tuser.append(0)
            elif type(self.user) is int:
                tuser.append(self.user)
            else:
                tuser.append(self.user[i])
            i += 1

        if self.last_cycle_user:
            tuser[-1] = self.last_cycle_user

        return tdata, tkeep, tid, tdest, tuser

    def parse(self, tdata, tkeep, tid, tdest, tuser):
        if tdata is None or tkeep is None or tuser is None:
            return
        if len(tdata) != len(tkeep) or len(tdata) != len(tid) or len(tdata) != len(tdest) or len(tdata) != len(tuser):
            raise Exception("Invalid data")

        self.data = []
        self.keep = []
        self.id = []
        self.dest = []
        self.user = []

        if self.B == 0:
            mask = 2**self.WL-1

            for i in range(len(tdata)):
                for j in range(self.M):
                    if tkeep[i] & (1 << j):
                        self.data.append((tdata[i] >> (j*self.WL)) & mask)
                self.keep.append(tkeep[i])
                self.id.append(tid[i])
                self.dest.append(tdest[i])
                self.user.append(tuser[i])
        else:
            for i in range(len(tdata)):
                self.data.append(tdata[i])
                self.keep.append(tkeep[i])
                self.id.append(tid[i])
                self.dest.append(tdest[i])
                self.user.append(tuser[i])

        if self.WL == 8:
            self.data = bytearray(self.data)

        self.last_cycle_user = self.user[-1]

    def __eq__(self, other):
        if not isinstance(other, AXIStreamFrame):
            return False
        if self.data != other.data:
            return False
        if self.keep is not None and other.keep is not None:
            if self.keep != other.keep:
                return False
        if self.id is not None and other.id is not None:
            if type(self.id) in (int, bool) and type(other.id) is list:
                for k in other.id:
                    if self.id != k:
                        return False
            elif type(other.id) in (int, bool) and type(self.id) is list:
                for k in self.id:
                    if other.id != k:
                        return False
            elif self.id != other.id:
                return False
        if self.dest is not None and other.dest is not None:
            if type(self.dest) in (int, bool) and type(other.dest) is list:
                for k in other.dest:
                    if self.dest != k:
                        return False
            elif type(other.dest) in (int, bool) and type(self.dest) is list:
                for k in self.dest:
                    if other.dest != k:
                        return False
            elif self.dest != other.dest:
                return False
        if self.last_cycle_user is not None and other.last_cycle_user is not None:
            if self.last_cycle_user != other.last_cycle_user:
                return False
            if self.user is not None and other.user is not None:
                if type(self.user) in (int, bool) and type(other.user) is list:
                    for k in other.user[:-1]:
                        if self.user != k:
                            return False
                elif type(other.user) in (int, bool) and type(self.user) is list:
                    for k in self.user[:-1]:
                        if other.user != k:
                            return False
                elif self.user != other.user:
                    return False
        else:
            if self.user is not None and other.user is not None:
                if type(self.user) in (int, bool) and type(other.user) is list:
                    for k in other.user:
                        if self.user != k:
                            return False
                elif type(other.user) in (int, bool) and type(self.user) is list:
                    for k in self.user:
                        if other.user != k:
                            return False
                elif self.user != other.user:
                    return False
        return True

    def __repr__(self):
        return (
                ('AXIStreamFrame(data=%s, ' % repr(self.data)) +
                ('keep=%s, ' % repr(self.keep)) +
                ('id=%s, ' % repr(self.id)) +
                ('dest=%s, ' % repr(self.dest)) +
                ('user=%s, ' % repr(self.user)) +
                ('last_cycle_user=%s)' % repr(self.last_cycle_user))
            )

    def __iter__(self):
        return self.data.__iter__()


class AXIStreamSource(object):
    def __init__(self):
        self.has_logic = False
        self.queue = []

    def send(self, frame):
        self.queue.append(AXIStreamFrame(frame))

    def write(self, data):
        self.send(data)

    def count(self):
        return len(self.queue)

    def empty(self):
        return self.count() == 0

    def create_logic(self,
                clk,
                rst,
                tdata=None,
                tkeep=Signal(bool(True)),
                tvalid=Signal(bool(False)),
                tready=Signal(bool(True)),
                tlast=Signal(bool(False)),
                tid=Signal(intbv(0)),
                tdest=Signal(intbv(0)),
                tuser=Signal(intbv(0)),
                pause=0,
                name=None
            ):

        assert not self.has_logic

        self.has_logic = True

        tready_int = Signal(bool(False))
        tvalid_int = Signal(bool(False))

        @always_comb
        def pause_logic():
            tready_int.next = tready and not pause
            tvalid.next = tvalid_int and not pause

        @instance
        def logic():
            frame = AXIStreamFrame()
            data = []
            keep = []
            id = []
            dest = []
            user = []
            B = 0
            N = len(tdata)
            M = len(tkeep)
            WL = int((len(tdata)+M-1)/M)

            if type(tdata) is list or type(tdata) is tuple:
                # multiple tdata signals
                B = len(tdata)
                N = [len(b) for b in tdata]
                M = 1
                WL = [1]*B

            while True:
                yield clk.posedge, rst.posedge

                if rst:
                    if B > 0:
                        for s in tdata:
                            s.next = 0
                    else:
                        tdata.next = 0
                    tkeep.next = 0
                    tid.next = 0
                    tdest.next = 0
                    tuser.next = False
                    tvalid_int.next = False
                    tlast.next = False
                else:
                    if tready_int and tvalid:
                        if len(data) > 0:
                            if B > 0:
                                l = data.pop(0)
                                for i in range(B):
                                    tdata[i].next = l[i]
                            else:
                                tdata.next = data.pop(0)
                            tkeep.next = keep.pop(0)
                            tid.next = id.pop(0)
                            tdest.next = dest.pop(0)
                            tuser.next = user.pop(0)
                            tvalid_int.next = True
                            tlast.next = len(data) == 0
                        else:
                            tvalid_int.next = False
                            tlast.next = False
                    if (tlast and tready_int and tvalid) or not tvalid_int:
                        if len(self.queue) > 0:
                            frame = self.queue.pop(0)
                            frame.B = B
                            frame.N = N
                            frame.M = M
                            frame.WL = WL
                            data, keep, id, dest, user = frame.build()
                            if name is not None:
                                print("[%s] Sending frame %s" % (name, repr(frame)))
                            if B > 0:
                                l = data.pop(0)
                                for i in range(B):
                                    tdata[i].next = l[i]
                            else:
                                tdata.next = data.pop(0)
                            tkeep.next = keep.pop(0)
                            tid.next = id.pop(0)
                            tdest.next = dest.pop(0)
                            tuser.next = user.pop(0)
                            tvalid_int.next = True
                            tlast.next = len(data) == 0

        return instances()


class AXIStreamSink(object):
    def __init__(self):
        self.has_logic = False
        self.queue = []
        self.read_queue = []

    def recv(self):
        if len(self.queue) > 0:
            return self.queue.pop(0)
        return None

    def read(self, count=-1):
        while len(self.queue) > 0:
            self.read_queue.extend(self.queue.pop(0).data)
        if count < 0:
            count = len(self.read_queue)
        data = self.read_queue[:count]
        del self.read_queue[:count]
        return data

    def count(self):
        return len(self.queue)

    def empty(self):
        return self.count() == 0

    def create_logic(self,
                clk,
                rst,
                tdata=None,
                tkeep=Signal(bool(True)),
                tvalid=Signal(bool(False)),
                tready=Signal(bool(True)),
                tlast=Signal(bool(True)),
                tid=Signal(intbv(0)),
                tdest=Signal(intbv(0)),
                tuser=Signal(intbv(0)),
                pause=0,
                name=None
            ):

        assert not self.has_logic

        self.has_logic = True

        tready_int = Signal(bool(False))
        tvalid_int = Signal(bool(False))

        @always_comb
        def pause_logic():
            tready.next = tready_int and not pause
            tvalid_int.next = tvalid and not pause

        @instance
        def logic():
            frame = AXIStreamFrame()
            data = []
            keep = []
            id = []
            dest = []
            user = []
            B = 0
            N = len(tdata)
            M = len(tkeep)
            WL = int((len(tdata)+M-1)/M)
            first = True

            if type(tdata) is list or type(tdata) is tuple:
                # multiple tdata signals
                B = len(tdata)
                N = [len(b) for b in tdata]
                M = 1
                WL = [1]*B

            while True:
                yield clk.posedge, rst.posedge

                if rst:
                    tready_int.next = False
                    frame = AXIStreamFrame()
                    data = []
                    keep = []
                    id = []
                    dest = []
                    user = []
                    first = True
                else:
                    tready_int.next = True

                    if tvalid_int:

                        if not skip_asserts:
                            # zero tkeep not allowed
                            assert int(tkeep) != 0
                            # tkeep must be contiguous
                            # i.e. 0b00011110 allowed, but 0b00011010 not allowed
                            b = int(tkeep)
                            while b & 1 == 0:
                                b = b >> 1
                            while b & 1 == 1:
                                b = b >> 1
                            assert b == 0
                            # tkeep must not have gaps across cycles
                            if not first:
                                # not first cycle; lowest bit must be set
                                assert int(tkeep) & 1
                            if not tlast:
                                # not last cycle; highest bit must be set
                                assert int(tkeep) & (1 << len(tkeep)-1)

                        if B > 0:
                            l = []
                            for i in range(B):
                                l.append(int(tdata[i]))
                            data.append(l)
                        else:
                            data.append(int(tdata))
                        keep.append(int(tkeep))
                        id.append(int(tid))
                        dest.append(int(tdest))
                        user.append(int(tuser))
                        first = False
                        if tlast:
                            frame.B = B
                            frame.N = N
                            frame.M = M
                            frame.WL = WL
                            frame.parse(data, keep, id, dest, user)
                            self.queue.append(frame)
                            if name is not None:
                                print("[%s] Got frame %s" % (name, repr(frame)))
                            frame = AXIStreamFrame()
                            data = []
                            keep = []
                            id = []
                            dest = []
                            user = []
                            first = True

        return instances()



================================================
FILE: tb/i2s_ep.py
================================================
"""

Copyright (c) 2014 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *

def I2SControl(clk, rst,
               sck=None,
               ws=None,
               width=16,
               prescale=2):
    
    @instance
    def logic():
        prescale_cnt = 0
        ws_cnt = 0

        while True:
            yield clk.posedge

            if rst:
                sck.next = 0
                ws.next = 0
                prescale_cnt = 0
                ws_cnt = 0
            else:
                if prescale_cnt > 0:
                    prescale_cnt = prescale_cnt - 1;
                else:
                    prescale_cnt = prescale;
                    if sck:
                        sck.next = False
                        if ws_cnt > 0:
                            ws_cnt = ws_cnt - 1
                        else:
                            ws_cnt = width-1
                            ws.next = not ws
                    else:
                        sck.next = True

    return instances()


def I2SSource(clk, rst,
              sck=None,
              ws=None,
              sd=None,
              width=16,
              fifo=None,
              name=None):
    
    @instance
    def logic():
        lst = None
        r_data = 0
        bit_cnt = 0
        last_sck = 0
        last_ws = 0
        sreg = 0

        while True:
            yield clk.posedge

            if rst:
                sd.next = 0
                r_data = 0
                bit_cnt = 0
                last_sck = 0
                last_ws = 0
                sreg = 0
            else:
                if not last_sck and sck:
                    if last_ws != ws:
                        bit_cnt = width

                        if ws:
                            sreg = r_data
                        else:
                            d = (0,0)
                            if lst is None or len(lst) == 0:
                                if not fifo.empty():
                                    d = fifo.get(False)
                                if type(d) is list:
                                    lst = d
                                    d = lst.pop(0)
                            else:
                                d = lst.pop(0)
                            sreg, r_data = d
                            if name is not None:
                                print("[%s] Sending I2S data (%d, %d)" % (name, sreg, r_data))

                    last_ws = int(ws)

                if last_sck and not sck:
                    if bit_cnt > 0:
                        bit_cnt = bit_cnt - 1
                        sd.next = sreg & (1 << bit_cnt) != 0

                last_sck = int(sck)


    return logic


def I2SSink(clk, rst,
            sck=None,
            ws=None,
            sd=None,
            width=16,
            fifo=None,
            name=None):
    
    @instance
    def logic():
        l_data = 0
        bit_cnt = 0
        last_sck = 0
        last_ws = 0
        last_ws2 = 0
        sreg = 0

        while True:
            yield clk.posedge

            if rst:
                l_data = 0
                bit_cnt = 0
                last_sck = 0
                last_ws = 0
                last_ws2 = 0
                sreg = 0
            else:
                if not last_sck and sck:
                    if last_ws2 != last_ws:
                        bit_cnt = width-1
                        sreg = int(sd)
                    elif bit_cnt > 0:
                        if bit_cnt > 1:
                            sreg = (sreg << 1) | int(sd)
                        elif last_ws2:
                            d = (sreg << 1) | int(sd)
                            fifo.put((l_data, d))
                            if name is not None:
                                print("[%s] Got I2S data (%d, %d)" % (name, l_data, d))
                        else:
                            l_data = (sreg << 1) | int(sd)

                        bit_cnt = bit_cnt - 1

                    last_ws2 = last_ws
                    last_ws = int(ws)

                last_sck = int(sck)

    return instances()



================================================
FILE: tb/test_cic_decimator.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import numpy as np
import math

import axis_ep

module = 'cic_decimator'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_cic_decimator(clk,
                      rst,
                      current_test,
                      input_tdata,
                      input_tvalid,
                      input_tready,
                      output_tdata,
                      output_tvalid,
                      output_tready,
                      rate):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_tdata=input_tdata,
                input_tvalid=input_tvalid,
                input_tready=input_tready,
                output_tdata=output_tdata,
                output_tvalid=output_tvalid,
                output_tready=output_tready,
                rate=rate)

def bench():

    # Parameters
    WIDTH = 16
    RMAX = 4
    M = 1
    N = 2
    REG_WIDTH = WIDTH+math.ceil(math.log10((RMAX*M)**N)/math.log10(2))

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_tdata = Signal(intbv(0)[WIDTH:])
    input_tvalid = Signal(bool(0))
    output_tready = Signal(bool(0))
    rate = Signal(intbv(0)[math.ceil(math.log10(RMAX+1)/math.log10(2)):])

    # Outputs
    input_tready = Signal(bool(0))
    output_tdata = Signal(intbv(0)[REG_WIDTH:])
    output_tvalid = Signal(bool(0))

    # sources and sinks
    input_source_queue = Queue()
    input_source_pause = Signal(bool(0))
    output_sink_queue = Queue()
    output_sink_pause = Signal(bool(0))
    
    input_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_tdata,
                                           tvalid=input_tvalid,
                                           tready=input_tready,
                                           fifo=input_source_queue,
                                           pause=input_source_pause,
                                           name='input_source')

    output_sink = axis_ep.AXIStreamSink(clk,
                                        rst,
                                        tdata=output_tdata,
                                        tvalid=output_tvalid,
                                        tready=output_tready,
                                        fifo=output_sink_queue,
                                        pause=output_sink_pause,
                                        name='output_sink')

    # DUT
    dut = dut_cic_decimator(clk,
                            rst,
                            current_test,
                            input_tdata,
                            input_tvalid,
                            input_tready,
                            output_tdata,
                            output_tvalid,
                            output_tready,
                            rate)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        rate.next = 2

        yield clk.posedge
        print("test 1: impulse response")
        current_test.next = 1

        y = [1, 0, 0, 0, 0]
        ref = cic_decimate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*10

        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 2: ramp")
        current_test.next = 2

        # reset integrator
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge

        y = list(range(100)) + [0,0,0,0,0]
        ref = cic_decimate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*10
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 3: source pause")
        current_test.next = 3

        # reset integrator
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge

        y = list(range(100)) + [0,0,0,0,0]
        ref = cic_decimate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*10
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            input_source_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            input_source_pause.next = False
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 4: sink pause")
        current_test.next = 4

        # reset integrator
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge

        y = list(range(100)) + [0,0,0,0,0]
        ref = cic_decimate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*10
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            output_sink_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            output_sink_pause.next = False
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 5: sinewave")
        current_test.next = 5

        # reset integrator
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge

        x = np.arange(0,100)
        y = np.r_[(np.sin(2*np.pi*x/50)*1024).astype(int), [0,0,0,0]]
        ref = cic_decimate(y, N, M, rate)

        ys = y
        ys[y < 0] += 2**WIDTH

        refs = ref
        refs[ref < 0] += 2**REG_WIDTH

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(map(int, ys)) + [0]*10

        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 6: rate of 4")
        current_test.next = 6

        # reset integrator
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge

        rate.next = 4

        yield clk.posedge

        x = np.arange(0,100)
        y = np.r_[(np.sin(2*np.pi*x/50)*1024).astype(int), [0]*10]
        ref = cic_decimate(y, N, M, rate)

        ys = y
        ys[y < 0] += 2**WIDTH

        refs = ref
        refs[ref < 0] += 2**REG_WIDTH

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(map(int, ys)) + [0]*10
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 7: DC")
        current_test.next = 7

        # reset integrator
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge

        rate.next = 2

        yield clk.posedge

        y = np.r_[np.ones(1000).astype(int)*1000, [0]*10]
        ref = cic_decimate(y, N, M, rate)

        ys = y
        ys[y < 0] += 2**WIDTH

        refs = ref
        refs[ref < 0] += 2**REG_WIDTH

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(map(int, ys)) + [0]*10
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        raise StopSimulation

    return instances()

def cic_decimate(y, N=2, M=1, R=2):
    y = np.array(y)

    # integrate
    for i in range(N):
        s = 0
        for j in range(len(y)):
            s += y[j]
            y[j] = s

    # pipeline delay
    y = np.r_[[0]*N, y]

    # upconvert
    y = y[0::R]

    # comb stage
    for i in range(N):
        for j in range(len(y)-1, M-1, -1):
            y[j] = y[j] - y[j-M]

    return y

def contains(small, big):
    for i in range(len(big)-len(small)+1):
        for j in range(len(small)):
            if big[i+j] != small[j]:
                break
        else:
            return i, i+len(small)
    return False

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_cic_decimator.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for cic_decimator
 */
module test_cic_decimator;

// Parameters
parameter WIDTH = 16;
parameter RMAX = 4;
parameter M = 1;
parameter N = 2;
parameter REG_WIDTH = WIDTH+$clog2((RMAX*M)**N);

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_tdata = 0;
reg input_tvalid = 0;
reg output_tready = 0;
reg [$clog2(RMAX+1)-1:0] rate = 0;

// Outputs
wire input_tready;
wire [REG_WIDTH-1:0] output_tdata;
wire output_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_tdata,
                input_tvalid,
                output_tready,
                rate);
    $to_myhdl(input_tready,
              output_tdata,
              output_tvalid);

    // dump file
    $dumpfile("test_cic_decimator.lxt");
    $dumpvars(0, test_cic_decimator);
end

cic_decimator #(
    .WIDTH(WIDTH),
    .RMAX(RMAX),
    .M(M),
    .N(N)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_tdata(input_tdata),
    .input_tvalid(input_tvalid),
    .input_tready(input_tready),
    .output_tdata(output_tdata),
    .output_tvalid(output_tvalid),
    .output_tready(output_tready),
    .rate(rate)
);

endmodule


================================================
FILE: tb/test_cic_interpolator.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import numpy as np
import math

import axis_ep

module = 'cic_interpolator'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_cic_interpolator(clk,
                         rst,
                         current_test,
                         input_tdata,
                         input_tvalid,
                         input_tready,
                         output_tdata,
                         output_tvalid,
                         output_tready,
                         rate):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_tdata=input_tdata,
                input_tvalid=input_tvalid,
                input_tready=input_tready,
                output_tdata=output_tdata,
                output_tvalid=output_tvalid,
                output_tready=output_tready,
                rate=rate)

def bench():

    # Parameters
    WIDTH = 16
    RMAX = 4
    M = 1
    N = 2
    REG_WIDTH = WIDTH+max(N, math.ceil(math.log10(((RMAX*M)**N)/RMAX)/math.log10(2)))

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_tdata = Signal(intbv(0)[WIDTH:])
    input_tvalid = Signal(bool(0))
    output_tready = Signal(bool(0))
    rate = Signal(intbv(0)[math.ceil(math.log10(RMAX+1)/math.log10(2)):])

    # Outputs
    input_tready = Signal(bool(0))
    output_tdata = Signal(intbv(0)[REG_WIDTH:])
    output_tvalid = Signal(bool(0))

    # sources and sinks
    input_source_queue = Queue()
    input_source_pause = Signal(bool(0))
    output_sink_queue = Queue()
    output_sink_pause = Signal(bool(0))
    
    input_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_tdata,
                                           tvalid=input_tvalid,
                                           tready=input_tready,
                                           fifo=input_source_queue,
                                           pause=input_source_pause,
                                           name='input_source')

    output_sink = axis_ep.AXIStreamSink(clk,
                                        rst,
                                        tdata=output_tdata,
                                        tvalid=output_tvalid,
                                        tready=output_tready,
                                        fifo=output_sink_queue,
                                        pause=output_sink_pause,
                                        name='output_sink')

    # DUT
    dut = dut_cic_interpolator(clk,
                               rst,
                               current_test,
                               input_tdata,
                               input_tvalid,
                               input_tready,
                               output_tdata,
                               output_tvalid,
                               output_tready,
                               rate)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        rate.next = 2

        yield clk.posedge
        print("test 1: impulse response")
        current_test.next = 1

        y = [1, 0, 0, 0, 0]
        ref = cic_interpolate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*5

        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 2: ramp")
        current_test.next = 2

        y = list(range(100)) + [0,0]
        ref = cic_interpolate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*5
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 3: source pause")
        current_test.next = 3

        y = list(range(100)) + [0,0]
        ref = cic_interpolate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*5
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            input_source_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            input_source_pause.next = False
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 4: sink pause")
        current_test.next = 4

        y = list(range(100)) + [0,0]
        ref = cic_interpolate(y, N, M, rate)

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = y + [0]*5
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            output_sink_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            output_sink_pause.next = False
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 5: sinewave")
        current_test.next = 5

        x = np.arange(0,100)
        y = np.r_[(np.sin(2*np.pi*x/50)*1024).astype(int), [0,0]]
        ref = cic_interpolate(y, N, M, rate)

        ys = y
        ys[y < 0] += 2**WIDTH

        refs = ref
        refs[ref < 0] += 2**REG_WIDTH

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(map(int, ys)) + [0]*5
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        yield clk.posedge
        print("test 6: rate of 4")
        current_test.next = 6

        rate.next = 4

        yield clk.posedge

        x = np.arange(0,100)
        y = np.r_[(np.sin(2*np.pi*x/50)*1024).astype(int), [0,0]]
        ref = cic_interpolate(y, N, M, rate)

        ys = y
        ys[y < 0] += 2**WIDTH

        refs = ref
        refs[ref < 0] += 2**REG_WIDTH

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(map(int, ys)) + [0]*5
        
        input_source_queue.put(test_frame)
        
        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        print(lst)
        print(ref)
        assert contains(ref, lst)

        yield delay(100)

        raise StopSimulation

    return instances()

def cic_interpolate(y, N=2, M=1, R=2):
    y = np.array(y)

    # comb stage
    for i in range(N):
        for j in range(len(y)-1, M-1, -1):
            y[j] = y[j] - y[j-M]

    # upconvert
    y2 = np.zeros(y.shape[0]*R, dtype=y.dtype)
    y2[0::R] = y
    y = y2

    # integrate
    for i in range(N):
        s = 0
        for j in range(len(y)):
            s += y[j]
            y[j] = s

    return y

def contains(small, big):
    for i in range(len(big)-len(small)+1):
        for j in range(len(small)):
            if big[i+j] != small[j]:
                break
        else:
            return i, i+len(small)
    return False

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_cic_interpolator.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for cic_interpolator
 */
module test_cic_interpolator;

// Parameters
parameter WIDTH = 16;
parameter RMAX = 4;
parameter M = 1;
parameter N = 2;
parameter REG_WIDTH = WIDTH+$max(N, $clog2(((RMAX*M)**N)/RMAX));

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_tdata = 0;
reg input_tvalid = 0;
reg output_tready = 0;
reg [$clog2(RMAX+1)-1:0] rate = 0;

// Outputs
wire input_tready;
wire [REG_WIDTH-1:0] output_tdata;
wire output_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_tdata,
                input_tvalid,
                output_tready,
                rate);
    $to_myhdl(input_tready,
              output_tdata,
              output_tvalid);

    // dump file
    $dumpfile("test_cic_interpolator.lxt");
    $dumpvars(0, test_cic_interpolator);
end

cic_interpolator #(
    .WIDTH(WIDTH),
    .RMAX(RMAX),
    .M(M),
    .N(N)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_tdata(input_tdata),
    .input_tvalid(input_tvalid),
    .input_tready(input_tready),
    .output_tdata(output_tdata),
    .output_tvalid(output_tvalid),
    .output_tready(output_tready),
    .rate(rate)
);

endmodule


================================================
FILE: tb/test_dsp_iq_mult.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep

module = 'dsp_iq_mult'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_dsp_iq_mult(clk,
                    rst,
                    current_test,
                    input_a_i_tdata,
                    input_a_q_tdata,
                    input_a_tvalid,
                    input_a_tready,
                    input_b_i_tdata,
                    input_b_q_tdata,
                    input_b_tvalid,
                    input_b_tready,
                    output_i_tdata,
                    output_q_tdata,
                    output_tvalid,
                    output_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_a_i_tdata=input_a_i_tdata,
                input_a_q_tdata=input_a_q_tdata,
                input_a_tvalid=input_a_tvalid,
                input_a_tready=input_a_tready,
                input_b_i_tdata=input_b_i_tdata,
                input_b_q_tdata=input_b_q_tdata,
                input_b_tvalid=input_b_tvalid,
                input_b_tready=input_b_tready,
                output_i_tdata=output_i_tdata,
                output_q_tdata=output_q_tdata,
                output_tvalid=output_tvalid,
                output_tready=output_tready)

def bench():

    # Parameters
    WIDTH = 16

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_a_i_tdata = Signal(intbv(0)[WIDTH:])
    input_a_q_tdata = Signal(intbv(0)[WIDTH:])
    input_a_tvalid = Signal(bool(0))
    input_b_i_tdata = Signal(intbv(0)[WIDTH:])
    input_b_q_tdata = Signal(intbv(0)[WIDTH:])
    input_b_tvalid = Signal(bool(0))
    output_tready = Signal(bool(0))

    # Outputs
    input_a_tready = Signal(bool(0))
    input_b_tready = Signal(bool(0))
    output_i_tdata = Signal(intbv(0)[WIDTH*2:])
    output_q_tdata = Signal(intbv(0)[WIDTH*2:])
    output_tvalid = Signal(bool(0))

    # sources and sinks
    input_a_source_queue = Queue()
    input_a_source_pause = Signal(bool(0))
    input_b_source_queue = Queue()
    input_b_source_pause = Signal(bool(0))
    output_sink_queue = Queue()
    output_sink_pause = Signal(bool(0))

    input_a_source = axis_ep.AXIStreamSource(clk,
                                             rst,
                                             tdata=(input_a_i_tdata, input_a_q_tdata),
                                             tvalid=input_a_tvalid,
                                             tready=input_a_tready,
                                             fifo=input_a_source_queue,
                                             pause=input_a_source_pause,
                                             name='input_a_source')

    input_b_source = axis_ep.AXIStreamSource(clk,
                                             rst,
                                             tdata=(input_b_i_tdata, input_b_q_tdata),
                                             tvalid=input_b_tvalid,
                                             tready=input_b_tready,
                                             fifo=input_b_source_queue,
                                             pause=input_b_source_pause,
                                             name='input_b_source')

    output_sink = axis_ep.AXIStreamSink(clk,
                                       rst,
                                       tdata=(output_i_tdata, output_q_tdata),
                                       tvalid=output_tvalid,
                                       tready=output_tready,
                                       fifo=output_sink_queue,
                                       pause=output_sink_pause,
                                       name='output_sink')

    # DUT
    dut = dut_dsp_iq_mult(clk,
                          rst,
                          current_test,
                          input_a_i_tdata,
                          input_a_q_tdata,
                          input_a_tvalid,
                          input_a_tready,
                          input_b_i_tdata,
                          input_b_q_tdata,
                          input_b_tvalid,
                          input_b_tready,
                          output_i_tdata,
                          output_q_tdata,
                          output_tvalid,
                          output_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: test multiplier")
        current_test.next = 1

        test_frame1 = axis_ep.AXIStreamFrame()
        test_frame1.data = [[12, 56]] + [[0,0]]*4
        test_frame2 = axis_ep.AXIStreamFrame()
        test_frame2.data = [[34, 78]] + [[0,0]]*4

        input_a_source_queue.put(test_frame1)
        input_b_source_queue.put(test_frame2)

        yield clk.posedge
        yield clk.posedge
        yield clk.posedge
        yield clk.posedge

        while output_sink_queue.empty():
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        for i in range(4):
            rx_frame = output_sink_queue.get(False)

        rx_frame = output_sink_queue.get(False)
        assert rx_frame.data[0] == [12*34,56*78]

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_dsp_iq_mult.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for dsp_iq_mult
 */
module test_dsp_iq_mult;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_a_i_tdata = 0;
reg [WIDTH-1:0] input_a_q_tdata = 0;
reg input_a_tvalid = 0;
reg [WIDTH-1:0] input_b_i_tdata = 0;
reg [WIDTH-1:0] input_b_q_tdata = 0;
reg input_b_tvalid = 0;
reg output_tready = 0;

// Outputs
wire input_a_tready;
wire input_b_tready;
wire [(WIDTH*2)-1:0] output_i_tdata;
wire [(WIDTH*2)-1:0] output_q_tdata;
wire output_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_a_i_tdata,
                input_a_q_tdata,
                input_a_tvalid,
                input_b_i_tdata,
                input_b_q_tdata,
                input_b_tvalid,
                output_tready);
    $to_myhdl(input_a_tready,
              input_b_tready,
              output_i_tdata,
              output_q_tdata,
              output_tvalid);

    // dump file
    $dumpfile("test_dsp_iq_mult.lxt");
    $dumpvars(0, test_dsp_iq_mult);
end

dsp_iq_mult #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_a_i_tdata(input_a_i_tdata),
    .input_a_q_tdata(input_a_q_tdata),
    .input_a_tvalid(input_a_tvalid),
    .input_a_tready(input_a_tready),
    .input_b_i_tdata(input_b_i_tdata),
    .input_b_q_tdata(input_b_q_tdata),
    .input_b_tvalid(input_b_tvalid),
    .input_b_tready(input_b_tready),
    .output_i_tdata(output_i_tdata),
    .output_q_tdata(output_q_tdata),
    .output_tvalid(output_tvalid),
    .output_tready(output_tready)
);

endmodule


================================================
FILE: tb/test_dsp_mult.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep

module = 'dsp_mult'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_dsp_mult(clk,
                 rst,
                 current_test,
                 input_a_tdata,
                 input_a_tvalid,
                 input_a_tready,
                 input_b_tdata,
                 input_b_tvalid,
                 input_b_tready,
                 output_tdata,
                 output_tvalid,
                 output_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_a_tdata=input_a_tdata,
                input_a_tvalid=input_a_tvalid,
                input_a_tready=input_a_tready,
                input_b_tdata=input_b_tdata,
                input_b_tvalid=input_b_tvalid,
                input_b_tready=input_b_tready,
                output_tdata=output_tdata,
                output_tvalid=output_tvalid,
                output_tready=output_tready)

def bench():

    # Parameters
    WIDTH = 16

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_a_tdata = Signal(intbv(0)[WIDTH:])
    input_a_tvalid = Signal(bool(0))
    input_b_tdata = Signal(intbv(0)[WIDTH:])
    input_b_tvalid = Signal(bool(0))
    output_tready = Signal(bool(0))

    # Outputs
    input_a_tready = Signal(bool(0))
    input_b_tready = Signal(bool(0))
    output_tdata = Signal(intbv(0)[WIDTH*2:])
    output_tvalid = Signal(bool(0))

    # sources and sinks
    input_a_source_queue = Queue()
    input_a_source_pause = Signal(bool(0))
    input_b_source_queue = Queue()
    input_b_source_pause = Signal(bool(0))
    output_sink_queue = Queue()
    output_sink_pause = Signal(bool(0))

    input_a_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_a_tdata,
                                           tvalid=input_a_tvalid,
                                           tready=input_a_tready,
                                           fifo=input_a_source_queue,
                                           pause=input_a_source_pause,
                                           name='input_a_source')

    input_b_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_b_tdata,
                                           tvalid=input_b_tvalid,
                                           tready=input_b_tready,
                                           fifo=input_b_source_queue,
                                           pause=input_b_source_pause,
                                           name='input_b_source')

    output_sink = axis_ep.AXIStreamSink(clk,
                                       rst,
                                       tdata=output_tdata,
                                       tvalid=output_tvalid,
                                       tready=output_tready,
                                       fifo=output_sink_queue,
                                       pause=output_sink_pause,
                                       name='output_sink')

    # DUT
    dut = dut_dsp_mult(clk,
                       rst,
                       current_test,
                       input_a_tdata,
                       input_a_tvalid,
                       input_a_tready,
                       input_b_tdata,
                       input_b_tvalid,
                       input_b_tready,
                       output_tdata,
                       output_tvalid,
                       output_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: test multiplier")
        current_test.next = 1

        test_frame1 = axis_ep.AXIStreamFrame()
        test_frame1.data = [123] + [0]*4
        test_frame2 = axis_ep.AXIStreamFrame()
        test_frame2.data = [456] + [0]*4

        input_a_source_queue.put(test_frame1)
        input_b_source_queue.put(test_frame2)

        yield clk.posedge
        yield clk.posedge
        yield clk.posedge
        yield clk.posedge

        while output_sink_queue.empty():
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        for i in range(4):
            rx_frame = output_sink_queue.get(False)

        rx_frame = output_sink_queue.get(False)
        assert rx_frame.data[0] == 123*456

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_dsp_mult.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for dsp_mult
 */
module test_dsp_mult;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_a_tdata = 0;
reg input_a_tvalid = 0;
reg [WIDTH-1:0] input_b_tdata = 0;
reg input_b_tvalid = 0;
reg output_tready = 0;

// Outputs
wire input_a_tready;
wire input_b_tready;
wire [(WIDTH*2)-1:0] output_tdata;
wire output_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_a_tdata,
                input_a_tvalid,
                input_b_tdata,
                input_b_tvalid,
                output_tready);
    $to_myhdl(input_a_tready,
              input_b_tready,
              output_tdata,
              output_tvalid);

    // dump file
    $dumpfile("test_dsp_mult.lxt");
    $dumpvars(0, test_dsp_mult);
end

dsp_mult #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_a_tdata(input_a_tdata),
    .input_a_tvalid(input_a_tvalid),
    .input_a_tready(input_a_tready),
    .input_b_tdata(input_b_tdata),
    .input_b_tvalid(input_b_tvalid),
    .input_b_tready(input_b_tready),
    .output_tdata(output_tdata),
    .output_tvalid(output_tvalid),
    .output_tready(output_tready)
);

endmodule


================================================
FILE: tb/test_i2s_ctrl.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

import i2s_ep

module = 'i2s_ctrl'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_i2s_ctrl(clk,
                 rst,
                 current_test,
                 sck,
                 ws,
                 prescale):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                sck=sck,
                ws=ws,
                prescale=prescale)

def bench():

    # Parameters
    WIDTH = 16

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    prescale = Signal(intbv(0)[16:])

    # Outputs
    sck = Signal(bool(0))
    ws = Signal(bool(0))

    sck_check = Signal(bool(0))
    ws_check = Signal(bool(0))

    i2s_ctrl = i2s_ep.I2SControl(clk,
                                 rst,
                                 sck=sck_check,
                                 ws=ws_check,
                                 width=WIDTH,
                                 prescale=prescale)

    # DUT
    dut = dut_i2s_ctrl(clk,
                       rst,
                       current_test,
                       sck,
                       ws,
                       prescale)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: no prescaler")
        current_test.next = 1

        for i in range(100):
            print(sck, ws, sck_check, ws_check)
            assert sck == sck_check
            assert ws == ws_check
            yield clk.posedge

        yield delay(100)

        yield clk.posedge
        print("test 2: prescaler of 4")
        current_test.next = 2

        prescale.next = 4

        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        for i in range(100):
            print(sck, ws, sck_check, ws_check)
            assert sck == sck_check
            assert ws == ws_check
            yield clk.posedge

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_i2s_ctrl.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for i2s_ctrl
 */
module test_i2s_ctrl;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [15:0] prescale = 0;

// Outputs
wire sck;
wire ws;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                prescale);
    $to_myhdl(sck,
              ws);

    // dump file
    $dumpfile("test_i2s_ctrl.lxt");
    $dumpvars(0, test_i2s_ctrl);
end

i2s_ctrl #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .sck(sck),
    .ws(ws),
    .prescale(prescale)
);

endmodule


================================================
FILE: tb/test_i2s_rx.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep
import i2s_ep

module = 'i2s_rx'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_i2s_rx(clk,
               rst,
               current_test,
               sck,
               ws,
               sd,
               output_l_tdata,
               output_r_tdata,
               output_tvalid,
               output_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                sck=sck,
                ws=ws,
                sd=sd,
                output_l_tdata=output_l_tdata,
                output_r_tdata=output_r_tdata,
                output_tvalid=output_tvalid,
                output_tready=output_tready)

def bench():

    # Parameters
    WIDTH = 16

    i2s_ctrl_width = Signal(intbv(WIDTH))

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    sck = Signal(bool(0))
    ws = Signal(bool(0))
    sd = Signal(bool(0))
    output_tready = Signal(bool(0))

    # Outputs
    output_l_tdata = Signal(intbv(0)[WIDTH:])
    output_r_tdata = Signal(intbv(0)[WIDTH:])
    output_tvalid = Signal(bool(0))

    # Sources and sinks
    input_source_queue = Queue()
    output_sink_queue = Queue()
    output_sink_pause = Signal(bool(0))

    i2s_ctrl = i2s_ep.I2SControl(clk,
                                 rst,
                                 sck=sck,
                                 ws=ws,
                                 width=i2s_ctrl_width,
                                 prescale=2)

    i2s_source = i2s_ep.I2SSource(clk,
                                  rst,
                                  sck=sck,
                                  ws=ws,
                                  sd=sd,
                                  width=WIDTH,
                                  fifo=input_source_queue,
                                  name='source')

    output_sink = axis_ep.AXIStreamSink(clk,
                                        rst,
                                        tdata=(output_l_tdata, output_r_tdata),
                                        tvalid=output_tvalid,
                                        tready=output_tready,
                                        fifo=output_sink_queue,
                                        pause=output_sink_pause,
                                        name='output_sink')

    # DUT
    dut = dut_i2s_rx(clk,
                     rst,
                     current_test,
                     sck,
                     ws,
                     sd,
                     output_l_tdata,
                     output_r_tdata,
                     output_tvalid,
                     output_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: test ramp")
        current_test.next = 1

        y_l = list(range(0,4096,128))
        y_r = list(range(4096-128,-128,-128))
        y = list(zip(y_l, y_r))

        for p in y:
            input_source_queue.put(p)

        yield clk.posedge
        yield clk.posedge

        while not input_source_queue.empty():
            yield clk.posedge

        yield clk.posedge

        yield delay(3000)

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        lst = [tuple(p) for p in lst]

        assert contains(y, lst)

        yield delay(100)

        yield clk.posedge
        print("test 2: trailing zeros")
        current_test.next = 2

        i2s_ctrl_width.next = 24

        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        y_l = list(range(0,4096,128))
        y_r = list(range(4096-128,-128,-128))
        y = list(zip(y_l, y_r))

        for p in y:
            input_source_queue.put(p)

        yield clk.posedge
        yield clk.posedge

        while not input_source_queue.empty():
            yield clk.posedge

        yield clk.posedge

        yield delay(5000)

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        lst = [tuple(p) for p in lst]

        assert contains(y, lst)

        yield delay(100)

        raise StopSimulation

    return instances()

def contains(small, big):
    for i in range(len(big)-len(small)+1):
        for j in range(len(small)):
            if big[i+j] != small[j]:
                break
        else:
            return i, i+len(small)
    return False

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_i2s_rx.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for i2s_rx
 */
module test_i2s_rx;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg sck = 0;
reg ws = 0;
reg sd = 0;
reg output_tready = 0;

// Outputs
wire [WIDTH-1:0] output_l_tdata;
wire [WIDTH-1:0] output_r_tdata;
wire output_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                sck,
                ws,
                sd,
                output_tready);
    $to_myhdl(output_l_tdata,
              output_r_tdata,
              output_tvalid);

    // dump file
    $dumpfile("test_i2s_rx.lxt");
    $dumpvars(0, test_i2s_rx);
end

i2s_rx #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .sck(sck),
    .ws(ws),
    .sd(sd),
    .output_l_tdata(output_l_tdata),
    .output_r_tdata(output_r_tdata),
    .output_tvalid(output_tvalid),
    .output_tready(output_tready)
);

endmodule


================================================
FILE: tb/test_i2s_tx.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep
import i2s_ep

module = 'i2s_tx'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_i2s_tx(clk,
               rst,
               current_test,
               input_l_tdata,
               input_r_tdata,
               input_tvalid,
               input_tready,
               sck,
               ws,
               sd):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_l_tdata=input_l_tdata,
                input_r_tdata=input_r_tdata,
                input_tvalid=input_tvalid,
                input_tready=input_tready,
                sck=sck,
                ws=ws,
                sd=sd)

def bench():

    # Parameters
    WIDTH = 16

    i2s_ctrl_width = Signal(intbv(WIDTH))

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_l_tdata = Signal(intbv(0)[WIDTH:])
    input_r_tdata = Signal(intbv(0)[WIDTH:])
    input_tvalid = Signal(bool(0))
    sck = Signal(bool(0))
    ws = Signal(bool(0))

    # Outputs
    input_tready = Signal(bool(0))
    sd = Signal(bool(0))

    # Sources and sinks
    input_source_queue = Queue()
    input_source_pause = Signal(bool(0))
    output_sink_queue = Queue()

    input_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=(input_l_tdata, input_r_tdata),
                                           tvalid=input_tvalid,
                                           tready=input_tready,
                                           fifo=input_source_queue,
                                           pause=input_source_pause,
                                           name='input_source')

    i2s_ctrl = i2s_ep.I2SControl(clk,
                                 rst,
                                 sck=sck,
                                 ws=ws,
                                 width=i2s_ctrl_width,
                                 prescale=2)

    i2s_sink = i2s_ep.I2SSink(clk,
                              rst,
                              sck=sck,
                              ws=ws,
                              sd=sd,
                              width=WIDTH,
                              fifo=output_sink_queue,
                              name='sink')

    # DUT
    dut = dut_i2s_tx(clk,
                     rst,
                     current_test,
                     input_l_tdata,
                     input_r_tdata,
                     input_tvalid,
                     input_tready,
                     sck,
                     ws,
                     sd)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: test ramp")
        current_test.next = 1

        y_l = list(range(0,4096,128))
        y_r = list(range(4096-128,-128,-128))
        y = list(zip(y_l, y_r))

        input_source_queue.put(y)

        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        yield delay(3000)

        lst = []

        while not output_sink_queue.empty():
            lst.append(output_sink_queue.get(False))

        assert contains(y, lst)

        yield delay(100)

        yield clk.posedge
        print("test 2: trailing zeros")
        current_test.next = 2

        i2s_ctrl_width.next = 24

        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        y_l = list(range(0,4096,128))
        y_r = list(range(4096-128,-128,-128))
        y = list(zip(y_l, y_r))

        input_source_queue.put(y)

        yield clk.posedge
        yield clk.posedge

        while input_tvalid:
            yield clk.posedge

        yield clk.posedge

        yield delay(5000)

        lst = []

        while not output_sink_queue.empty():
            lst.append(output_sink_queue.get(False))

        assert contains(y, lst)

        yield delay(100)

        raise StopSimulation

    return instances()

def contains(small, big):
    for i in range(len(big)-len(small)+1):
        for j in range(len(small)):
            if big[i+j] != small[j]:
                break
        else:
            return i, i+len(small)
    return False

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_i2s_tx.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for i2s_tx
 */
module test_i2s_tx;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_l_tdata = 0;
reg [WIDTH-1:0] input_r_tdata = 0;
reg input_tvalid = 0;
reg sck = 0;
reg ws = 0;

// Outputs
wire input_tready;
wire sd;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_l_tdata,
                input_r_tdata,
                input_tvalid,
                sck,
                ws);
    $to_myhdl(input_tready,
              sd);

    // dump file
    $dumpfile("test_i2s_tx.lxt");
    $dumpvars(0, test_i2s_tx);
end

i2s_tx #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_l_tdata(input_l_tdata),
    .input_r_tdata(input_r_tdata),
    .input_tvalid(input_tvalid),
    .input_tready(input_tready),
    .sck(sck),
    .ws(ws),
    .sd(sd)
);

endmodule


================================================
FILE: tb/test_iq_join.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep

module = 'iq_join'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_iq_join(clk,
                rst,
                current_test,
                input_i_tdata,
                input_i_tvalid,
                input_i_tready,
                input_q_tdata,
                input_q_tvalid,
                input_q_tready,
                output_i_tdata,
                output_q_tdata,
                output_tvalid,
                output_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_i_tdata=input_i_tdata,
                input_i_tvalid=input_i_tvalid,
                input_i_tready=input_i_tready,
                input_q_tdata=input_q_tdata,
                input_q_tvalid=input_q_tvalid,
                input_q_tready=input_q_tready,
                output_i_tdata=output_i_tdata,
                output_q_tdata=output_q_tdata,
                output_tvalid=output_tvalid,
                output_tready=output_tready)

def bench():

    # Parameters
    WIDTH = 16

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_i_tdata = Signal(intbv(0)[WIDTH:])
    input_i_tvalid = Signal(bool(0))
    input_q_tdata = Signal(intbv(0)[WIDTH:])
    input_q_tvalid = Signal(bool(0))
    output_tready = Signal(bool(0))

    # Outputs
    input_i_tready = Signal(bool(0))
    input_q_tready = Signal(bool(0))
    output_i_tdata = Signal(intbv(0)[WIDTH:])
    output_q_tdata = Signal(intbv(0)[WIDTH:])
    output_tvalid = Signal(bool(0))

    # Sources and sinks
    input_i_source_queue = Queue()
    input_i_source_pause = Signal(bool(0))
    input_q_source_queue = Queue()
    input_q_source_pause = Signal(bool(0))
    output_sink_queue = Queue()
    output_sink_pause = Signal(bool(0))

    input_i_source = axis_ep.AXIStreamSource(clk,
                                             rst,
                                             tdata=input_i_tdata,
                                             tvalid=input_i_tvalid,
                                             tready=input_i_tready,
                                             fifo=input_i_source_queue,
                                             pause=input_i_source_pause,
                                             name='input_i_source')

    input_q_source = axis_ep.AXIStreamSource(clk,
                                             rst,
                                             tdata=input_q_tdata,
                                             tvalid=input_q_tvalid,
                                             tready=input_q_tready,
                                             fifo=input_q_source_queue,
                                             pause=input_q_source_pause,
                                             name='input_q_source')

    output_sink = axis_ep.AXIStreamSink(clk,
                                       rst,
                                       tdata=(output_i_tdata, output_q_tdata),
                                       tvalid=output_tvalid,
                                       tready=output_tready,
                                       fifo=output_sink_queue,
                                       pause=output_sink_pause,
                                       name='output_sink')

    # DUT
    dut = dut_iq_join(clk,
                      rst,
                      current_test,
                      input_i_tdata,
                      input_i_tvalid,
                      input_i_tready,
                      input_q_tdata,
                      input_q_tvalid,
                      input_q_tready,
                      output_i_tdata,
                      output_q_tdata,
                      output_tvalid,
                      output_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: test sequence")
        current_test.next = 1

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame_i = axis_ep.AXIStreamFrame(i_data)
        test_frame_q = axis_ep.AXIStreamFrame(q_data)

        input_i_source_queue.put(test_frame_i)
        input_q_source_queue.put(test_frame_q)
        yield clk.posedge
        yield clk.posedge

        while input_i_tvalid or input_q_tvalid or output_tvalid:
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        assert lst == [list(f) for f in zip(i_data, q_data)]

        yield delay(100)

        yield clk.posedge
        print("test 2: pause source")
        current_test.next = 2

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame_i = axis_ep.AXIStreamFrame(i_data)
        test_frame_q = axis_ep.AXIStreamFrame(q_data)

        input_i_source_queue.put(test_frame_i)
        input_q_source_queue.put(test_frame_q)
        yield clk.posedge
        yield clk.posedge

        while input_i_tvalid or input_q_tvalid or output_tvalid:
            input_i_source_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            input_i_source_pause.next = False
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        assert lst == [list(f) for f in zip(i_data, q_data)]

        yield delay(100)

        yield clk.posedge
        print("test 3: pause both sources")
        current_test.next = 3

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame_i = axis_ep.AXIStreamFrame(i_data)
        test_frame_q = axis_ep.AXIStreamFrame(q_data)

        input_i_source_queue.put(test_frame_i)
        input_q_source_queue.put(test_frame_q)
        yield clk.posedge
        yield clk.posedge

        input_q_source_pause.next = True

        while input_i_tvalid or input_q_tvalid or output_tvalid:
            input_i_source_pause.next = True
            yield clk.posedge
            input_q_source_pause.next = False
            yield clk.posedge
            input_q_source_pause.next = True
            yield clk.posedge
            input_i_source_pause.next = False
            yield clk.posedge

        input_q_source_pause.next = False

        yield clk.posedge
        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        assert lst == [list(f) for f in zip(i_data, q_data)]

        yield delay(100)

        yield clk.posedge
        print("test 4: pause sink")
        current_test.next = 4

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame_i = axis_ep.AXIStreamFrame(i_data)
        test_frame_q = axis_ep.AXIStreamFrame(q_data)

        input_i_source_queue.put(test_frame_i)
        input_q_source_queue.put(test_frame_q)
        yield clk.posedge
        yield clk.posedge

        while input_i_tvalid or input_q_tvalid or output_tvalid:
            output_sink_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            output_sink_pause.next = False
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        assert lst == [list(f) for f in zip(i_data, q_data)]

        yield delay(100)

        yield clk.posedge
        print("test 5: pause source and sink")
        current_test.next = 4

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame_i = axis_ep.AXIStreamFrame(i_data)
        test_frame_q = axis_ep.AXIStreamFrame(q_data)

        input_i_source_queue.put(test_frame_i)
        input_q_source_queue.put(test_frame_q)
        yield clk.posedge
        yield clk.posedge

        input_q_source_pause.next = True
    
        while input_i_tvalid or input_q_tvalid or output_tvalid:
            output_sink_pause.next = True
            yield clk.posedge
            input_q_source_pause.next = False
            yield clk.posedge
            input_q_source_pause.next = True
            yield clk.posedge
            output_sink_pause.next = False
            yield clk.posedge
        
        input_q_source_pause.next = False

        yield clk.posedge
        yield clk.posedge

        lst = []

        while not output_sink_queue.empty():
            lst += output_sink_queue.get(False).data

        assert lst == [list(f) for f in zip(i_data, q_data)]

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_iq_join.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for iq_join
 */
module test_iq_join;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_i_tdata = 0;
reg input_i_tvalid = 0;
reg [WIDTH-1:0] input_q_tdata = 0;
reg input_q_tvalid = 0;
reg output_tready = 0;

// Outputs
wire input_i_tready;
wire input_q_tready;
wire [WIDTH-1:0] output_i_tdata;
wire [WIDTH-1:0] output_q_tdata;
wire output_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_i_tdata,
                input_i_tvalid,
                input_q_tdata,
                input_q_tvalid,
                output_tready);
    $to_myhdl(input_i_tready,
              input_q_tready,
              output_i_tdata,
              output_q_tdata,
              output_tvalid);

    // dump file
    $dumpfile("test_iq_join.lxt");
    $dumpvars(0, test_iq_join);
end

iq_join #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_i_tdata(input_i_tdata),
    .input_i_tvalid(input_i_tvalid),
    .input_i_tready(input_i_tready),
    .input_q_tdata(input_q_tdata),
    .input_q_tvalid(input_q_tvalid),
    .input_q_tready(input_q_tready),
    .output_i_tdata(output_i_tdata),
    .output_q_tdata(output_q_tdata),
    .output_tvalid(output_tvalid),
    .output_tready(output_tready)
);

endmodule


================================================
FILE: tb/test_iq_split.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep

module = 'iq_split'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_iq_split(clk,
                 rst,
                 current_test,
                 input_i_tdata,
                 input_q_tdata,
                 input_tvalid,
                 input_tready,
                 output_i_tdata,
                 output_i_tvalid,
                 output_i_tready,
                 output_q_tdata,
                 output_q_tvalid,
                 output_q_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,
                input_i_tdata=input_i_tdata,
                input_q_tdata=input_q_tdata,
                input_tvalid=input_tvalid,
                input_tready=input_tready,
                output_i_tdata=output_i_tdata,
                output_i_tvalid=output_i_tvalid,
                output_i_tready=output_i_tready,
                output_q_tdata=output_q_tdata,
                output_q_tvalid=output_q_tvalid,
                output_q_tready=output_q_tready)

def bench():

    # Parameters
    WIDTH = 16

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_i_tdata = Signal(intbv(0)[WIDTH:])
    input_q_tdata = Signal(intbv(0)[WIDTH:])
    input_tvalid = Signal(bool(0))
    output_i_tready = Signal(bool(0))
    output_q_tready = Signal(bool(0))

    # Outputs
    input_tready = Signal(bool(0))
    output_i_tdata = Signal(intbv(0)[WIDTH:])
    output_i_tvalid = Signal(bool(0))
    output_q_tdata = Signal(intbv(0)[WIDTH:])
    output_q_tvalid = Signal(bool(0))

    # Sources and sinks
    input_source_queue = Queue()
    input_source_pause = Signal(bool(0))
    output_i_sink_queue = Queue()
    output_i_sink_pause = Signal(bool(0))
    output_q_sink_queue = Queue()
    output_q_sink_pause = Signal(bool(0))

    input_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=(input_i_tdata, input_q_tdata),
                                           tvalid=input_tvalid,
                                           tready=input_tready,
                                           fifo=input_source_queue,
                                           pause=input_source_pause,
                                           name='input_source')

    output_i_sink = axis_ep.AXIStreamSink(clk,
                                          rst,
                                          tdata=output_i_tdata,
                                          tvalid=output_i_tvalid,
                                          tready=output_i_tready,
                                          fifo=output_i_sink_queue,
                                          pause=output_i_sink_pause,
                                          name='output_i_sink')

    output_q_sink = axis_ep.AXIStreamSink(clk,
                                          rst,
                                          tdata=output_q_tdata,
                                          tvalid=output_q_tvalid,
                                          tready=output_q_tready,
                                          fifo=output_q_sink_queue,
                                          pause=output_q_sink_pause,
                                          name='output_q_sink')

    # DUT
    dut = dut_iq_split(clk,
                       rst,
                       current_test,
                       input_i_tdata,
                       input_q_tdata,
                       input_tvalid,
                       input_tready,
                       output_i_tdata,
                       output_i_tvalid,
                       output_i_tready,
                       output_q_tdata,
                       output_q_tvalid,
                       output_q_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: test sequence")
        current_test.next = 1

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame = axis_ep.AXIStreamFrame(zip(i_data, q_data))

        input_source_queue.put(test_frame)
        yield clk.posedge
        yield clk.posedge

        while input_tvalid or output_i_tvalid or output_q_tvalid:
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        i_lst = []
        q_lst = []

        while not output_i_sink_queue.empty():
            i_lst += output_i_sink_queue.get(False).data
        while not output_q_sink_queue.empty():
            q_lst += output_q_sink_queue.get(False).data

        assert i_data == i_lst
        assert q_data == q_lst

        yield delay(100)

        yield clk.posedge
        print("test 2: pause source")
        current_test.next = 2

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame = axis_ep.AXIStreamFrame(zip(i_data, q_data))

        input_source_queue.put(test_frame)
        yield clk.posedge
        yield clk.posedge

        while input_tvalid or output_i_tvalid or output_q_tvalid:
            input_source_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            input_source_pause.next = False
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        i_lst = []
        q_lst = []

        while not output_i_sink_queue.empty():
            i_lst += output_i_sink_queue.get(False).data
        while not output_q_sink_queue.empty():
            q_lst += output_q_sink_queue.get(False).data

        assert i_data == i_lst
        assert q_data == q_lst

        yield delay(100)

        yield clk.posedge
        print("test 3: pause sink")
        current_test.next = 3

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame = axis_ep.AXIStreamFrame(zip(i_data, q_data))

        input_source_queue.put(test_frame)
        yield clk.posedge
        yield clk.posedge

        while input_tvalid or output_i_tvalid or output_q_tvalid:
            output_i_sink_pause.next = True
            yield clk.posedge
            yield clk.posedge
            yield clk.posedge
            output_i_sink_pause.next = False
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        i_lst = []
        q_lst = []

        while not output_i_sink_queue.empty():
            i_lst += output_i_sink_queue.get(False).data
        while not output_q_sink_queue.empty():
            q_lst += output_q_sink_queue.get(False).data

        assert i_data == i_lst
        assert q_data == q_lst

        yield delay(100)

        yield clk.posedge
        print("test 4: pause both sinks")
        current_test.next = 4

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame = axis_ep.AXIStreamFrame(zip(i_data, q_data))

        input_source_queue.put(test_frame)
        yield clk.posedge
        yield clk.posedge

        output_q_sink_pause.next = True

        while input_tvalid or output_i_tvalid or output_q_tvalid:
            output_i_sink_pause.next = True
            yield clk.posedge
            output_q_sink_pause.next = False
            yield clk.posedge
            output_q_sink_pause.next = True
            yield clk.posedge
            output_i_sink_pause.next = False
            yield clk.posedge

        output_q_sink_pause.next = False

        yield clk.posedge
        yield clk.posedge

        i_lst = []
        q_lst = []

        while not output_i_sink_queue.empty():
            i_lst += output_i_sink_queue.get(False).data
        while not output_q_sink_queue.empty():
            q_lst += output_q_sink_queue.get(False).data

        assert i_data == i_lst
        assert q_data == q_lst

        yield delay(100)

        yield clk.posedge
        print("test 5: pause source and sink")
        current_test.next = 5

        i_data = list(range(20))
        q_data = list(range(20,40))

        test_frame = axis_ep.AXIStreamFrame(zip(i_data, q_data))

        input_source_queue.put(test_frame)
        yield clk.posedge
        yield clk.posedge

        output_q_sink_pause.next = True

        while input_tvalid or output_i_tvalid or output_q_tvalid:
            input_source_pause.next = True
            yield clk.posedge
            output_q_sink_pause.next = False
            yield clk.posedge
            output_q_sink_pause.next = True
            yield clk.posedge
            input_source_pause.next = False
            yield clk.posedge

        output_q_sink_pause.next = False

        yield clk.posedge
        yield clk.posedge

        i_lst = []
        q_lst = []

        while not output_i_sink_queue.empty():
            i_lst += output_i_sink_queue.get(False).data
        while not output_q_sink_queue.empty():
            q_lst += output_q_sink_queue.get(False).data

        assert i_data == i_lst
        assert q_data == q_lst

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_iq_split.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for iq_split
 */
module test_iq_split;

// Parameters
parameter WIDTH = 16;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_i_tdata = 0;
reg [WIDTH-1:0] input_q_tdata = 0;
reg input_tvalid = 0;
reg output_i_tready = 0;
reg output_q_tready = 0;

// Outputs
wire input_tready;
wire [WIDTH-1:0] output_i_tdata;
wire output_i_tvalid;
wire [WIDTH-1:0] output_q_tdata;
wire output_q_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_i_tdata,
                input_q_tdata,
                input_tvalid,
                output_i_tready,
                output_q_tready);
    $to_myhdl(input_tready,
              output_i_tdata,
              output_i_tvalid,
              output_q_tdata,
              output_q_tvalid);

    // dump file
    $dumpfile("test_iq_split.lxt");
    $dumpvars(0, test_iq_split);
end

iq_split #(
    .WIDTH(WIDTH)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_i_tdata(input_i_tdata),
    .input_q_tdata(input_q_tdata),
    .input_tvalid(input_tvalid),
    .input_tready(input_tready),
    .output_i_tdata(output_i_tdata),
    .output_i_tvalid(output_i_tvalid),
    .output_i_tready(output_i_tready),
    .output_q_tdata(output_q_tdata),
    .output_q_tvalid(output_q_tvalid),
    .output_q_tready(output_q_tready)
);

endmodule


================================================
FILE: tb/test_phase_accumulator.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import axis_ep

module = 'phase_accumulator'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_phase_accumulator(clk,
                          rst,
                          current_test,

                          input_phase_tdata,
                          input_phase_tvalid,
                          input_phase_tready,

                          input_phase_step_tdata,
                          input_phase_step_tvalid,
                          input_phase_step_tready,

                          output_phase_tdata,
                          output_phase_tvalid,
                          output_phase_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,

                input_phase_tdata=input_phase_tdata,
                input_phase_tvalid=input_phase_tvalid,
                input_phase_tready=input_phase_tready,

                input_phase_step_tdata=input_phase_step_tdata,
                input_phase_step_tvalid=input_phase_step_tvalid,
                input_phase_step_tready=input_phase_step_tready,

                output_phase_tdata=output_phase_tdata,
                output_phase_tvalid=output_phase_tvalid,
                output_phase_tready=output_phase_tready)

def bench():

    # Parameters
    WIDTH = 32
    INITIAL_PHASE = 0
    INITIAL_PHASE_STEP = 0

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_phase_tdata = Signal(intbv(0)[WIDTH:])
    input_phase_tvalid = Signal(bool(0))
    input_phase_step_tdata = Signal(intbv(0)[WIDTH:])
    input_phase_step_tvalid = Signal(bool(0))
    output_phase_tready = Signal(bool(0))

    # Outputs
    input_phase_tready = Signal(bool(1))
    input_phase_step_tready = Signal(bool(1))
    output_phase_tdata = Signal(intbv(0)[WIDTH:])
    output_phase_tvalid = Signal(bool(1))

    # sources and sinks
    phase_source_queue = Queue()
    phase_source_pause = Signal(bool(0))
    phase_step_source_queue = Queue()
    phase_step_source_pause = Signal(bool(0))
    phase_sink_queue = Queue()
    phase_sink_pause = Signal(bool(0))

    phase_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_phase_tdata,
                                           tvalid=input_phase_tvalid,
                                           tready=input_phase_tready,
                                           fifo=phase_source_queue,
                                           pause=phase_source_pause,
                                           name='phase_source')

    phase_step_source = axis_ep.AXIStreamSource(clk,
                                                rst,
                                                tdata=input_phase_step_tdata,
                                                tvalid=input_phase_step_tvalid,
                                                tready=input_phase_step_tready,
                                                fifo=phase_step_source_queue,
                                                pause=phase_step_source_pause,
                                                name='phase_step_source')

    phase_sink = axis_ep.AXIStreamSink(clk,
                                       rst,
                                       tdata=output_phase_tdata,
                                       tvalid=output_phase_tvalid,
                                       tready=output_phase_tready,
                                       fifo=phase_sink_queue,
                                       pause=phase_sink_pause,
                                       name='phase_sink')

    # DUT
    dut = dut_phase_accumulator(clk,
                                rst,
                                current_test,

                                input_phase_tdata,
                                input_phase_tvalid,
                                input_phase_tready,

                                input_phase_step_tdata,
                                input_phase_step_tvalid,
                                input_phase_step_tready,

                                output_phase_tdata,
                                output_phase_tvalid,
                                output_phase_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: initial phase")
        current_test.next = 1

        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = [123456]

        phase_source_queue.put(test_frame)

        yield clk.posedge
        yield clk.posedge

        while not phase_sink_queue.empty():
            phase_sink_queue.get(False)

        yield clk.posedge
        yield clk.posedge

        rx_frame = phase_sink_queue.get(False)
        assert rx_frame.data[0] == 123456

        yield delay(100)

        yield clk.posedge
        print("test 2: phase step")
        current_test.next = 2

        test_frame1 = axis_ep.AXIStreamFrame()
        test_frame1.data = [10000]
        test_frame2 = axis_ep.AXIStreamFrame()
        test_frame2.data = [5000]

        phase_source_queue.put(test_frame1)
        phase_step_source_queue.put(test_frame2)

        yield clk.posedge
        yield clk.posedge

        while not phase_sink_queue.empty():
            phase_sink_queue.get(False)

        yield clk.posedge
        yield clk.posedge
        yield clk.posedge

        rx_frame = phase_sink_queue.get(False)
        assert rx_frame.data[0] == 10000
        rx_frame = phase_sink_queue.get(False)
        assert rx_frame.data[0] == 15000
        rx_frame = phase_sink_queue.get(False)
        assert rx_frame.data[0] == 20000

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_phase_accumulator.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for phase_accumulator
 */
module test_phase_accumulator;

// Parameters
parameter WIDTH = 32;
parameter INITIAL_PHASE = 0;
parameter INITIAL_PHASE_STEP = 0;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [WIDTH-1:0] input_phase_tdata = 0;
reg input_phase_tvalid = 0;
reg [WIDTH-1:0] input_phase_step_tdata = 0;
reg input_phase_step_tvalid = 0;
reg output_phase_tready = 0;

// Outputs
wire input_phase_tready;
wire input_phase_step_tready;
wire [WIDTH-1:0] output_phase_tdata;
wire output_phase_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_phase_tdata,
                input_phase_tvalid,
                input_phase_step_tdata,
                input_phase_step_tvalid,
                output_phase_tready);
    $to_myhdl(input_phase_tready,
              input_phase_step_tready,
              output_phase_tdata,
              output_phase_tvalid);

    // dump file
    $dumpfile("test_phase_accumulator.lxt");
    $dumpvars(0, test_phase_accumulator);
end

phase_accumulator #(
    .WIDTH(WIDTH),
    .INITIAL_PHASE(INITIAL_PHASE),
    .INITIAL_PHASE_STEP(INITIAL_PHASE_STEP)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_phase_tdata(input_phase_tdata),
    .input_phase_tvalid(input_phase_tvalid),
    .input_phase_tready(input_phase_tready),
    .input_phase_step_tdata(input_phase_step_tdata),
    .input_phase_step_tvalid(input_phase_step_tvalid),
    .input_phase_step_tready(input_phase_step_tready),
    .output_phase_tdata(output_phase_tdata),
    .output_phase_tvalid(output_phase_tvalid),
    .output_phase_tready(output_phase_tready)
);

endmodule


================================================
FILE: tb/test_sine_dds.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import numpy as np

import axis_ep

module = 'sine_dds'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/phase_accumulator.v")
srcs.append("../rtl/sine_dds_lut.v")
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_sine_dds(clk,
                 rst,
                 current_test,

                 input_phase_tdata,
                 input_phase_tvalid,
                 input_phase_tready,

                 input_phase_step_tdata,
                 input_phase_step_tvalid,
                 input_phase_step_tready,

                 output_sample_i_tdata,
                 output_sample_q_tdata,
                 output_sample_tvalid,
                 output_sample_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,

                input_phase_tdata=input_phase_tdata,
                input_phase_tvalid=input_phase_tvalid,
                input_phase_tready=input_phase_tready,

                input_phase_step_tdata=input_phase_step_tdata,
                input_phase_step_tvalid=input_phase_step_tvalid,
                input_phase_step_tready=input_phase_step_tready,

                output_sample_i_tdata=output_sample_i_tdata,
                output_sample_q_tdata=output_sample_q_tdata,
                output_sample_tvalid=output_sample_tvalid,
                output_sample_tready=output_sample_tready)

def bench():

    # Parameters
    PHASE_WIDTH = 32
    OUTPUT_WIDTH = 16
    INITIAL_PHASE = 0
    INITIAL_PHASE_STEP = 0

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_phase_tdata = Signal(intbv(0)[PHASE_WIDTH:])
    input_phase_tvalid = Signal(bool(0))
    input_phase_step_tdata = Signal(intbv(0)[PHASE_WIDTH:])
    input_phase_step_tvalid = Signal(bool(0))
    output_sample_tready = Signal(bool(0))

    # Outputs
    input_phase_tready = Signal(bool(0))
    input_phase_step_tready = Signal(bool(1))
    output_sample_i_tdata = Signal(intbv(0)[OUTPUT_WIDTH:])
    output_sample_q_tdata = Signal(intbv(0)[OUTPUT_WIDTH:])
    output_sample_tvalid = Signal(bool(1))

    # sources and sinks
    phase_source_queue = Queue()
    phase_source_pause = Signal(bool(0))
    phase_step_source_queue = Queue()
    phase_step_source_pause = Signal(bool(0))
    sample_sink_queue = Queue()
    sample_sink_pause = Signal(bool(0))

    phase_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_phase_tdata,
                                           tvalid=input_phase_tvalid,
                                           tready=input_phase_tready,
                                           fifo=phase_source_queue,
                                           pause=phase_source_pause,
                                           name='phase_source')

    phase_step_source = axis_ep.AXIStreamSource(clk,
                                                rst,
                                                tdata=input_phase_step_tdata,
                                                tvalid=input_phase_step_tvalid,
                                                tready=input_phase_step_tready,
                                                fifo=phase_step_source_queue,
                                                pause=phase_step_source_pause,
                                                name='phase_step_source')

    sample_sink = axis_ep.AXIStreamSink(clk,
                                        rst,
                                        tdata=(output_sample_i_tdata, output_sample_q_tdata),
                                        tvalid=output_sample_tvalid,
                                        tready=output_sample_tready,
                                        fifo=sample_sink_queue,
                                        pause=sample_sink_pause,
                                        name='sample_sink')

    # DUT
    dut = dut_sine_dds(clk,
                       rst,
                       current_test,

                       input_phase_tdata,
                       input_phase_tvalid,
                       input_phase_tready,

                       input_phase_step_tdata,
                       input_phase_step_tvalid,
                       input_phase_step_tready,

                       output_sample_i_tdata,
                       output_sample_q_tdata,
                       output_sample_tvalid,
                       output_sample_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: high frequency")
        current_test.next = 1

        fcw = int(2**PHASE_WIDTH / 100)
        offset = 0

        test_frame1 = axis_ep.AXIStreamFrame()
        test_frame1.data = [offset]
        test_frame2 = axis_ep.AXIStreamFrame()
        test_frame2.data = [fcw]

        phase_source_queue.put(test_frame1)
        phase_step_source_queue.put(test_frame2)

        yield clk.posedge
        yield clk.posedge

        while not sample_sink_queue.empty():
            sample_sink_queue.get(False)

        yield delay(1000)

        for j in range(6):
            sample_sink_queue.get(False)

        for j in range(100):
            rx_frame = sample_sink_queue.get(False)
            INPUT_WIDTH = OUTPUT_WIDTH+2
            x = int((fcw*j + offset) / 2**(PHASE_WIDTH-INPUT_WIDTH))
            c, s = rx_frame.data[0]

            # sign bit
            if c >= 2**(OUTPUT_WIDTH-1):
                c -= 2**OUTPUT_WIDTH
            if s >= 2**(OUTPUT_WIDTH-1):
                s -= 2**OUTPUT_WIDTH

            # reference sine and cosine
            rc = int(np.cos(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))
            rs = int(np.sin(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))

            # assert error of two counts or less
            assert abs(c-rc) <= 2
            assert abs(s-rs) <= 2

        yield clk.posedge
        print("test 2: low frequency")
        current_test.next = 2

        fcw = int(2**PHASE_WIDTH / 10000)
        offset = 0

        test_frame1 = axis_ep.AXIStreamFrame()
        test_frame1.data = [offset]
        test_frame2 = axis_ep.AXIStreamFrame()
        test_frame2.data = [fcw]

        phase_source_queue.put(test_frame1)
        phase_step_source_queue.put(test_frame2)

        yield clk.posedge
        yield clk.posedge

        while not sample_sink_queue.empty():
            sample_sink_queue.get(False)

        yield delay(1000)

        for j in range(6):
            sample_sink_queue.get(False)

        for j in range(100):
            rx_frame = sample_sink_queue.get(False)
            INPUT_WIDTH = OUTPUT_WIDTH+2
            x = int((fcw*j + offset) / 2**(PHASE_WIDTH-INPUT_WIDTH))
            c, s = rx_frame.data[0]

            # sign bit
            if c >= 2**(OUTPUT_WIDTH-1):
                c -= 2**OUTPUT_WIDTH
            if s >= 2**(OUTPUT_WIDTH-1):
                s -= 2**OUTPUT_WIDTH

            # reference sine and cosine
            rc = int(np.cos(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))
            rs = int(np.sin(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))

            # assert error of two counts or less
            assert abs(c-rc) <= 2
            assert abs(s-rs) <= 2

        yield clk.posedge
        print("test 3: phase offset")
        current_test.next = 3

        fcw = int(2**PHASE_WIDTH / 10000)
        offset = 2**(PHASE_WIDTH-2)

        test_frame1 = axis_ep.AXIStreamFrame()
        test_frame1.data = [offset]
        test_frame2 = axis_ep.AXIStreamFrame()
        test_frame2.data = [fcw]

        phase_source_queue.put(test_frame1)
        phase_step_source_queue.put(test_frame2)

        yield clk.posedge
        yield clk.posedge

        while not sample_sink_queue.empty():
            sample_sink_queue.get(False)

        yield delay(1000)

        for j in range(6):
            sample_sink_queue.get(False)

        for j in range(100):
            rx_frame = sample_sink_queue.get(False)
            INPUT_WIDTH = OUTPUT_WIDTH+2
            x = int((fcw*j + offset) / 2**(PHASE_WIDTH-INPUT_WIDTH))
            c, s = rx_frame.data[0]

            # sign bit
            if c >= 2**(OUTPUT_WIDTH-1):
                c -= 2**OUTPUT_WIDTH
            if s >= 2**(OUTPUT_WIDTH-1):
                s -= 2**OUTPUT_WIDTH

            # reference sine and cosine
            rc = int(np.cos(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))
            rs = int(np.sin(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))

            # assert error of two counts or less
            assert abs(c-rc) <= 2
            assert abs(s-rs) <= 2

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_sine_dds.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for sine_dds
 */
module test_sine_dds;

// Parameters
parameter PHASE_WIDTH = 32;
parameter OUTPUT_WIDTH = 16;
parameter INITIAL_PHASE = 0;
parameter INITIAL_PHASE_STEP = 0;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [PHASE_WIDTH-1:0] input_phase_tdata = 0;
reg input_phase_tvalid = 0;
reg [PHASE_WIDTH-1:0] input_phase_step_tdata = 0;
reg input_phase_step_tvalid = 0;
reg output_sample_tready = 0;

// Outputs
wire input_phase_tready;
wire input_phase_step_tready;
wire [OUTPUT_WIDTH-1:0] output_sample_i_tdata;
wire [OUTPUT_WIDTH-1:0] output_sample_q_tdata;
wire output_sample_tvalid;

initial begin
    // myhdl integration
    $from_myhdl(clk,
                rst,
                current_test,
                input_phase_tdata,
                input_phase_tvalid,
                input_phase_step_tdata,
                input_phase_step_tvalid,
                output_sample_tready);
    $to_myhdl(input_phase_tready,
              input_phase_step_tready,
              output_sample_i_tdata,
              output_sample_q_tdata,
              output_sample_tvalid);

    // dump file
    $dumpfile("test_sine_dds.lxt");
    $dumpvars(0, test_sine_dds);
end

sine_dds #(
    .PHASE_WIDTH(PHASE_WIDTH),
    .OUTPUT_WIDTH(OUTPUT_WIDTH),
    .INITIAL_PHASE(INITIAL_PHASE),
    .INITIAL_PHASE_STEP(INITIAL_PHASE_STEP)
)
UUT (
    .clk(clk),
    .rst(rst),
    .input_phase_tdata(input_phase_tdata),
    .input_phase_tvalid(input_phase_tvalid),
    .input_phase_tready(input_phase_tready),
    .input_phase_step_tdata(input_phase_step_tdata),
    .input_phase_step_tvalid(input_phase_step_tvalid),
    .input_phase_step_tready(input_phase_step_tready),
    .output_sample_i_tdata(output_sample_i_tdata),
    .output_sample_q_tdata(output_sample_q_tdata),
    .output_sample_tvalid(output_sample_tvalid),
    .output_sample_tready(output_sample_tready)
);

endmodule


================================================
FILE: tb/test_sine_dds_lut.py
================================================
#!/usr/bin/env python
"""

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

"""

from myhdl import *
import os

try:
    from queue import Queue
except ImportError:
    from Queue import Queue

import numpy as np

import axis_ep

module = 'sine_dds_lut'

srcs = []

srcs.append("../rtl/%s.v" % module)
srcs.append("test_%s.v" % module)

src = ' '.join(srcs)

build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)

def dut_sine_dds_lut(clk,
                     rst,
                     current_test,

                     input_phase_tdata,
                     input_phase_tvalid,
                     input_phase_tready,

                     output_sample_i_tdata,
                     output_sample_q_tdata,
                     output_sample_tvalid,
                     output_sample_tready):

    if os.system(build_cmd):
        raise Exception("Error running build command")
    return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
                clk=clk,
                rst=rst,
                current_test=current_test,

                input_phase_tdata=input_phase_tdata,
                input_phase_tvalid=input_phase_tvalid,
                input_phase_tready=input_phase_tready,

                output_sample_i_tdata=output_sample_i_tdata,
                output_sample_q_tdata=output_sample_q_tdata,
                output_sample_tvalid=output_sample_tvalid,
                output_sample_tready=output_sample_tready)

def bench():

    # Parameters
    OUTPUT_WIDTH = 16
    INPUT_WIDTH = OUTPUT_WIDTH+2

    # Inputs
    clk = Signal(bool(0))
    rst = Signal(bool(0))
    current_test = Signal(intbv(0)[8:])

    input_phase_tdata = Signal(intbv(0)[INPUT_WIDTH:])
    input_phase_tvalid = Signal(bool(0))
    output_sample_tready = Signal(bool(0))

    # Outputs
    input_phase_tready = Signal(bool(0))
    output_sample_i_tdata = Signal(intbv(0)[OUTPUT_WIDTH:])
    output_sample_q_tdata = Signal(intbv(0)[OUTPUT_WIDTH:])
    output_sample_tvalid = Signal(bool(0))

    # sources and sinks
    phase_source_queue = Queue()
    phase_source_pause = Signal(bool(0))
    sample_sink_queue = Queue()
    sample_sink_pause = Signal(bool(0))

    phase_source = axis_ep.AXIStreamSource(clk,
                                           rst,
                                           tdata=input_phase_tdata,
                                           tvalid=input_phase_tvalid,
                                           tready=input_phase_tready,
                                           fifo=phase_source_queue,
                                           pause=phase_source_pause,
                                           name='phase_source')

    sample_sink = axis_ep.AXIStreamSink(clk,
                                        rst,
                                        tdata=(output_sample_i_tdata, output_sample_q_tdata),
                                        tvalid=output_sample_tvalid,
                                        tready=output_sample_tready,
                                        fifo=sample_sink_queue,
                                        pause=sample_sink_pause,
                                        name='sample_sink')

    # DUT
    dut = dut_sine_dds_lut(clk,
                           rst,
                           current_test,

                           input_phase_tdata,
                           input_phase_tvalid,
                           input_phase_tready,

                           output_sample_i_tdata,
                           output_sample_q_tdata,
                           output_sample_tvalid,
                           output_sample_tready)

    @always(delay(4))
    def clkgen():
        clk.next = not clk

    @instance
    def check():
        yield delay(100)
        yield clk.posedge
        rst.next = 1
        yield clk.posedge
        rst.next = 0
        yield clk.posedge
        yield delay(100)
        yield clk.posedge

        # testbench stimulus

        yield clk.posedge
        print("test 1: coarse check")
        current_test.next = 1

        # check single cycle
        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(range(0,2**18,2**10)) + [0]*6

        phase_source_queue.put(test_frame)

        yield clk.posedge
        yield clk.posedge

        while not phase_source_queue.empty() or input_phase_tvalid:
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        # pipeline delay
        for j in range(6):
            sample_sink_queue.get(False)

        for j in range(len(test_frame.data)-6):
            rx_frame = sample_sink_queue.get(False)
            x = test_frame.data[j]
            c, s = rx_frame.data[0]

            # sign bit
            if c >= 2**(OUTPUT_WIDTH-1):
                c -= 2**OUTPUT_WIDTH
            if s >= 2**(OUTPUT_WIDTH-1):
                s -= 2**OUTPUT_WIDTH
            
            # reference sine and cosine
            rc = int(np.cos(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))
            rs = int(np.sin(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))

            # assert error of two counts or less
            assert abs(c-rc) <= 2
            assert abs(s-rs) <= 2

        yield clk.posedge
        print("test 2: fine check")
        current_test.next = 2

        # check two zero crossing regions
        test_frame = axis_ep.AXIStreamFrame()
        test_frame.data = list(range(2**18-2**8,2**18-1)) + list(range(0,2**8)) + list(range(2**16-2**8, 2**16+2**8)) + [0]*6

        phase_source_queue.put(test_frame)

        yield clk.posedge
        yield clk.posedge

        while not phase_source_queue.empty() or input_phase_tvalid:
            yield clk.posedge

        yield clk.posedge
        yield clk.posedge

        # pipeline delay
        for j in range(6):
            sample_sink_queue.get(False)

        for j in range(len(test_frame.data)-6):
            rx_frame = sample_sink_queue.get(False)
            x = test_frame.data[j]
            c, s = rx_frame.data[0]

            # sign bit
            if c >= 2**(OUTPUT_WIDTH-1):
                c -= 2**OUTPUT_WIDTH
            if s >= 2**(OUTPUT_WIDTH-1):
                s -= 2**OUTPUT_WIDTH
            
            # reference sine and cosine
            rc = int(np.cos(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))
            rs = int(np.sin(2*np.pi*(x-2**((INPUT_WIDTH-2)/2-1))/2**INPUT_WIDTH)*(2**(OUTPUT_WIDTH-1)-1))

            # assert error of two counts or less
            assert abs(c-rc) <= 2
            assert abs(s-rs) <= 2

        yield delay(100)

        raise StopSimulation

    return instances()

def test_bench():
    sim = Simulation(bench())
    sim.run()

if __name__ == '__main__':
    print("Running test...")
    test_bench()


================================================
FILE: tb/test_sine_dds_lut.v
================================================
/*

Copyright (c) 2015 Alex Forencich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Testbench for sine_dds_lut
 */
module test_sine_dds_lut;

// Parameters
parameter OUTPUT_WIDTH = 16;
parameter INPUT_WIDTH = OUTPUT_WIDTH+2;

// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;

reg [INPUT_WIDTH-1:0] input_pha
Download .txt
gitextract_6r_l5_gw/

├── .gitignore
├── .travis.yml
├── AUTHORS
├── COPYING
├── README.md
├── rtl/
│   ├── cic_decimator.v
│   ├── cic_interpolator.v
│   ├── dsp_iq_mult.v
│   ├── dsp_mult.v
│   ├── i2s_ctrl.v
│   ├── i2s_rx.v
│   ├── i2s_tx.v
│   ├── iq_join.v
│   ├── iq_split.v
│   ├── phase_accumulator.v
│   ├── sine_dds.v
│   └── sine_dds_lut.v
└── tb/
    ├── axis_ep.py
    ├── i2s_ep.py
    ├── test_cic_decimator.py
    ├── test_cic_decimator.v
    ├── test_cic_interpolator.py
    ├── test_cic_interpolator.v
    ├── test_dsp_iq_mult.py
    ├── test_dsp_iq_mult.v
    ├── test_dsp_mult.py
    ├── test_dsp_mult.v
    ├── test_i2s_ctrl.py
    ├── test_i2s_ctrl.v
    ├── test_i2s_rx.py
    ├── test_i2s_rx.v
    ├── test_i2s_tx.py
    ├── test_i2s_tx.v
    ├── test_iq_join.py
    ├── test_iq_join.v
    ├── test_iq_split.py
    ├── test_iq_split.v
    ├── test_phase_accumulator.py
    ├── test_phase_accumulator.v
    ├── test_sine_dds.py
    ├── test_sine_dds.v
    ├── test_sine_dds_lut.py
    └── test_sine_dds_lut.v
Download .txt
SYMBOL INDEX (66 symbols across 14 files)

FILE: tb/axis_ep.py
  class AXIStreamFrame (line 29) | class AXIStreamFrame(object):
    method __init__ (line 30) | def __init__(self, data=b'', keep=None, id=None, dest=None, user=None,...
    method build (line 82) | def build(self):
    method parse (line 141) | def parse(self, tdata, tkeep, tid, tdest, tuser):
    method __eq__ (line 177) | def __eq__(self, other):
    method __repr__ (line 235) | def __repr__(self):
    method __iter__ (line 245) | def __iter__(self):
  class AXIStreamSource (line 249) | class AXIStreamSource(object):
    method __init__ (line 250) | def __init__(self):
    method send (line 254) | def send(self, frame):
    method write (line 257) | def write(self, data):
    method count (line 260) | def count(self):
    method empty (line 263) | def empty(self):
    method create_logic (line 266) | def create_logic(self,
  class AXIStreamSink (line 372) | class AXIStreamSink(object):
    method __init__ (line 373) | def __init__(self):
    method recv (line 378) | def recv(self):
    method read (line 383) | def read(self, count=-1):
    method count (line 392) | def count(self):
    method empty (line 395) | def empty(self):
    method create_logic (line 398) | def create_logic(self,

FILE: tb/i2s_ep.py
  function I2SControl (line 27) | def I2SControl(clk, rst,
  function I2SSource (line 64) | def I2SSource(clk, rst,
  function I2SSink (line 125) | def I2SSink(clk, rst,

FILE: tb/test_cic_decimator.py
  function dut_cic_decimator (line 50) | def dut_cic_decimator(clk,
  function bench (line 75) | def bench():
  function cic_decimate (line 449) | def cic_decimate(y, N=2, M=1, R=2):
  function contains (line 472) | def contains(small, big):
  function test_bench (line 481) | def test_bench():

FILE: tb/test_cic_interpolator.py
  function dut_cic_interpolator (line 50) | def dut_cic_interpolator(clk,
  function bench (line 75) | def bench():
  function cic_interpolate (line 372) | def cic_interpolate(y, N=2, M=1, R=2):
  function contains (line 394) | def contains(small, big):
  function test_bench (line 403) | def test_bench():

FILE: tb/test_dsp_iq_mult.py
  function dut_dsp_iq_mult (line 47) | def dut_dsp_iq_mult(clk,
  function bench (line 82) | def bench():
  function test_bench (line 211) | def test_bench():

FILE: tb/test_dsp_mult.py
  function dut_dsp_mult (line 47) | def dut_dsp_mult(clk,
  function bench (line 76) | def bench():
  function test_bench (line 199) | def test_bench():

FILE: tb/test_i2s_ctrl.py
  function dut_i2s_ctrl (line 42) | def dut_i2s_ctrl(clk,
  function bench (line 59) | def bench():
  function test_bench (line 148) | def test_bench():

FILE: tb/test_i2s_rx.py
  function dut_i2s_rx (line 48) | def dut_i2s_rx(clk,
  function bench (line 73) | def bench():
  function contains (line 233) | def contains(small, big):
  function test_bench (line 242) | def test_bench():

FILE: tb/test_i2s_tx.py
  function dut_i2s_tx (line 48) | def dut_i2s_tx(clk,
  function bench (line 73) | def bench():
  function contains (line 227) | def contains(small, big):
  function test_bench (line 236) | def test_bench():

FILE: tb/test_iq_join.py
  function dut_iq_join (line 47) | def dut_iq_join(clk,
  function bench (line 78) | def bench():
  function test_bench (line 354) | def test_bench():

FILE: tb/test_iq_split.py
  function dut_iq_split (line 47) | def dut_iq_split(clk,
  function bench (line 78) | def bench():
  function test_bench (line 364) | def test_bench():

FILE: tb/test_phase_accumulator.py
  function dut_phase_accumulator (line 47) | def dut_phase_accumulator(clk,
  function bench (line 82) | def bench():
  function test_bench (line 233) | def test_bench():

FILE: tb/test_sine_dds.py
  function dut_sine_dds (line 51) | def dut_sine_dds(clk,
  function bench (line 88) | def bench():
  function test_bench (line 326) | def test_bench():

FILE: tb/test_sine_dds_lut.py
  function dut_sine_dds_lut (line 49) | def dut_sine_dds_lut(clk,
  function bench (line 78) | def bench():
  function test_bench (line 244) | def test_bench():
Condensed preview — 43 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (205K chars).
[
  {
    "path": ".gitignore",
    "chars": 33,
    "preview": "*~\n*.lxt\n*.pyc\n*.vvp\n*.kate-swp\n\n"
  },
  {
    "path": ".travis.yml",
    "chars": 427,
    "preview": "language: python\npython:\n  - \"3.4\"\nbefore_install:\n  - export d=`pwd`\n  - export PYTHON_EXE=`which python`\n  - sudo apt-"
  },
  {
    "path": "AUTHORS",
    "chars": 40,
    "preview": "Alex Forencich <alex@alexforencich.com>\n"
  },
  {
    "path": "COPYING",
    "chars": 1059,
    "preview": "Copyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this "
  },
  {
    "path": "README.md",
    "chars": 14,
    "preview": "Verilog DSP\n\n\n"
  },
  {
    "path": "rtl/cic_decimator.v",
    "chars": 4819,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/cic_interpolator.v",
    "chars": 4738,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/dsp_iq_mult.v",
    "chars": 4007,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/dsp_mult.v",
    "chars": 3025,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/i2s_ctrl.v",
    "chars": 2258,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/i2s_rx.v",
    "chars": 3292,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/i2s_tx.v",
    "chars": 3137,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/iq_join.v",
    "chars": 2794,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/iq_split.v",
    "chars": 2771,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/phase_accumulator.v",
    "chars": 2683,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/sine_dds.v",
    "chars": 3277,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "rtl/sine_dds_lut.v",
    "chars": 4705,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/axis_ep.py",
    "chars": 17608,
    "preview": "\"\"\"\n\nCopyright (c) 2014-2018 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "tb/i2s_ep.py",
    "chars": 5156,
    "preview": "\"\"\"\n\nCopyright (c) 2014 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "tb/test_cic_decimator.py",
    "chars": 11964,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_cic_decimator.v",
    "chars": 2340,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_cic_interpolator.py",
    "chars": 10467,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_cic_interpolator.v",
    "chars": 2371,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_dsp_iq_mult.py",
    "chars": 7170,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_dsp_iq_mult.v",
    "chars": 2766,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_dsp_mult.py",
    "chars": 6426,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_dsp_mult.v",
    "chars": 2405,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_i2s_ctrl.py",
    "chars": 3891,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_i2s_ctrl.v",
    "chars": 1732,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_i2s_rx.py",
    "chars": 6486,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_i2s_rx.v",
    "chars": 2074,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_i2s_tx.py",
    "chars": 6293,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_i2s_tx.v",
    "chars": 2063,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_iq_join.py",
    "chars": 10789,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_iq_join.v",
    "chars": 2504,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_iq_split.py",
    "chars": 10979,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_iq_split.v",
    "chars": 2517,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_phase_accumulator.py",
    "chars": 7676,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_phase_accumulator.v",
    "chars": 2817,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_sine_dds.py",
    "chars": 10792,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_sine_dds.v",
    "chars": 3026,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  },
  {
    "path": "tb/test_sine_dds_lut.py",
    "chars": 7898,
    "preview": "#!/usr/bin/env python\n\"\"\"\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "tb/test_sine_dds_lut.v",
    "chars": 2519,
    "preview": "/*\n\nCopyright (c) 2015 Alex Forencich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
  }
]

About this extraction

This page contains the full source code of the alexforencich/verilog-dsp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 43 files (191.2 KB), approximately 46.8k tokens, and a symbol index with 66 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!