module altera_jtag_dc_streaming  #(
    parameter PURPOSE = 0, // for discovery of services behind this JTAG Phy - 0
                           //   for JTAG Phy, 1 for Packets to Master
    parameter UPSTREAM_FIFO_SIZE = 0,
    parameter DOWNSTREAM_FIFO_SIZE = 0,
    parameter MGMT_CHANNEL_WIDTH = 0
) (
    // Signals in the JTAG clock domain
    input  wire       tck,
    input  wire       tdi,
    output wire       tdo,
    input  wire [2:0] ir_in,
    input  wire       virtual_state_cdr,
    input  wire       virtual_state_sdr,
    input  wire       virtual_state_udr,

    input  wire       clk,
    input  wire       reset_n,
    output wire [7:0] source_data,
    output wire       source_valid,
    input  wire [7:0] sink_data,
    input  wire       sink_valid,
    output wire       sink_ready,
    output wire       resetrequest,
    output wire       debug_reset,
    output wire       mgmt_valid,
    output wire [(MGMT_CHANNEL_WIDTH>0?MGMT_CHANNEL_WIDTH:1)-1:0] mgmt_channel,
    output wire       mgmt_data
);

   // the tck to sysclk sync depth is fixed at 8
   // 8 is the worst case scenario from our metastability analysis, and since
   // using TCK serially is so slow we should have plenty of clock cycles.
   localparam TCK_TO_SYSCLK_SYNC_DEPTH = 8;
   // The clk to tck path is fixed at 3 deep for Synchronizer depth.
   // Since the tck clock is so slow, no parameter is exposed.
   localparam SYSCLK_TO_TCK_SYNC_DEPTH = 3;

   wire       jtag_clock_reset_n; // system reset is synchronized with tck
   wire [7:0] jtag_source_data;
   wire       jtag_source_valid;
   wire [7:0] jtag_sink_data;
   wire       jtag_sink_valid;
   wire       jtag_sink_ready;

   /* Reset Synchronizer module.
    *
    * The SLD Node does not provide a reset for the TCK clock domain.
    * Due to the handshaking nature of the Avalon-ST Clock Crosser,
    * internal states need to be reset to 0 in order to guarantee proper
    * functionality throughout resets.
    *
    * This reset block will asynchronously assert reset, and synchronously
    * deassert reset for the tck clock domain.
    */
   altera_std_synchronizer #(
       .depth(SYSCLK_TO_TCK_SYNC_DEPTH)
   ) synchronizer (
       .clk(tck),
       .reset_n(reset_n),
       .din(1'b1),
       .dout(jtag_clock_reset_n)
   );

   altera_jtag_streaming #(
       .PURPOSE(PURPOSE),
       .UPSTREAM_FIFO_SIZE(UPSTREAM_FIFO_SIZE),
       .DOWNSTREAM_FIFO_SIZE(DOWNSTREAM_FIFO_SIZE),
       .MGMT_CHANNEL_WIDTH(MGMT_CHANNEL_WIDTH)
   ) jtag_streaming (
       .tck              (tck),
       .tdi              (tdi),
       .tdo              (tdo),
       .ir_in            (ir_in),
       .virtual_state_cdr(virtual_state_cdr),
       .virtual_state_sdr(virtual_state_sdr),
       .virtual_state_udr(virtual_state_udr),

       .reset_n(jtag_clock_reset_n),
       .source_data(jtag_source_data),
       .source_valid(jtag_source_valid),
       .sink_data(jtag_sink_data),
       .sink_valid(jtag_sink_valid),
       .sink_ready(jtag_sink_ready),
       .clock_to_sample(clk),
       .reset_to_sample(reset_n),
       .resetrequest(resetrequest),
       .debug_reset(debug_reset),
       .mgmt_valid(mgmt_valid),
       .mgmt_channel(mgmt_channel),
       .mgmt_data(mgmt_data)
    );

   // synchronization in both clock domain crossings takes place in the "clk" system clock domain!

   altera_avalon_st_clock_crosser #(
       .SYMBOLS_PER_BEAT(1),
       .BITS_PER_SYMBOL(8),
       .FORWARD_SYNC_DEPTH(SYSCLK_TO_TCK_SYNC_DEPTH),
       .BACKWARD_SYNC_DEPTH(TCK_TO_SYSCLK_SYNC_DEPTH)
   ) sink_crosser (
       .in_clk(clk),
       .in_reset(~reset_n),
       .in_data(sink_data),
       .in_ready(sink_ready),
       .in_valid(sink_valid),
       .out_clk(tck),
       .out_reset(~jtag_clock_reset_n),
       .out_data(jtag_sink_data),
       .out_ready(jtag_sink_ready),
       .out_valid(jtag_sink_valid)
   );

   altera_jtag_src_crosser #(
       .SYNC_DEPTH(TCK_TO_SYSCLK_SYNC_DEPTH)
   ) source_crosser (
       .sink_clk(tck),
       .sink_reset_n(jtag_clock_reset_n),
       .sink_valid(jtag_source_valid),
       .sink_data(jtag_source_data),
       .src_clk(clk),
       .src_reset_n(reset_n),
       .src_valid(source_valid),
       .src_data(source_data)
   );

endmodule