data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv
None: at end of input
1: b'%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:19: Cannot find include file: test_exec.svh\n  `include "test_exec.svh" \n           ^~~~~~~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen,data/full_repos/permissive/214858095/test_exec.svh\n             data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen,data/full_repos/permissive/214858095/test_exec.svh.v\n             data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen,data/full_repos/permissive/214858095/test_exec.svh.sv\n             test_exec.svh\n             test_exec.svh.v\n             test_exec.svh.sv\n             obj_dir/test_exec.svh\n             obj_dir/test_exec.svh.v\n             obj_dir/test_exec.svh.sv\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:26: Cannot find include file: rfnoc_block_siggen_regs.vh\n  `include "rfnoc_block_siggen_regs.vh" \n           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:21: syntax error, unexpected IDENTIFIER, expecting PACKAGE-IDENTIFIER or STRING\n  import PkgTestExec::*;\n         ^~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:101: syntax error, unexpected \'=\', expecting \',\' or \';\'\n  RfnocBlockCtrlBfm #(CHDR_W, ITEM_W) blk_ctrl = new(backend, m_ctrl, s_ctrl);\n                                               ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:104: syntax error, unexpected \'#\', expecting \'.\' or \';\'\n  typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;\n                   ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:105: syntax error, unexpected \'#\', expecting \'.\' or \';\'\n  typedef ChdrData #(CHDR_W, ITEM_W)::item_t      item_t;\n                   ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:305: syntax error, unexpected IDENTIFIER\n    item_t items[$];\n           ^~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:308: Unsupported: fork statements\n      fork\n      ^~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:312: Unsupported: wait statements\n            wait(!m_rfnoc_chdr_tvalid[port]);\n            ^~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:313: Unsupported: wait statements\n          wait(m_rfnoc_chdr_tvalid[port]);\n          ^~~~\n%Warning-STMTDLY: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:316: Unsupported: Ignoring delay on this delayed statement.\n          #(CHDR_CLK_PER*timeout);\n          ^\n                  ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message.\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:353: Define or directive not defined: \'`ASSERT_ERROR\'\n    `ASSERT_ERROR(value === expected, {err_msg, "initial value"});\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:353: syntax error, unexpected \',\'\n    `ASSERT_ERROR(value === expected, {err_msg, "initial value"});\n                                    ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:359: Define or directive not defined: \'`ASSERT_ERROR\'\n    `ASSERT_ERROR(value === expected, {err_msg, "write max value"});\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:359: syntax error, unexpected \',\'\n    `ASSERT_ERROR(value === expected, {err_msg, "write max value"});\n                                    ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:365: Define or directive not defined: \'`ASSERT_ERROR\'\n    `ASSERT_ERROR(value === expected, {err_msg, "write zero"});\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:365: syntax error, unexpected \',\'\n    `ASSERT_ERROR(value === expected, {err_msg, "write zero"});\n                                    ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:397: syntax error, unexpected IDENTIFIER\n      item_t items[$];\n             ^~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:404: Define or directive not defined: \'`ASSERT_ERROR\'\n      `ASSERT_ERROR(\n      ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:405: syntax error, unexpected \',\'\n        items.size() == spp,\n                           ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:429: Define or directive not defined: \'`ASSERT_ERROR\'\n          `ASSERT_ERROR(\n          ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:430: syntax error, unexpected \',\'\n            actual == expected_const,\n                                    ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:437: Define or directive not defined: \'`ASSERT_ERROR\'\n          `ASSERT_ERROR(\n          ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:438: syntax error, unexpected \',\'\n            samples_are_close(actual, expected_sine),\n                                                    ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:446: Define or directive not defined: \'`ASSERT_ERROR\'\n            `ASSERT_ERROR(items[i] !== items[i-1],\n            ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:446: syntax error, unexpected \',\'\n            `ASSERT_ERROR(items[i] !== items[i-1],\n                                                 ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:475: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(gain <= MAX_GAIN_R   || gain >= MIN_GAIN_R,  "Gain out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:475: syntax error, unexpected \',\'\n    `ASSERT_FATAL(gain <= MAX_GAIN_R   || gain >= MIN_GAIN_R,  "Gain out of range");\n                                                            ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:476: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(re   <= MAX_CONST_R  || re   >= MIN_CONST_R, "Real out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:476: syntax error, unexpected \',\'\n    `ASSERT_FATAL(re   <= MAX_CONST_R  || re   >= MIN_CONST_R, "Real out of range");\n                                                             ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:477: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(im   <= MAX_CONST_R  || im   >= MIN_CONST_R, "Imag out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:477: syntax error, unexpected \',\'\n    `ASSERT_FATAL(im   <= MAX_CONST_R  || im   >= MIN_CONST_R, "Imag out of range");\n                                                             ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:511: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(gain  <= MAX_GAIN_R  || gain  >= MIN_GAIN_R,  "Gain out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:511: syntax error, unexpected \',\'\n    `ASSERT_FATAL(gain  <= MAX_GAIN_R  || gain  >= MIN_GAIN_R,  "Gain out of range");\n                                                             ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:512: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(x     <= MAX_CART_R  || x     >= MIN_CART_R,  "X out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:512: syntax error, unexpected \',\'\n    `ASSERT_FATAL(x     <= MAX_CART_R  || x     >= MIN_CART_R,  "X out of range");\n                                                             ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:513: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(y     <= MAX_CART_R  || y     >= MIN_CART_R,  "Y out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:513: syntax error, unexpected \',\'\n    `ASSERT_FATAL(y     <= MAX_CART_R  || y     >= MIN_CART_R,  "Y out of range");\n                                                             ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:514: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(phase <= MAX_PHASE_R || phase >= MIN_PHASE_R, "Phase out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:514: syntax error, unexpected \',\'\n    `ASSERT_FATAL(phase <= MAX_PHASE_R || phase >= MIN_PHASE_R, "Phase out of range");\n                                                              ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:547: Define or directive not defined: \'`ASSERT_FATAL\'\n    `ASSERT_FATAL(gain <= MAX_GAIN_R || gain >= MIN_GAIN_R, "Gain out of range");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:547: syntax error, unexpected \',\'\n    `ASSERT_FATAL(gain <= MAX_GAIN_R || gain >= MIN_GAIN_R, "Gain out of range");\n                                                          ^\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:569: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test($sformatf("Test registers (port %0d)", port), 1ms);\n                                                                  ^~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:582: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test($sformatf("Test waveforms (port %0d)", port), 1ms);\n                                                                  ^~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:597: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test($sformatf("Test gain (port %0d)", port), 1ms);\n                                                             ^~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:625: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test($sformatf("Test phase (port %0d)", port), 1ms);\n                                                              ^~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:638: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test($sformatf("Test packet length (port %0d)", port), 1ms);\n                                                                      ^~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:672: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test("Flush block then reset it", 10us);\n                                                 ^~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:680: syntax error, unexpected TIME NUMBER, expecting \')\'\n    test.start_test("Verify Block Info", 2us);\n                                         ^~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:681: Define or directive not defined: \'`ASSERT_ERROR\'\n    `ASSERT_ERROR(blk_ctrl.get_noc_id() == NOC_ID, "Incorrect NOC_ID Value");\n    ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/214858095/FPGA_Exploration/spartan6/B205mini/ISE_Project/lib/rfnoc/blocks/rfnoc_block_siggen/rfnoc_block_siggen_tb.sv:681: syntax error, unexpected \',\'\n    `ASSERT_ERROR(blk_ctrl.get_noc_id() == NOC_ID, "Incorrect NOC_ID Value");\n                                                 ^\n%Error: Exiting due to too many errors encountered; --error-limit=50\n'
module rfnoc_block_siggen_tb #(
  parameter CHDR_W    = 64,
  parameter NUM_PORTS = 1
);

  `include "test_exec.svh"

  import PkgTestExec::*;
  import PkgChdrUtils::*;
  import PkgRfnocBlockCtrlBfm::*;
  import PkgRfnocItemUtils::*;

  `include "rfnoc_block_siggen_regs.vh"






  localparam [31:0] NOC_ID          = 32'h51663110;
  localparam [ 9:0] THIS_PORTID     = 10'h123;
  localparam int    MTU             = 10;
  localparam int    NUM_PORTS_I     = 1;
  localparam int    NUM_PORTS_O     = 0+NUM_PORTS;
  localparam int    ITEM_W          = 32;
  localparam int    SPP             = 64;
  localparam int    PKT_SIZE_BYTES  = SPP * (ITEM_W/8);
  localparam int    STALL_PROB      = 25;
  localparam real   CHDR_CLK_PER    = 5.0;
  localparam real   CTRL_CLK_PER    = 8.0;
  localparam real   CE_CLK_PER      = 4.0;

  localparam real PI = 2*$acos(0);



  localparam int GAIN_FRAC  = 15;
  localparam int CONST_FRAC = 15;
  localparam int PHASE_FRAC = 13;
  localparam int CART_FRAC  = 14;




  localparam real MAX_GAIN_R  =  (2.0**15-1) / (2.0**GAIN_FRAC);
  localparam real MIN_GAIN_R  = -(2.0**15)   / (2.0**GAIN_FRAC);
  localparam real MAX_CONST_R =  (2.0**15-1) / (2.0**CONST_FRAC);
  localparam real MIN_CONST_R = -(2.0**15)   / (2.0**CONST_FRAC);
  localparam real MAX_CART_R  =  (2.0**15-1) / (2.0**CART_FRAC);
  localparam real MIN_CART_R  = -(2.0**15)   / (2.0**CART_FRAC);

  localparam real MAX_PHASE_R = +1.0;
  localparam real MIN_PHASE_R = -1.0;






  bit rfnoc_chdr_clk;
  bit rfnoc_ctrl_clk;
  bit ce_clk;

  sim_clock_gen #(.PERIOD(CHDR_CLK_PER), .AUTOSTART(0))
   rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst());
  sim_clock_gen #(.PERIOD(CTRL_CLK_PER), .AUTOSTART(0))
   rfnoc_ctrl_clk_gen (.clk(rfnoc_ctrl_clk), .rst());
  sim_clock_gen #(.PERIOD(CE_CLK_PER), .AUTOSTART(0))
     ce_clk_gen (.clk(ce_clk), .rst());







  RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);


  AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
  AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);


  AxiStreamIf #(CHDR_W) m_chdr [NUM_PORTS_I] (rfnoc_chdr_clk, 1'b0);
  AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS_O] (rfnoc_chdr_clk, 1'b0);


  RfnocBlockCtrlBfm #(CHDR_W, ITEM_W) blk_ctrl = new(backend, m_ctrl, s_ctrl);


  typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
  typedef ChdrData #(CHDR_W, ITEM_W)::item_t      item_t;


  for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_bfm_input_connections
    initial begin
      blk_ctrl.connect_master_data_port(i, m_chdr[i], PKT_SIZE_BYTES);
      blk_ctrl.set_master_stall_prob(i, STALL_PROB);
    end
  end
  for (genvar i = 0; i < NUM_PORTS_O; i++) begin : gen_bfm_output_connections
    initial begin
      blk_ctrl.connect_slave_data_port(i, s_chdr[i]);
      blk_ctrl.set_slave_stall_prob(i, STALL_PROB);
    end
  end







  logic [CHDR_W*NUM_PORTS_I-1:0] s_rfnoc_chdr_tdata;
  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tlast;
  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tvalid;
  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tready;


  logic [CHDR_W*NUM_PORTS_O-1:0] m_rfnoc_chdr_tdata;
  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tlast;
  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tvalid;
  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tready;


  for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_dut_input_connections

    assign s_rfnoc_chdr_tdata[CHDR_W*i+:CHDR_W] = m_chdr[i].tdata;
    assign s_rfnoc_chdr_tlast[i]                = m_chdr[i].tlast;
    assign s_rfnoc_chdr_tvalid[i]               = m_chdr[i].tvalid;
    assign m_chdr[i].tready                     = s_rfnoc_chdr_tready[i];
  end
  for (genvar i = 0; i < NUM_PORTS_O; i++) begin : gen_dut_output_connections

    assign s_chdr[i].tdata        = m_rfnoc_chdr_tdata[CHDR_W*i+:CHDR_W];
    assign s_chdr[i].tlast        = m_rfnoc_chdr_tlast[i];
    assign s_chdr[i].tvalid       = m_rfnoc_chdr_tvalid[i];
    assign m_rfnoc_chdr_tready[i] = s_chdr[i].tready;
  end

  rfnoc_block_siggen #(
    .THIS_PORTID         (THIS_PORTID),
    .CHDR_W              (CHDR_W),
    .MTU                 (MTU),
    .NUM_PORTS           (NUM_PORTS)
  ) dut (
    .rfnoc_chdr_clk      (rfnoc_chdr_clk),
    .rfnoc_ctrl_clk      (rfnoc_ctrl_clk),
    .ce_clk              (ce_clk),
    .rfnoc_core_config   (backend.cfg),
    .rfnoc_core_status   (backend.sts),
    .s_rfnoc_chdr_tdata  (s_rfnoc_chdr_tdata),
    .s_rfnoc_chdr_tlast  (s_rfnoc_chdr_tlast),
    .s_rfnoc_chdr_tvalid (s_rfnoc_chdr_tvalid),
    .s_rfnoc_chdr_tready (s_rfnoc_chdr_tready),
    .m_rfnoc_chdr_tdata  (m_rfnoc_chdr_tdata),
    .m_rfnoc_chdr_tlast  (m_rfnoc_chdr_tlast),
    .m_rfnoc_chdr_tvalid (m_rfnoc_chdr_tvalid),
    .m_rfnoc_chdr_tready (m_rfnoc_chdr_tready),
    .s_rfnoc_ctrl_tdata  (m_ctrl.tdata),
    .s_rfnoc_ctrl_tlast  (m_ctrl.tlast),
    .s_rfnoc_ctrl_tvalid (m_ctrl.tvalid),
    .s_rfnoc_ctrl_tready (m_ctrl.tready),
    .m_rfnoc_ctrl_tdata  (s_ctrl.tdata),
    .m_rfnoc_ctrl_tlast  (s_ctrl.tlast),
    .m_rfnoc_ctrl_tvalid (s_ctrl.tvalid),
    .m_rfnoc_ctrl_tready (s_ctrl.tready)
  );







  task automatic write_reg(int port, bit [19:0] addr, bit [31:0] value);
    blk_ctrl.reg_write(port * (2**SIGGEN_ADDR_W) + addr, value);
  endtask : write_reg


  task automatic read_reg(int port, bit [19:0] addr, output logic [31:0] value);
    blk_ctrl.reg_read(port * (2**SIGGEN_ADDR_W) + addr, value);
  endtask : read_reg




  function bit samples_are_close(
    logic [31:0] samp_a, samp_b,
    real         threshold = 3.0
  );
    real ax, ay, bx, by;
    real distance;


    ax = signed'(samp_a[31:16]);
    ay = signed'(samp_a[15: 0]);
    bx = signed'(samp_b[31:16]);
    by = signed'(samp_b[15: 0]);

    distance = $sqrt( (ax-bx)*(ax-bx) + (ay-by)*(ay-by) );

    return distance <= threshold;
  endfunction : samples_are_close



  function automatic logic [15:0] real_to_fixed(real value, int frac = 15);

    value = value * 2.0**frac;


    value = $floor(value + 0.5);


    if (value > 16'sh7FFF) value = 16'sh7FFF;
    if (value < 16'sh8000) value = 16'sh8000;
    return int'(value);
  endfunction : real_to_fixed




  function automatic real fixed_to_real(
    logic signed [15:0] value,
    int                 frac = 15
  );
    return real'(value) / (2.0 ** frac);
  endfunction : fixed_to_real





  function automatic logic [31:0] next_sine_value(
    logic [31:0] sample,
    logic [15:0] phase_inc
  );
    real x, y, phase, new_x, new_y;
    x        = fixed_to_real(sample[31:16], CART_FRAC);
    y        = fixed_to_real(sample[15: 0], CART_FRAC);
    phase    = fixed_to_real(phase_inc, PHASE_FRAC) * PI;


    new_x = x*$cos(phase) - y*$sin(phase);
    new_y = x*$sin(phase) + y*$cos(phase);

    return { real_to_fixed(new_x, CART_FRAC), real_to_fixed(new_y, CART_FRAC) };
  endfunction : next_sine_value




  function automatic logic [15:0] apply_gain(
    logic signed [15:0] gain,
    logic signed [15:0] value
  );
    logic signed [31:0] result;
    bit round;


    result = gain * value;








    if (result[31:15] != 17'h0FFFF) begin
      round = result[14];
    end else begin
      round = 0;
    end
    result = result >>> 15;
    result = result + round;


    if (result < 16'sh8000) begin
      result = 16'sh8000;
    end else if (result > 16'sh7FFF) begin
      result = 16'sh7FFF;
    end

    return result[15:0];
  endfunction : apply_gain



  task automatic flush_output(int port, timeout = 100);
    item_t items[$];

    forever begin
      fork
        begin : wait_for_data_fork

          if (m_rfnoc_chdr_tvalid[port])
            wait(!m_rfnoc_chdr_tvalid[port]);
          wait(m_rfnoc_chdr_tvalid[port]);
        end
        begin : wait_for_timeout_fork
          #(CHDR_CLK_PER*timeout);
        end
      join_any


      if (!m_rfnoc_chdr_tvalid[port]) break;
    end


    while (blk_ctrl.num_received(port)) begin
      blk_ctrl.recv_items(port, items);
    end
  endtask : flush_output









  task automatic test_read_write_reg(
    int          port,
    bit   [19:0] addr,
    bit   [31:0] mask = 32'hFFFFFFFF,
    logic [31:0] initial_value = '0
  );
    string       err_msg;
    logic [31:0] value;
    logic [31:0] expected;

    err_msg = $sformatf("Register 0x%X failed read/write test: ", addr);


    expected = initial_value;
    read_reg(port, addr, value);
    `ASSERT_ERROR(value === expected, {err_msg, "initial value"});


    expected = (initial_value & ~mask) | mask;
    write_reg(port, addr, '1);
    read_reg(port, addr, value);
    `ASSERT_ERROR(value === expected, {err_msg, "write max value"});


    expected = (initial_value & ~mask);
    write_reg(port, addr, '0);
    read_reg(port, addr, value);
    `ASSERT_ERROR(value === expected, {err_msg, "write zero"});


    write_reg(port, addr, initial_value);
  endtask : test_read_write_reg



  task automatic run_waveform(
    int                 port,
    logic signed [15:0] gain        = 16'h7FFF,
    logic         [2:0] mode        = WAVE_CONST,
    int                 num_packets = 1,
    int                 spp         = SPP,
    logic signed [15:0] const_re    = 16'h7FFF,
    logic signed [15:0] const_im    = 16'h7FFF,
    logic signed [15:0] phase_inc   = real_to_fixed(2.0/16, 13),
    logic signed [15:0] cart_x      = real_to_fixed(1.0, 14),
    logic signed [15:0] cart_y      = real_to_fixed(0.0, 14)
  );
    write_reg(port, REG_SPP, spp);
    write_reg(port, REG_WAVEFORM, mode);
    write_reg(port, REG_GAIN, gain);
    if (mode == WAVE_CONST) begin
      write_reg(port, REG_CONSTANT, {const_re, const_im});
    end else if (mode == WAVE_SINE) begin
      write_reg(port, REG_PHASE_INC, phase_inc);
      write_reg(port, REG_CARTESIAN, {cart_x, cart_y});
    end
    write_reg(port, REG_ENABLE, 1);

    for (int packet_count = 0; packet_count < num_packets; packet_count++) begin
      item_t items[$];
      item_t expected_const, expected_sine, actual;


      blk_ctrl.recv_items(port, items);


      `ASSERT_ERROR(
        items.size() == spp,
        "Packet length didn't match configured SPP"
      );


      foreach (items[i]) begin
        actual = items[i];


        expected_const[31:16] = apply_gain(gain, const_re);
        expected_const[15: 0] = apply_gain(gain, const_im);


        if (i == 0) begin


          expected_sine = actual;
        end else begin
          expected_sine = next_sine_value(items[i-1], phase_inc);
        end


        if (mode == WAVE_CONST) begin

          `ASSERT_ERROR(
            actual == expected_const,
            $sformatf("Incorrect constant sample on packet %0d. Expected 0x%X, received 0x%X.",
              packet_count, expected_const, actual)
          );
        end else if (mode == WAVE_SINE) begin


          `ASSERT_ERROR(
            samples_are_close(actual, expected_sine),
            $sformatf("Incorrect sine sample on packet %0d. Expected 0x%X, received 0x%X.",
              packet_count, expected_sine, actual)
          );
        end else if (mode == WAVE_NOISE) begin
          if (i != 0) begin


            `ASSERT_ERROR(items[i] !== items[i-1],
              $sformatf("Noise output didn't update on packet %0d.Received 0x%X.",
                packet_count, actual)
            );
          end
        end

      end
    end


    write_reg(port, REG_ENABLE, 0);
    flush_output(port);
  endtask : run_waveform




  task automatic run_const(
    int  port,
    int  num_packets = 50,
    int  spp         = SPP,
    real gain,
    real re,
    real im
  );
    logic signed [15:0] fgain, fre, fim;


    `ASSERT_FATAL(gain <= MAX_GAIN_R   || gain >= MIN_GAIN_R,  "Gain out of range");
    `ASSERT_FATAL(re   <= MAX_CONST_R  || re   >= MIN_CONST_R, "Real out of range");
    `ASSERT_FATAL(im   <= MAX_CONST_R  || im   >= MIN_CONST_R, "Imag out of range");


    fgain  = real_to_fixed(gain, GAIN_FRAC);
    fre    = real_to_fixed(re, CONST_FRAC);
    fim    = real_to_fixed(im, CONST_FRAC);


    run_waveform(
      .port(port),
      .gain(fgain),
      .mode(WAVE_CONST),
      .num_packets(num_packets),
      .spp(spp),
      .const_re(fre),
      .const_im(fim)
    );
  endtask : run_const




  task automatic run_sine(
    int  port,
    int  num_packets = 50,
    int  spp         = SPP,
    real gain,
    real x,
    real y,
    real phase
  );
    logic signed [15:0] fgain, fx, fy, fphase;


    `ASSERT_FATAL(gain  <= MAX_GAIN_R  || gain  >= MIN_GAIN_R,  "Gain out of range");
    `ASSERT_FATAL(x     <= MAX_CART_R  || x     >= MIN_CART_R,  "X out of range");
    `ASSERT_FATAL(y     <= MAX_CART_R  || y     >= MIN_CART_R,  "Y out of range");
    `ASSERT_FATAL(phase <= MAX_PHASE_R || phase >= MIN_PHASE_R, "Phase out of range");


    fgain  = real_to_fixed(gain, GAIN_FRAC);
    fx     = real_to_fixed(x, CART_FRAC);
    fy     = real_to_fixed(y, CART_FRAC);
    fphase = real_to_fixed(phase, PHASE_FRAC);


    run_waveform(
      .port(port),
      .gain(fgain),
      .mode(WAVE_SINE),
      .num_packets(num_packets),
      .spp(spp),
      .cart_x(fx),
      .cart_y(fy),
      .phase_inc(fphase)
    );
  endtask : run_sine




  task automatic run_noise(
    int  port,
    int  num_packets = 50,
    int  spp         = SPP,
    real gain
  );
    logic signed [15:0] fgain;


    `ASSERT_FATAL(gain <= MAX_GAIN_R || gain >= MIN_GAIN_R, "Gain out of range");


    fgain = real_to_fixed(gain, GAIN_FRAC);


    run_waveform(
      .port(port),
      .gain(fgain),
      .mode(WAVE_NOISE),
      .num_packets(num_packets),
      .spp(spp)
    );
  endtask : run_noise







  task automatic test_registers(int port);
    test.start_test($sformatf("Test registers (port %0d)", port), 1ms);

    test_read_write_reg(port, REG_SPP,       {REG_SPP_LEN{1'b1}},       32'd16);
    test_read_write_reg(port, REG_GAIN,      {REG_GAIN_LEN{1'b1}},      32'h7FFF);
    test_read_write_reg(port, REG_CONSTANT,  {REG_CONSTANT_LEN{1'b1}},  32'h0);
    test_read_write_reg(port, REG_PHASE_INC, {REG_PHASE_INC_LEN{1'b1}}, {REG_PHASE_INC_LEN{1'bX}});
    test_read_write_reg(port, REG_CARTESIAN, {REG_CARTESIAN_LEN{1'b1}}, {REG_CARTESIAN_LEN{1'bX}});
    test.end_test();
  endtask : test_registers



  task automatic test_waveforms(int port);
    test.start_test($sformatf("Test waveforms (port %0d)", port), 1ms);
    run_const(.port(port), .gain(0.5), .re(0.25), .im(0.5));
    run_sine(.port(port), .gain(0.75), .x(0.25), .y(0.5), .phase(2.0/64));
    run_noise(.port(port), .gain(0.999));
    test.end_test();
  endtask : test_waveforms





  task automatic test_gain(int port);
    logic signed [15:0] min_val;
    logic signed [15:0] max_val;

    test.start_test($sformatf("Test gain (port %0d)", port), 1ms);

    max_val = 16'sh7FFF;
    min_val = 16'sh8000;


    run_waveform(.port(port), .mode(WAVE_CONST), .gain(max_val),
      .const_re(max_val), .const_im(min_val));

    run_waveform(.port(port), .mode(WAVE_CONST), .gain(min_val),
      .const_re(min_val), .const_im(max_val));

    run_waveform(.port(port), .mode(WAVE_CONST), .gain(0),
      .const_re(max_val), .const_im(min_val));

    run_waveform(
      .port(port),
      .mode(WAVE_CONST),
      .const_re(real_to_fixed(0.5, CONST_FRAC)),
      .const_im(real_to_fixed(0.25, CONST_FRAC)),
      .gain(real_to_fixed(0.5, GAIN_FRAC))
      );
    test.end_test();
  endtask : test_gain



  task automatic test_phase(int port);
    test.start_test($sformatf("Test phase (port %0d)", port), 1ms);

    run_sine(.port(port), .gain(0.5), .x(1.0), .y(0.0), .phase(2.0/16), .num_packets(2));

    run_sine(.port(port), .gain(0.5), .x(1.0), .y(0.0), .phase(MAX_PHASE_R), .num_packets(2));

    run_sine(.port(port), .gain(0.5), .x(1.0), .y(0.0), .phase(MIN_PHASE_R), .num_packets(2));
    test.end_test();
  endtask : test_phase



  task automatic test_packet_length(int port);
    test.start_test($sformatf("Test packet length (port %0d)", port), 1ms);
    run_waveform(.port(port), .spp(2));
    run_waveform(.port(port), .spp(SPP));
    run_waveform(.port(port), .spp((2**MTU-1) * (CHDR_W / ITEM_W)));
    test.end_test();
  endtask : test_packet_length






  initial begin : tb_main
    int port;


    test.start_tb(
      $sformatf("rfnoc_block_siggen_tb (CHDR_W = %0d, NUM_PORTS = %0d)",
      CHDR_W, NUM_PORTS));




    rfnoc_chdr_clk_gen.start();
    rfnoc_ctrl_clk_gen.start();
    ce_clk_gen.start();


    blk_ctrl.run();





    test.start_test("Flush block then reset it", 10us);
    blk_ctrl.flush_and_reset();
    test.end_test();





    test.start_test("Verify Block Info", 2us);
    `ASSERT_ERROR(blk_ctrl.get_noc_id() == NOC_ID, "Incorrect NOC_ID Value");
    `ASSERT_ERROR(blk_ctrl.get_num_data_i() == NUM_PORTS_I, "Incorrect NUM_DATA_I Value");
    `ASSERT_ERROR(blk_ctrl.get_num_data_o() == NUM_PORTS_O, "Incorrect NUM_DATA_O Value");
    `ASSERT_ERROR(blk_ctrl.get_mtu() == MTU, "Incorrect MTU Value");
    test.end_test();






    for(port = 0; port < NUM_PORTS; port++) begin
      test_registers(port);
      test_waveforms(port);
    end


    port = 0;
    test_gain(port);
    test_packet_length(port);
    test_phase(port);








    test.end_tb(0);


    rfnoc_chdr_clk_gen.kill();
    rfnoc_ctrl_clk_gen.kill();
    ce_clk_gen.kill();
  end : tb_main

endmodule
module rfnoc_block_siggen_tb #(
  parameter CHDR_W    = 64,
  parameter NUM_PORTS = 1
);


  `include "test_exec.svh"

  import PkgTestExec::*;
  import PkgChdrUtils::*;
  import PkgRfnocBlockCtrlBfm::*;
  import PkgRfnocItemUtils::*;

  `include "rfnoc_block_siggen_regs.vh"






  localparam [31:0] NOC_ID          = 32'h51663110;
  localparam [ 9:0] THIS_PORTID     = 10'h123;
  localparam int    MTU             = 10;
  localparam int    NUM_PORTS_I     = 1;
  localparam int    NUM_PORTS_O     = 0+NUM_PORTS;
  localparam int    ITEM_W          = 32;
  localparam int    SPP             = 64;
  localparam int    PKT_SIZE_BYTES  = SPP * (ITEM_W/8);
  localparam int    STALL_PROB      = 25;
  localparam real   CHDR_CLK_PER    = 5.0;
  localparam real   CTRL_CLK_PER    = 8.0;
  localparam real   CE_CLK_PER      = 4.0;

  localparam real PI = 2*$acos(0);



  localparam int GAIN_FRAC  = 15;
  localparam int CONST_FRAC = 15;
  localparam int PHASE_FRAC = 13;
  localparam int CART_FRAC  = 14;




  localparam real MAX_GAIN_R  =  (2.0**15-1) / (2.0**GAIN_FRAC);
  localparam real MIN_GAIN_R  = -(2.0**15)   / (2.0**GAIN_FRAC);
  localparam real MAX_CONST_R =  (2.0**15-1) / (2.0**CONST_FRAC);
  localparam real MIN_CONST_R = -(2.0**15)   / (2.0**CONST_FRAC);
  localparam real MAX_CART_R  =  (2.0**15-1) / (2.0**CART_FRAC);
  localparam real MIN_CART_R  = -(2.0**15)   / (2.0**CART_FRAC);

  localparam real MAX_PHASE_R = +1.0;
  localparam real MIN_PHASE_R = -1.0;






  bit rfnoc_chdr_clk;
  bit rfnoc_ctrl_clk;
  bit ce_clk;

  sim_clock_gen #(.PERIOD(CHDR_CLK_PER), .AUTOSTART(0))
   rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst());
  sim_clock_gen #(.PERIOD(CTRL_CLK_PER), .AUTOSTART(0))
   rfnoc_ctrl_clk_gen (.clk(rfnoc_ctrl_clk), .rst());
  sim_clock_gen #(.PERIOD(CE_CLK_PER), .AUTOSTART(0))
     ce_clk_gen (.clk(ce_clk), .rst());







  RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);


  AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
  AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);


  AxiStreamIf #(CHDR_W) m_chdr [NUM_PORTS_I] (rfnoc_chdr_clk, 1'b0);
  AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS_O] (rfnoc_chdr_clk, 1'b0);


  RfnocBlockCtrlBfm #(CHDR_W, ITEM_W) blk_ctrl = new(backend, m_ctrl, s_ctrl);


  typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
  typedef ChdrData #(CHDR_W, ITEM_W)::item_t      item_t;


  for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_bfm_input_connections
    initial begin
      blk_ctrl.connect_master_data_port(i, m_chdr[i], PKT_SIZE_BYTES);
      blk_ctrl.set_master_stall_prob(i, STALL_PROB);
    end
  end
  for (genvar i = 0; i < NUM_PORTS_O; i++) begin : gen_bfm_output_connections
    initial begin
      blk_ctrl.connect_slave_data_port(i, s_chdr[i]);
      blk_ctrl.set_slave_stall_prob(i, STALL_PROB);
    end
  end







  logic [CHDR_W*NUM_PORTS_I-1:0] s_rfnoc_chdr_tdata;
  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tlast;
  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tvalid;
  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tready;


  logic [CHDR_W*NUM_PORTS_O-1:0] m_rfnoc_chdr_tdata;
  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tlast;
  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tvalid;
  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tready;


  for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_dut_input_connections

    assign s_rfnoc_chdr_tdata[CHDR_W*i+:CHDR_W] = m_chdr[i].tdata;
    assign s_rfnoc_chdr_tlast[i]                = m_chdr[i].tlast;
    assign s_rfnoc_chdr_tvalid[i]               = m_chdr[i].tvalid;
    assign m_chdr[i].tready                     = s_rfnoc_chdr_tready[i];
  end
  for (genvar i = 0; i < NUM_PORTS_O; i++) begin : gen_dut_output_connections

    assign s_chdr[i].tdata        = m_rfnoc_chdr_tdata[CHDR_W*i+:CHDR_W];
    assign s_chdr[i].tlast        = m_rfnoc_chdr_tlast[i];
    assign s_chdr[i].tvalid       = m_rfnoc_chdr_tvalid[i];
    assign m_rfnoc_chdr_tready[i] = s_chdr[i].tready;
  end

  rfnoc_block_siggen #(
    .THIS_PORTID         (THIS_PORTID),
    .CHDR_W              (CHDR_W),
    .MTU                 (MTU),
    .NUM_PORTS           (NUM_PORTS)
  ) dut (
    .rfnoc_chdr_clk      (rfnoc_chdr_clk),
    .rfnoc_ctrl_clk      (rfnoc_ctrl_clk),
    .ce_clk              (ce_clk),
    .rfnoc_core_config   (backend.cfg),
    .rfnoc_core_status   (backend.sts),
    .s_rfnoc_chdr_tdata  (s_rfnoc_chdr_tdata),
    .s_rfnoc_chdr_tlast  (s_rfnoc_chdr_tlast),
    .s_rfnoc_chdr_tvalid (s_rfnoc_chdr_tvalid),
    .s_rfnoc_chdr_tready (s_rfnoc_chdr_tready),
    .m_rfnoc_chdr_tdata  (m_rfnoc_chdr_tdata),
    .m_rfnoc_chdr_tlast  (m_rfnoc_chdr_tlast),
    .m_rfnoc_chdr_tvalid (m_rfnoc_chdr_tvalid),
    .m_rfnoc_chdr_tready (m_rfnoc_chdr_tready),
    .s_rfnoc_ctrl_tdata  (m_ctrl.tdata),
    .s_rfnoc_ctrl_tlast  (m_ctrl.tlast),
    .s_rfnoc_ctrl_tvalid (m_ctrl.tvalid),
    .s_rfnoc_ctrl_tready (m_ctrl.tready),
    .m_rfnoc_ctrl_tdata  (s_ctrl.tdata),
    .m_rfnoc_ctrl_tlast  (s_ctrl.tlast),
    .m_rfnoc_ctrl_tvalid (s_ctrl.tvalid),
    .m_rfnoc_ctrl_tready (s_ctrl.tready)
  );







  task automatic write_reg(int port, bit [19:0] addr, bit [31:0] value);
    blk_ctrl.reg_write(port * (2**SIGGEN_ADDR_W) + addr, value);
  endtask : write_reg


  task automatic read_reg(int port, bit [19:0] addr, output logic [31:0] value);
    blk_ctrl.reg_read(port * (2**SIGGEN_ADDR_W) + addr, value);
  endtask : read_reg




  function bit samples_are_close(
    logic [31:0] samp_a, samp_b,
    real         threshold = 3.0
  );
    real ax, ay, bx, by;
    real distance;


    ax = signed'(samp_a[31:16]);
    ay = signed'(samp_a[15: 0]);
    bx = signed'(samp_b[31:16]);
    by = signed'(samp_b[15: 0]);

    distance = $sqrt( (ax-bx)*(ax-bx) + (ay-by)*(ay-by) );

    return distance <= threshold;
  endfunction : samples_are_close



  function automatic logic [15:0] real_to_fixed(real value, int frac = 15);

    value = value * 2.0**frac;


    value = $floor(value + 0.5);


    if (value > 16'sh7FFF) value = 16'sh7FFF;
    if (value < 16'sh8000) value = 16'sh8000;
    return int'(value);
  endfunction : real_to_fixed




  function automatic real fixed_to_real(
    logic signed [15:0] value,
    int                 frac = 15
  );
    return real'(value) / (2.0 ** frac);
  endfunction : fixed_to_real





  function automatic logic [31:0] next_sine_value(
    logic [31:0] sample,
    logic [15:0] phase_inc
  );
    real x, y, phase, new_x, new_y;
    x        = fixed_to_real(sample[31:16], CART_FRAC);
    y        = fixed_to_real(sample[15: 0], CART_FRAC);
    phase    = fixed_to_real(phase_inc, PHASE_FRAC) * PI;


    new_x = x*$cos(phase) - y*$sin(phase);
    new_y = x*$sin(phase) + y*$cos(phase);

    return { real_to_fixed(new_x, CART_FRAC), real_to_fixed(new_y, CART_FRAC) };
  endfunction : next_sine_value




  function automatic logic [15:0] apply_gain(
    logic signed [15:0] gain,
    logic signed [15:0] value
  );
    logic signed [31:0] result;
    bit round;


    result = gain * value;








    if (result[31:15] != 17'h0FFFF) begin
      round = result[14];
    end else begin
      round = 0;
    end
    result = result >>> 15;
    result = result + round;


    if (result < 16'sh8000) begin
      result = 16'sh8000;
    end else if (result > 16'sh7FFF) begin
      result = 16'sh7FFF;
    end

    return result[15:0];
  endfunction : apply_gain



  task automatic flush_output(int port, timeout = 100);
    item_t items[$];

    forever begin
      fork
        begin : wait_for_data_fork

          if (m_rfnoc_chdr_tvalid[port])
            wait(!m_rfnoc_chdr_tvalid[port]);
          wait(m_rfnoc_chdr_tvalid[port]);
        end
        begin : wait_for_timeout_fork
          #(CHDR_CLK_PER*timeout);
        end
      join_any


      if (!m_rfnoc_chdr_tvalid[port]) break;
    end


    while (blk_ctrl.num_received(port)) begin
      blk_ctrl.recv_items(port, items);
    end
  endtask : flush_output









  task automatic test_read_write_reg(
    int          port,
    bit   [19:0] addr,
    bit   [31:0] mask = 32'hFFFFFFFF,
    logic [31:0] initial_value = '0
  );
    string       err_msg;
    logic [31:0] value;
    logic [31:0] expected;

    err_msg = $sformatf("Register 0x%X failed read/write test: ", addr);


    expected = initial_value;
    read_reg(port, addr, value);
    `ASSERT_ERROR(value === expected, {err_msg, "initial value"});


    expected = (initial_value & ~mask) | mask;
    write_reg(port, addr, '1);
    read_reg(port, addr, value);
    `ASSERT_ERROR(value === expected, {err_msg, "write max value"});


    expected = (initial_value & ~mask);
    write_reg(port, addr, '0);
    read_reg(port, addr, value);
    `ASSERT_ERROR(value === expected, {err_msg, "write zero"});


    write_reg(port, addr, initial_value);
  endtask : test_read_write_reg



  task automatic run_waveform(
    int                 port,
    logic signed [15:0] gain        = 16'h7FFF,
    logic         [2:0] mode        = WAVE_CONST,
    int                 num_packets = 1,
    int                 spp         = SPP,
    logic signed [15:0] const_re    = 16'h7FFF,
    logic signed [15:0] const_im    = 16'h7FFF,
    logic signed [15:0] phase_inc   = real_to_fixed(2.0/16, 13),
    logic signed [15:0] cart_x      = real_to_fixed(1.0, 14),
    logic signed [15:0] cart_y      = real_to_fixed(0.0, 14)
  );
    write_reg(port, REG_SPP, spp);
    write_reg(port, REG_WAVEFORM, mode);
    write_reg(port, REG_GAIN, gain);
    if (mode == WAVE_CONST) begin
      write_reg(port, REG_CONSTANT, {const_re, const_im});
    end else if (mode == WAVE_SINE) begin
      write_reg(port, REG_PHASE_INC, phase_inc);
      write_reg(port, REG_CARTESIAN, {cart_x, cart_y});
    end
    write_reg(port, REG_ENABLE, 1);

    for (int packet_count = 0; packet_count < num_packets; packet_count++) begin
      item_t items[$];
      item_t expected_const, expected_sine, actual;


      blk_ctrl.recv_items(port, items);


      `ASSERT_ERROR(
        items.size() == spp,
        "Packet length didn't match configured SPP"
      );


      foreach (items[i]) begin
        actual = items[i];


        expected_const[31:16] = apply_gain(gain, const_re);
        expected_const[15: 0] = apply_gain(gain, const_im);


        if (i == 0) begin


          expected_sine = actual;
        end else begin
          expected_sine = next_sine_value(items[i-1], phase_inc);
        end


        if (mode == WAVE_CONST) begin

          `ASSERT_ERROR(
            actual == expected_const,
            $sformatf("Incorrect constant sample on packet %0d. Expected 0x%X, received 0x%X.",
              packet_count, expected_const, actual)
          );
        end else if (mode == WAVE_SINE) begin


          `ASSERT_ERROR(
            samples_are_close(actual, expected_sine),
            $sformatf("Incorrect sine sample on packet %0d. Expected 0x%X, received 0x%X.",
              packet_count, expected_sine, actual)
          );
        end else if (mode == WAVE_NOISE) begin
          if (i != 0) begin


            `ASSERT_ERROR(items[i] !== items[i-1],
              $sformatf("Noise output didn't update on packet %0d.Received 0x%X.",
                packet_count, actual)
            );
          end
        end

      end
    end


    write_reg(port, REG_ENABLE, 0);
    flush_output(port);
  endtask : run_waveform




  task automatic run_const(
    int  port,
    int  num_packets = 50,
    int  spp         = SPP,
    real gain,
    real re,
    real im
  );
    logic signed [15:0] fgain, fre, fim;


    `ASSERT_FATAL(gain <= MAX_GAIN_R   || gain >= MIN_GAIN_R,  "Gain out of range");
    `ASSERT_FATAL(re   <= MAX_CONST_R  || re   >= MIN_CONST_R, "Real out of range");
    `ASSERT_FATAL(im   <= MAX_CONST_R  || im   >= MIN_CONST_R, "Imag out of range");


    fgain  = real_to_fixed(gain, GAIN_FRAC);
    fre    = real_to_fixed(re, CONST_FRAC);
    fim    = real_to_fixed(im, CONST_FRAC);


    run_waveform(
      .port(port),
      .gain(fgain),
      .mode(WAVE_CONST),
      .num_packets(num_packets),
      .spp(spp),
      .const_re(fre),
      .const_im(fim)
    );
  endtask : run_const




  task automatic run_sine(
    int  port,
    int  num_packets = 50,
    int  spp         = SPP,
    real gain,
    real x,
    real y,
    real phase
  );
    logic signed [15:0] fgain, fx, fy, fphase;


    `ASSERT_FATAL(gain  <= MAX_GAIN_R  || gain  >= MIN_GAIN_R,  "Gain out of range");
    `ASSERT_FATAL(x     <= MAX_CART_R  || x     >= MIN_CART_R,  "X out of range");
    `ASSERT_FATAL(y     <= MAX_CART_R  || y     >= MIN_CART_R,  "Y out of range");
    `ASSERT_FATAL(phase <= MAX_PHASE_R || phase >= MIN_PHASE_R, "Phase out of range");


    fgain  = real_to_fixed(gain, GAIN_FRAC);
    fx     = real_to_fixed(x, CART_FRAC);
    fy     = real_to_fixed(y, CART_FRAC);
    fphase = real_to_fixed(phase, PHASE_FRAC);


    run_waveform(
      .port(port),
      .gain(fgain),
      .mode(WAVE_SINE),
      .num_packets(num_packets),
      .spp(spp),
      .cart_x(fx),
      .cart_y(fy),
      .phase_inc(fphase)
    );
  endtask : run_sine




  task automatic run_noise(
    int  port,
    int  num_packets = 50,
    int  spp         = SPP,
    real gain
  );
    logic signed [15:0] fgain;


    `ASSERT_FATAL(gain <= MAX_GAIN_R || gain >= MIN_GAIN_R, "Gain out of range");


    fgain = real_to_fixed(gain, GAIN_FRAC);


    run_waveform(
      .port(port),
      .gain(fgain),
      .mode(WAVE_NOISE),
      .num_packets(num_packets),
      .spp(spp)
    );
  endtask : run_noise







  task automatic test_registers(int port);
    test.start_test($sformatf("Test registers (port %0d)", port), 1ms);

    test_read_write_reg(port, REG_SPP,       {REG_SPP_LEN{1'b1}},       32'd16);
    test_read_write_reg(port, REG_GAIN,      {REG_GAIN_LEN{1'b1}},      32'h7FFF);
    test_read_write_reg(port, REG_CONSTANT,  {REG_CONSTANT_LEN{1'b1}},  32'h0);
    test_read_write_reg(port, REG_PHASE_INC, {REG_PHASE_INC_LEN{1'b1}}, {REG_PHASE_INC_LEN{1'bX}});
    test_read_write_reg(port, REG_CARTESIAN, {REG_CARTESIAN_LEN{1'b1}}, {REG_CARTESIAN_LEN{1'bX}});
    test.end_test();
  endtask : test_registers



  task automatic test_waveforms(int port);
    test.start_test($sformatf("Test waveforms (port %0d)", port), 1ms);
    run_const(.port(port), .gain(0.5), .re(0.25), .im(0.5));
    run_sine(.port(port), .gain(0.75), .x(0.25), .y(0.5), .phase(2.0/64));
    run_noise(.port(port), .gain(0.999));
    test.end_test();
  endtask : test_waveforms





  task automatic test_gain(int port);
    logic signed [15:0] min_val;
    logic signed [15:0] max_val;

    test.start_test($sformatf("Test gain (port %0d)", port), 1ms);

    max_val = 16'sh7FFF;
    min_val = 16'sh8000;


    run_waveform(.port(port), .mode(WAVE_CONST), .gain(max_val),
      .const_re(max_val), .const_im(min_val));

    run_waveform(.port(port), .mode(WAVE_CONST), .gain(min_val),
      .const_re(min_val), .const_im(max_val));

    run_waveform(.port(port), .mode(WAVE_CONST), .gain(0),
      .const_re(max_val), .const_im(min_val));

    run_waveform(
      .port(port),
      .mode(WAVE_CONST),
      .const_re(real_to_fixed(0.5, CONST_FRAC)),
      .const_im(real_to_fixed(0.25, CONST_FRAC)),
      .gain(real_to_fixed(0.5, GAIN_FRAC))
      );
    test.end_test();
  endtask : test_gain



  task automatic test_phase(int port);
    test.start_test($sformatf("Test phase (port %0d)", port), 1ms);

    run_sine(.port(port), .gain(0.5), .x(1.0), .y(0.0), .phase(2.0/16), .num_packets(2));

    run_sine(.port(port), .gain(0.5), .x(1.0), .y(0.0), .phase(MAX_PHASE_R), .num_packets(2));

    run_sine(.port(port), .gain(0.5), .x(1.0), .y(0.0), .phase(MIN_PHASE_R), .num_packets(2));
    test.end_test();
  endtask : test_phase



  task automatic test_packet_length(int port);
    test.start_test($sformatf("Test packet length (port %0d)", port), 1ms);
    run_waveform(.port(port), .spp(2));
    run_waveform(.port(port), .spp(SPP));
    run_waveform(.port(port), .spp((2**MTU-1) * (CHDR_W / ITEM_W)));
    test.end_test();
  endtask : test_packet_length






  initial begin : tb_main
    int port;


    test.start_tb(
      $sformatf("rfnoc_block_siggen_tb (CHDR_W = %0d, NUM_PORTS = %0d)",
      CHDR_W, NUM_PORTS));




    rfnoc_chdr_clk_gen.start();
    rfnoc_ctrl_clk_gen.start();
    ce_clk_gen.start();


    blk_ctrl.run();





    test.start_test("Flush block then reset it", 10us);
    blk_ctrl.flush_and_reset();
    test.end_test();





    test.start_test("Verify Block Info", 2us);
    `ASSERT_ERROR(blk_ctrl.get_noc_id() == NOC_ID, "Incorrect NOC_ID Value");
    `ASSERT_ERROR(blk_ctrl.get_num_data_i() == NUM_PORTS_I, "Incorrect NUM_DATA_I Value");
    `ASSERT_ERROR(blk_ctrl.get_num_data_o() == NUM_PORTS_O, "Incorrect NUM_DATA_O Value");
    `ASSERT_ERROR(blk_ctrl.get_mtu() == MTU, "Incorrect MTU Value");
    test.end_test();






    for(port = 0; port < NUM_PORTS; port++) begin
      test_registers(port);
      test_waveforms(port);
    end


    port = 0;
    test_gain(port);
    test_packet_length(port);
    test_phase(port);








    test.end_tb(0);


    rfnoc_chdr_clk_gen.kill();
    rfnoc_ctrl_clk_gen.kill();
    ce_clk_gen.kill();
  end : tb_main

endmodule