USB passthrough


#1

Hello all,

First, I’d like to be clear: I am totally new to verilog (and FPGA work); I am sure there is something simple that I’m missing.

I’m working on a project to modify USB packets inline. I’d like to be able to do this without a PHY, it’s just a home project intended to help me learn. Anyways, I’m currently able to snoop USB traffic and output DATA packets, but I’d like to be able to modify the signal inline.

I have 4 tri-state ports; D+/D- for both host and device. Ideally, I’d like to just pass through host<->dev while maintaining a bus direction register… the pins should never z state. The relevant code is below:

/*
  This module drives the tristate pins for host and device USB.
  It controls the state of tx/rx based on busdir.
*/

module bus_bidirection(
    //Device side pins
    inout USB_DP_DEV,
    inout USB_DN_DEV,
    // Host side pins
    inout USB_DP_HOST,
    inout USB_DN_HOST,
    // Bus tap
    output USB_DP,
    output USB_DN,
    //High if from device; Low for host to device
    input BUSDIR,
    input CLOCK24
  );

  assign USB_DP = BUSDIR ? USB_DP_DEV_IN : USB_DP_HOST_IN;
  assign USB_DN = BUSDIR ? USB_DN_DEV_IN : USB_DN_HOST_IN;


/*
  wire USB_DP_DEV, USB_DP_HOST;
  wire USB_DN_DEV, USB_DN_HOST;
*/

  wire USB_DP_DEV_IN, USB_DP_HOST_IN;
  wire USB_DP_DEV_OUT, USB_DP_HOST_OUT;
  wire USB_DN_DEV_IN, USB_DN_HOST_IN;
  wire USB_DN_DEV_OUT, USB_DN_HOST_OUT;



  assign USB_DP_DEV_OUT   = BUSDIR ? 1'b0 : USB_DP_HOST_IN;
  assign USB_DN_DEV_OUT   = BUSDIR ? 1'b0 : USB_DN_HOST_IN;
  assign USB_DP_HOST_OUT  = BUSDIR ? USB_DP_DEV_IN : 1'b1;
  assign USB_DN_HOST_OUT  = BUSDIR ? USB_DN_DEV_IN : 1'b0;


/*
  assign USB_DP_DEV_OUT   = USB_DP_HOST_IN;
  assign USB_DN_DEV_OUT   = USB_DN_HOST_IN;
  assign USB_DP_HOST_OUT  = USB_DP_DEV_IN;
  assign USB_DN_HOST_OUT  = USB_DN_DEV_IN;
*/

  //
  // Tristates for device pins
  //
  SB_IO #(
    .PIN_TYPE(6'b1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
    .PULLUP(1'b0)
  )
  iobuf_usbp_dev (
    .PACKAGE_PIN(USB_DP_DEV),
    .OUTPUT_ENABLE(!BUSDIR),
    .D_OUT_0(USB_DP_DEV_OUT),
    .D_IN_0(USB_DP_DEV_IN)
  );


  SB_IO #(
    .PIN_TYPE(6'b1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
    .PULLUP(1'b0)
  )
  iobuf_usbn_dev (
    .PACKAGE_PIN(USB_DN_DEV),
    .OUTPUT_ENABLE(!BUSDIR),
    .D_OUT_0(USB_DN_DEV_OUT),
    .D_IN_0(USB_DN_DEV_IN)
  );

  //
  // Tristates for host pins
  //
  SB_IO #(
    .PIN_TYPE(6'b1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
    .PULLUP(1'b0)
  )
  iobuf_usbp_host (
    .PACKAGE_PIN(USB_DP_HOST),
    .OUTPUT_ENABLE(BUSDIR),
    .D_OUT_0(USB_DP_HOST_OUT),
    .D_IN_0(USB_DP_HOST_IN)
  );

  SB_IO #(
    .PIN_TYPE(6'b1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
    .PULLUP(1'b0)
  )
  iobuf_usbn_host (
    .PACKAGE_PIN(USB_DN_HOST),
    .OUTPUT_ENABLE(BUSDIR),
    .D_OUT_0(USB_DN_HOST_OUT),
    .D_IN_0(USB_DN_HOST_IN)
  );

endmodule

Logic analyzer output from the host pin side indicates that the output is not differential (but I’m not entirely sure if this is also host interference):

I imagine I’ve missed something obvious! Any help is appreciated, thanks!


#2

Hi @nopadon,

Interesting project, how do you plan to keep track of the direction? I am no expert[tm] either but here is my feedback.

I think I would choose for a less complex combinatorial approach purely based on the magic busdir
e.g.
assign host_dp_out = dev_dp_in
assign host_dm_out = dev_dm_in (or even force differential using ! dev_dp_out)

and use busdir only the change the direction of the IO buffers.

In your code I spotted a small problem:

  assign USB_DP_DEV_OUT   = BUSDIR ? 1'b0 : USB_DP_HOST_IN;
  assign USB_DN_DEV_OUT   = BUSDIR ? 1'b0 : USB_DN_HOST_IN;
  assign USB_DP_HOST_OUT  = BUSDIR ? USB_DP_DEV_IN : 1'b1; <- fishy that this one default to one compared to the others
  assign USB_DN_HOST_OUT  = BUSDIR ? USB_DN_DEV_IN : 1'b0;

#3

Hi,

any progress on this project?