data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v
1: b'%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:248: Define or directive not defined: \'`ADDR_SPACE_USB\'\n    user_usb_tb.wb_user_core_write(`ADDR_SPACE_USB+addr,wdata);\n                                   ^~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:256: Define or directive not defined: \'`ADDR_SPACE_USB\'\n    user_usb_tb.wb_user_core_read(`ADDR_SPACE_USB+addr,rdata);\n                                  ^~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:336: syntax error, unexpected ->\n     -> user_usb_tb.test_control.error_detected;\n     ^~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:443: syntax error, unexpected \'@\'\n   forever @(posedge user_usb_tb.usb_48mhz_clk) begin\n           ^\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:446: syntax error, unexpected \'@\'\n            @(posedge user_usb_tb.usb_48mhz_clk);\n            ^\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:451: syntax error, unexpected end\nend\n^~~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:461: syntax error, unexpected IDENTIFIER, expecting "\'{"\nreg [7:0] val;\n          ^~~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:668: syntax error, unexpected ->\n      -> user_usb_tb.test_control.error_detected;\n      ^~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:703: syntax error, unexpected ->\n       -> user_usb_tb.test_control.error_detected;\n       ^~\n%Error: data/full_repos/permissive/492704601/verilog/dv/agents/usb_agents.v:735: syntax error, unexpected ->\n       -> user_usb_tb.test_control.error_detected;\n       ^~\n%Error: Exiting due to 10 error(s)\n'
module usb_agent;






`define USB_RES_OK      8'h0
`define USB_RES_NAK     8'hFF
`define USB_RES_STALL   8'hFE
`define USB_RES_TIMEOUT 8'hFD



`define PID_OUT        8'hE1
`define PID_IN         8'h69
`define PID_SOF        8'hA5
`define PID_SETUP      8'h2D

`define PID_DATA0      8'hC3
`define PID_DATA1      8'h4B

`define PID_ACK        8'hD2
`define PID_NAK        8'h5A
`define PID_STALL      8'h1E


`define REQ_GET_STATUS        8'h00
`define REQ_CLEAR_FEATURE     8'h01
`define REQ_SET_FEATURE       8'h03
`define REQ_SET_ADDRESS       8'h05
`define REQ_GET_DESCRIPTOR    8'h06
`define REQ_SET_DESCRIPTOR    8'h07
`define REQ_GET_CONFIGURATION 8'h08
`define REQ_SET_CONFIGURATION 8'h09
`define REQ_GET_INTERFACE     8'h0A
`define REQ_SET_INTERFACE     8'h0B
`define REQ_SYNC_FRAME        8'h0C


`define DESC_DEVICE           8'h01
`define DESC_CONFIGURATION    8'h02
`define DESC_STRING           8'h03
`define DESC_INTERFACE        8'h04
`define DESC_ENDPOINT         8'h05
`define DESC_DEV_QUALIFIER    8'h06
`define DESC_OTHER_SPEED_CONF 8'h07
`define DESC_IF_POWER         8'h08


`define DEV_CLASS_RESERVED      8'h00
`define DEV_CLASS_AUDIO         8'h01
`define DEV_CLASS_COMMS         8'h02
`define DEV_CLASS_HID           8'h03
`define DEV_CLASS_MONITOR       8'h04
`define DEV_CLASS_PHY_IF        8'h05
`define DEV_CLASS_POWER         8'h06
`define DEV_CLASS_PRINTER       8'h07
`define DEV_CLASS_STORAGE       8'h08
`define DEV_CLASS_HUB           8'h09
`define DEV_CLASS_TMC           8'hFE
`define DEV_CLASS_VENDOR_CUSTOM 8'hFF


`define REQDIR_HOSTTODEVICE        (0 << 7)
`define REQDIR_DEVICETOHOST        (1 << 7)
`define REQTYPE_STANDARD           (0 << 5)
`define REQTYPE_CLASS              (1 << 5)
`define REQTYPE_VENDOR             (2 << 5)
`define REQREC_DEVICE              (0 << 0)
`define REQREC_INTERFACE           (1 << 0)
`define REQREC_ENDPOINT            (2 << 0)
`define REQREC_OTHER               (3 << 0)


`define ENDPOINT_DIR_MASK          (1 << 7)
`define ENDPOINT_DIR_IN            (1 << 7)
`define ENDPOINT_DIR_OUT           (0 << 7)
`define ENDPOINT_ADDR_MASK         (8'h7F)
`define ENDPOINT_TYPE_MASK         (8'h3)
`define ENDPOINT_TYPE_CONTROL      (0)
`define ENDPOINT_TYPE_ISO          (1)
`define ENDPOINT_TYPE_BULK         (2)
`define ENDPOINT_TYPE_INTERRUPT    (3)





`define USB_CTRL          8'h0
    `define USB_CTRL_TX_FLUSH                    8
    `define USB_CTRL_TX_FLUSH_SHIFT              8
    `define USB_CTRL_TX_FLUSH_MASK               8'h1

    `define USB_CTRL_PHY_DMPULLDOWN              7
    `define USB_CTRL_PHY_DMPULLDOWN_SHIFT        7
    `define USB_CTRL_PHY_DMPULLDOWN_MASK         8'h1

    `define USB_CTRL_PHY_DPPULLDOWN              6
    `define USB_CTRL_PHY_DPPULLDOWN_SHIFT        6
    `define USB_CTRL_PHY_DPPULLDOWN_MASK         8'h1

    `define USB_CTRL_PHY_TERMSELECT              5
    `define USB_CTRL_PHY_TERMSELECT_SHIFT        5
    `define USB_CTRL_PHY_TERMSELECT_MASK         8'h1

    `define USB_CTRL_PHY_XCVRSELECT_SHIFT        3
    `define USB_CTRL_PHY_XCVRSELECT_MASK         8'h3

    `define USB_CTRL_PHY_OPMODE_SHIFT            1
    `define USB_CTRL_PHY_OPMODE_MASK             8'h3

    `define USB_CTRL_ENABLE_SOF                  0
    `define USB_CTRL_ENABLE_SOF_SHIFT            0
    `define USB_CTRL_ENABLE_SOF_MASK             8'h1

`define USB_STATUS        8'h4
    `define USB_STATUS_SOF_TIME_SHIFT            16
    `define USB_STATUS_SOF_TIME_MASK             16'hffff

    `define USB_STATUS_RX_ERROR                  2
    `define USB_STATUS_RX_ERROR_SHIFT            2
    `define USB_STATUS_RX_ERROR_MASK             8'h1

    `define USB_STATUS_LINESTATE_BITS_SHIFT      0
    `define USB_STATUS_LINESTATE_BITS_MASK       8'h3

`define USB_IRQ_ACK       8'h8
    `define USB_IRQ_ACK_DEVICE_DETECT            3
    `define USB_IRQ_ACK_DEVICE_DETECT_SHIFT      3
    `define USB_IRQ_ACK_DEVICE_DETECT_MASK       8'h1

    `define USB_IRQ_ACK_ERR                      2
    `define USB_IRQ_ACK_ERR_SHIFT                2
    `define USB_IRQ_ACK_ERR_MASK                 8'h1

    `define USB_IRQ_ACK_DONE                     1
    `define USB_IRQ_ACK_DONE_SHIFT               1
    `define USB_IRQ_ACK_DONE_MASK                8'h1

    `define USB_IRQ_ACK_SOF                      0
    `define USB_IRQ_ACK_SOF_SHIFT                0
    `define USB_IRQ_ACK_SOF_MASK                 8'h1

`define USB_IRQ_STS       8'hc
    `define USB_IRQ_STS_DEVICE_DETECT            3
    `define USB_IRQ_STS_DEVICE_DETECT_SHIFT      3
    `define USB_IRQ_STS_DEVICE_DETECT_MASK       8'h1

    `define USB_IRQ_STS_ERR                      2
    `define USB_IRQ_STS_ERR_SHIFT                2
    `define USB_IRQ_STS_ERR_MASK                 8'h1

    `define USB_IRQ_STS_DONE                     1
    `define USB_IRQ_STS_DONE_SHIFT               1
    `define USB_IRQ_STS_DONE_MASK                8'h1

    `define USB_IRQ_STS_SOF                      0
    `define USB_IRQ_STS_SOF_SHIFT                0
    `define USB_IRQ_STS_SOF_MASK                 8'h1

`define USB_IRQ_MASK      8'h10
    `define USB_IRQ_MASK_DEVICE_DETECT           3
    `define USB_IRQ_MASK_DEVICE_DETECT_SHIFT     3
    `define USB_IRQ_MASK_DEVICE_DETECT_MASK      8'h1

    `define USB_IRQ_MASK_ERR                     2
    `define USB_IRQ_MASK_ERR_SHIFT               2
    `define USB_IRQ_MASK_ERR_MASK                8'h1

    `define USB_IRQ_MASK_DONE                    1
    `define USB_IRQ_MASK_DONE_SHIFT              1
    `define USB_IRQ_MASK_DONE_MASK               8'h1

    `define USB_IRQ_MASK_SOF                     0
    `define USB_IRQ_MASK_SOF_SHIFT               0
    `define USB_IRQ_MASK_SOF_MASK                8'h1

`define USB_XFER_DATA     8'h14
    `define USB_XFER_DATA_TX_LEN_SHIFT           0
    `define USB_XFER_DATA_TX_LEN_MASK            16'hffff

`define USB_XFER_TOKEN    8'h18
    `define USB_XFER_TOKEN_START                 31
    `define USB_XFER_TOKEN_START_SHIFT           31
    `define USB_XFER_TOKEN_START_MASK            8'h1

    `define USB_XFER_TOKEN_IN                    30
    `define USB_XFER_TOKEN_IN_SHIFT              30
    `define USB_XFER_TOKEN_IN_MASK               8'h1

    `define USB_XFER_TOKEN_ACK                   29
    `define USB_XFER_TOKEN_ACK_SHIFT             29
    `define USB_XFER_TOKEN_ACK_MASK              8'h1

    `define USB_XFER_TOKEN_PID_DATAX             28
    `define USB_XFER_TOKEN_PID_DATAX_SHIFT       28
    `define USB_XFER_TOKEN_PID_DATAX_MASK        8'h1

    `define USB_XFER_TOKEN_PID_BITS_SHIFT        16
    `define USB_XFER_TOKEN_PID_BITS_MASK         8'hff

    `define USB_XFER_TOKEN_DEV_ADDR_SHIFT        9
    `define USB_XFER_TOKEN_DEV_ADDR_MASK         8'h7f

    `define USB_XFER_TOKEN_EP_ADDR_SHIFT         5
    `define USB_XFER_TOKEN_EP_ADDR_MASK          8'hf

`define USB_RX_STAT       8'h1c
    `define USB_RX_STAT_START_PEND               31
    `define USB_RX_STAT_START_PEND_SHIFT         31
    `define USB_RX_STAT_START_PEND_MASK          8'h1

    `define USB_RX_STAT_CRC_ERR                  30
    `define USB_RX_STAT_CRC_ERR_SHIFT            30
    `define USB_RX_STAT_CRC_ERR_MASK             8'h1

    `define USB_RX_STAT_RESP_TIMEOUT             29
    `define USB_RX_STAT_RESP_TIMEOUT_SHIFT       29
    `define USB_RX_STAT_RESP_TIMEOUT_MASK        8'h1

    `define USB_RX_STAT_IDLE                     28
    `define USB_RX_STAT_IDLE_SHIFT               28
    `define USB_RX_STAT_IDLE_MASK                8'h1

    `define USB_RX_STAT_RESP_BITS_SHIFT          16
    `define USB_RX_STAT_RESP_BITS_MASK           8'hff

    `define USB_RX_STAT_COUNT_BITS_SHIFT         0
    `define USB_RX_STAT_COUNT_BITS_MASK          16'hffff

`define USB_WR_DATA       8'h20
    `define USB_WR_DATA_DATA_SHIFT               0
    `define USB_WR_DATA_DATA_MASK                8'hff

`define USB_RD_DATA       8'h20
    `define USB_RD_DATA_DATA_SHIFT               0
    `define USB_RD_DATA_DATA_MASK                8'hff


task usbhw_reg_write;
input [7:0] addr;
input [31:0] wdata;
begin
    `TOP.wb_user_core_write(`ADDR_SPACE_USB+addr,wdata);
end
endtask

task usbhw_reg_read;
input [7:0] addr;
output [31:0] rdata;
begin
    `TOP.wb_user_core_read(`ADDR_SPACE_USB+addr,rdata);
end
endtask

parameter   XMIT_BUF_SIZE       = 64;
parameter   RECV_BUF_SIZE       = 64;


reg [7:0]   XmitBuffer        [0 : XMIT_BUF_SIZE];
reg [7:0]   RecvBuffer        [0 : RECV_BUF_SIZE];




task usb_setup_packet;
input [7:0]  device_address; 
input [7:0]  request_type;
input [7:0]  request; 
input [15:0] value; 
input [15:0] index; 
input [15:0] length;
output       status;
reg   [7:0]  status;
integer idx;
begin
















    idx = 0;
    XmitBuffer[idx] = request_type;           idx = idx+1;
    XmitBuffer[idx] = request;                idx = idx+1;
    XmitBuffer[idx] = (value >> 0)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (value >> 8)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (index >> 0)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (index >> 8)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (length >> 0) & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (length >> 8) & 8'hFF;  idx = idx+1;


    usbhw_transfer_out(`PID_SETUP, device_address, 0, 1, `PID_DATA0, idx,status);

end
endtask




task setup;
input [7:0] device_address;
input  [3:0] endpoint;
output [7:0]status;
begin


    usbhw_transfer_out(`PID_SETUP, device_address, endpoint, 1, `PID_DATA0, 8,status);

    usbhw_timer_sleep(50);
end
endtask

task printstatus;
   input [3:0] RecvdStatus;
   input [3:0] ExpStatus;
begin
  $display("");
  $display("    #######################################################");
  if(RecvdStatus !== ExpStatus ) begin
     -> `TOP.test_control.error_detected;
     $display("    ERROR: Expected Status and Observed Status didn't match at %0d", $time);
     if(ExpStatus==4'b0000)
        $display("    Expected Status is ACK at %0d", $time);
     else if(ExpStatus==4'b0001)
        $display("    Expected Status is NACK at %0d", $time);
     else if(ExpStatus==4'b0010)
        $display("    Expected Status is STALL at %0d", $time);
     else if(ExpStatus==4'b0011)
        $display("    Expected Status is TIMEOUT at %0d", $time);
     else if(ExpStatus==4'b0100)
        $display("    Expected Status is INVALID RESPONSE at %0d", $time);
     else if(ExpStatus==4'b0101)
        $display("    Expected Status is CRC ERROR at %0d", $time);
  end

  if(RecvdStatus==4'b0000)
     $display("    Received Status is ACK at %0d", $time);
  else if(RecvdStatus==4'b0001)
     $display("    Received Status is NACK at %0d", $time);
  else if(RecvdStatus==4'b0010)
     $display("    Received Status is STALL at %0d", $time);
  else if(RecvdStatus==4'b011)
     $display("    Received Status is TIMEOUT at %0d", $time);
  else if(RecvdStatus==4'b0100)
     $display("    Received Status is INVALID RESPONSE at %0d", $time);
  else if(RecvdStatus==4'b0101)
     $display("    Received Status is CRC ERROR at %0d", $time);
  $display("    #######################################################");
  $display("");
end
endtask



task usbhw_reset;
reg  bflag;
begin
    $display("HW: Applying USB Reset \n");

    usbhw_hub_reset;

    $display("HW: Reset Wait time Started \n");

    usbhw_timer_sleep(11);

    $display("HW: Reset Wait time Over \n");


    usbhw_hub_enable(0);
    usbhw_timer_sleep(3);

    $display("HW: Waiting for device insertion\n");


    usbhw_hub_device_detected(bflag);
    while (!bflag)begin
       usbhw_hub_device_detected(bflag);
    end

    $display("HW: Device detected\n");


    usbhw_hub_enable(1);
end
endtask












task usbhw_hub_reset;
reg [7:0] val;
begin
    $display("HW: Enter USB bus reset\n");


    val = 0;
    val = val | (0 << `USB_CTRL_PHY_XCVRSELECT_SHIFT);
    val = val | (0 << `USB_CTRL_PHY_TERMSELECT_SHIFT);
    val = val | (2 << `USB_CTRL_PHY_OPMODE_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DPPULLDOWN_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DMPULLDOWN_SHIFT);
    usbhw_reg_write(`USB_CTRL, val);

end
endtask






task usbhw_timer_sleep;
input [7:0] ResetTime;
reg [7:0] tskResetTime;
reg [7:0] tskResetTimeCounter;
begin
   tskResetTimeCounter = 0;
   tskResetTime = ResetTime;
   forever @(posedge `TOP.usb_48mhz_clk) begin
      tskResetTimeCounter = tskResetTimeCounter + 1'b1;
      if (tskResetTimeCounter > tskResetTime) begin
            @(posedge `TOP.usb_48mhz_clk);
            @(posedge `TOP.usb_48mhz_clk);
            disable usbhw_timer_sleep;
      end
   end
end
endtask 






task usbhw_hub_enable;
input enable_sof;
reg [7:0] val;
begin
    $display("HW: Enable root hub\n");


    val = 0;
    val = val | (1 << `USB_CTRL_PHY_XCVRSELECT_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_TERMSELECT_SHIFT);
    val = val | (0 << `USB_CTRL_PHY_OPMODE_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DPPULLDOWN_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DMPULLDOWN_SHIFT);
    val = val | (1 << `USB_CTRL_TX_FLUSH_SHIFT);


    if (enable_sof)
        val = val | (1 << `USB_CTRL_ENABLE_SOF_SHIFT);

    usbhw_reg_write(`USB_CTRL, val);
end
endtask





task usbhw_hub_device_detected;
output bflag;
reg _usb_fs_device;
reg [31:0] status;
reg    bflag;
begin

    usbhw_reg_read(`USB_STATUS,status);
    status = status >> `USB_STATUS_LINESTATE_BITS_SHIFT;
    status = status & `USB_STATUS_LINESTATE_BITS_MASK;



    _usb_fs_device = (status & 1);
    if(status != 1) begin
       $display("ERROR: USB Pull Up Status is not 1, Only Full Seed Supported");
    end else begin
       $display("STATUS: USB Full Speed Detected");
    end

    bflag = (status != 0);
end
endtask

task status_IN;
input [7:0] device_addr;
input [3:0] endpoint;
output [7:0] exit_code;
reg    [7:0] exit_code;
reg   [7:0] status;
reg    [7:0] rx_count;
begin
  usbhw_transfer_in(`PID_IN, device_addr, endpoint, status,exit_code,rx_count);
end
endtask

task status_OUT;
input [7:0] device_addr;
input [3:0] endpoint;
output [7:0] status;
begin
  usbhw_transfer_out(`PID_OUT, device_addr, endpoint, 1, `PID_OUT, 0,status);
end
endtask

task control_OUT;
input [7:0] device_addr;
input [3:0] endpoint;
input [7:0] ByteCount;
output [7:0] status;
begin
  usbhw_transfer_out(`PID_OUT, device_addr, endpoint, 1, `PID_DATA1, ByteCount,status);
end
endtask

task control_IN;
input [7:0] device_addr;
input [3:0] endpoint;
input [7:0] ByteCount;
output [7:0] exit_code;
reg    [7:0] exit_code;
reg    [7:0] status;
reg    [7:0] rx_count;
begin
  usbhw_transfer_in(`PID_IN, device_addr, endpoint, status,exit_code,rx_count);
end
endtask

task SetAddress;
  input [6:0] address;
begin
    XmitBuffer[0] = 8'b0000_0000;
    XmitBuffer[1] = 8'b0000_0101;
    XmitBuffer[2] = {1'b0, address};
    XmitBuffer[3] = 8'b0000_0000;
    XmitBuffer[4] = 8'b0000_0000;
    XmitBuffer[5] = 8'b0000_0000;
    XmitBuffer[6] = 8'b0000_0000;
    XmitBuffer[7] = 8'b0000_0000;
end
endtask


task SetConfiguration;
  input [1:0] cfg_val;
begin
    XmitBuffer[0] = 8'b0000_0000;
    XmitBuffer[1] = 8'b0000_1001;
    XmitBuffer[2] = {6'b000_000, cfg_val};
    XmitBuffer[3] = 8'b0000_0000;
    XmitBuffer[4] = 8'b0000_0000;
    XmitBuffer[5] = 8'b0000_0000;
    XmitBuffer[6] = 8'b0000_0000;
    XmitBuffer[7] = 8'b0000_0000;
end
endtask

task VenRegWordWr;
  input [6:0] address;
  input [31:0] reg_address;
  input [31:0] dataword;
  reg   [7:0]  Status;
begin
   XmitBuffer[0] = 8'b0100_0000;
   XmitBuffer[1] = 8'b0001_0000;
   XmitBuffer[2] = reg_address[31:24];
   XmitBuffer[3] = reg_address[23:16];
   XmitBuffer[4] = reg_address[15:8];
   XmitBuffer[5] = reg_address[7:0];
   XmitBuffer[6] = 8'b0000_0100;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);

   XmitBuffer[0] = dataword[31:24];
   XmitBuffer[1] = dataword[23:16];
   XmitBuffer[2] = dataword[15:8];
   XmitBuffer[3] = dataword[7:0];

  control_OUT(address, 4'h0, 4, Status);
  status_IN (address, 4'h0, Status);
end
endtask

task VenRegWordRd;
  input [6:0] address;
  input [31:0] reg_address;
  output [31:0] dataword;
  reg  [31:0] ByteCount;
  reg  [7:0]  Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = 8'b0001_0001;
   XmitBuffer[2] = reg_address[31:24];
   XmitBuffer[3] = reg_address[23:16];
   XmitBuffer[4] = reg_address[15:8];
   XmitBuffer[5] = reg_address[7:0];
   XmitBuffer[6] = 8'b0000_0100;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
    dataword[7:0]      = RecvBuffer[3];
    dataword[15:8]     = RecvBuffer[2];
    dataword[23:16]    = RecvBuffer[1];
    dataword[31:24]    = RecvBuffer[0];
    dump_recv_buffer(ByteCount);

   status_OUT (address, 4'h0, Status);
end
endtask

task VenRegWordRdCmp;
  input [6:0] address;
  input [31:0] reg_address;
  input [31:0] dataword;
  reg   [31:0] ByteCount;
  reg   [31:0] ReadData;
  reg    [7:0] Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = 8'b0001_0001;
   XmitBuffer[2] = reg_address[31:24];
   XmitBuffer[3] = reg_address[23:16];
   XmitBuffer[4] = reg_address[15:8];
   XmitBuffer[5] = reg_address[7:0];
   XmitBuffer[6] = 8'b0000_0100;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if ((RecvBuffer[3] !== dataword[7:0]) || (RecvBuffer[2] !== dataword[15:8]) 
         || (RecvBuffer[1] !== dataword[23:16]) || (RecvBuffer[0] !== dataword[31:24]))
    begin
      -> `TOP.test_control.error_detected;
       $display( "usb_agent check: ERROR: Register Read Byte Mismatch !!! Address: %x Exp: %x ; Rxd: %x",reg_address,dataword[31:0], {RecvBuffer[0],RecvBuffer[1], RecvBuffer[2],RecvBuffer[3]} );
       dump_recv_buffer(ByteCount);
    end else begin
       $display( "usb_agent check: STATUS: Register Read Byte Match !!! Address: %x ; Rxd: %x",reg_address,{RecvBuffer[0],RecvBuffer[1], RecvBuffer[2],RecvBuffer[3]} );

    end

   status_OUT (address, 4'h0, Status);
end
endtask
task VenRegHalfWordRd;
  input [6:0] address;
  input [21:0] reg_address;
  input [15:0] dataword;
  output [31:0] ByteCount;
  reg    [7:0]  Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = 8'b0000_0010;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if ((RecvBuffer[0] !== dataword[7:0]) || (RecvBuffer[1] !== dataword[15:8])) 
    begin
       -> `TOP.test_control.error_detected;
       $display( "usb_agent check: Register Read Byte Mismatch !!!");
       dump_recv_buffer(ByteCount);
    end
   status_OUT (address, 4'h0, Status);
end
endtask

task VenRegByteRd;
  input [6:0] address;
  input [21:0] reg_address;
  input [7:0] dataword;
  output [31:0] ByteCount;
  reg     [7:0] Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = 8'b0000_0001;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if ((RecvBuffer[0] !== dataword[7:0]))
    begin
       -> `TOP.test_control.error_detected;
       $display( "usb_agent check: Register Read Byte Mismatch !!!");
       dump_recv_buffer(ByteCount);
    end
   status_OUT (address, 4'h0, Status);
end
endtask

task VenRegWr;
  input [21:0] reg_address;
  input [2:0]  length;
begin
   XmitBuffer[0] = 8'b0100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = {5'b0000_0,length};
   XmitBuffer[7] = 8'b0000_0000;   

end
endtask

task VenRegRd;
  input [21:0] reg_address;
  input [2:0]  length;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = {5'b0000_0,length};
   XmitBuffer[7] = 8'b0000_0000;   
end
endtask

task VenRegWrWordData;
  input [7:0] Byte0;
  input [7:0] Byte1;
  input [7:0] Byte2;
  input [7:0] Byte3;
begin
   XmitBuffer[0] = Byte0;        
   XmitBuffer[1] = Byte1;
   XmitBuffer[2] = Byte2;
   XmitBuffer[3] = Byte3;
end
endtask

task VenRegWrHWordData;
  input [7:0] Byte0;
  input [7:0] Byte1;
begin
   XmitBuffer[0] = Byte0;        
   XmitBuffer[1] = Byte1;
end
endtask

task VenRegWrByteData;
  input [7:0] Byte0;
begin
   XmitBuffer[0] = Byte0;        
end
endtask

task dump_recv_buffer;
  input [31:0] NumBytes;
  integer i;
begin
  for(i=0; i < NumBytes; i=i+1)
    $display("RecvBuffer[%0d]  = %b  : %0d", i, RecvBuffer[i], RecvBuffer[i]);
end
endtask





task usbhw_transfer_out;
input [7:0]   pid;
input [7:0]   device_addr;
input [3:0]   endpoint; 
input         handshake; 
input [7:0]   request; 
input  [7:0]  tx_length;
output [7:0]  exit_code;

reg    [7:0]  exit_code;

reg  [31:0] tdata;
integer     l;
reg [31:0]  token;
reg [31:0]  ctrl;
reg [31:0]  resp;
reg [31:0]  status;
reg [31:0]  status_chk;
begin





    for (l=0;l<tx_length;l = l + 1) begin
        tdata = XmitBuffer[l];

        usbhw_reg_write(`USB_WR_DATA, tdata);
    end


    usbhw_reg_write(`USB_XFER_DATA, tx_length);


    ctrl = (1 << `USB_XFER_TOKEN_START_SHIFT);


    ctrl= ctrl | (handshake ? (1 << `USB_XFER_TOKEN_ACK_SHIFT) : 0);

    ctrl= ctrl | ((request == `PID_DATA1) ? (1 << `USB_XFER_TOKEN_PID_DATAX_SHIFT) : (0 << `USB_XFER_TOKEN_PID_DATAX_SHIFT));


    token = (pid<<`USB_XFER_TOKEN_PID_BITS_SHIFT) | (device_addr << `USB_XFER_TOKEN_DEV_ADDR_SHIFT) | (endpoint << `USB_XFER_TOKEN_EP_ADDR_SHIFT);
    usbhw_reg_write(`USB_XFER_TOKEN, token | ctrl);


    usbhw_reg_read(`USB_RX_STAT,status) ;
    status_chk = status & (1 << `USB_RX_STAT_START_PEND_SHIFT);
    while (status_chk) begin
        usbhw_reg_read(`USB_RX_STAT,status) ;
        status_chk = status & (1 << `USB_RX_STAT_START_PEND_SHIFT);
    end


    if (!handshake) begin
	exit_code = `USB_RES_OK;
    end


    usbhw_reg_read(`USB_RX_STAT,status) ;
    status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT) ;
    while (!(status_chk)) begin
       usbhw_reg_read(`USB_RX_STAT,status) ;
       status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT) ;
    end

    $display("USB RESPONSE: %x",status);

    if (status & (1 << `USB_RX_STAT_RESP_TIMEOUT_SHIFT)) begin
       $display("  USB TIMEOUT\n");
       $display("USB ERROR: OUT timeout\n");
       exit_code = `USB_RES_TIMEOUT;
    end


    resp = ((status >> `USB_RX_STAT_RESP_BITS_SHIFT) & `USB_RX_STAT_RESP_BITS_MASK);
    if (resp == `PID_ACK) begin
       $display("USB STATUS: ACK\n");
       exit_code = `USB_RES_OK;
    end else if (resp == `PID_NAK) begin
       $display("USB STATUS: NAK\n");
       exit_code = `USB_RES_NAK;
    end else if (resp == `PID_STALL) begin
       $display("USB STATUS:  STALL\n");
       $display("USB ERROR:  OUT STALL\n");
       exit_code = `USB_RES_STALL;
    end else begin
       $display("USB ERROR: Unknown OUT response (%02x)\n", resp);


       exit_code = `USB_RES_STALL;
    end
end
endtask




task usbhw_transfer_in;
input [7:0]    pid; 
input [7:0]    device_addr; 
input [7:0]    endpoint; 
output [7:0]   response; 
output [7:0]   exit_code;
output [7:0]   rx_count;

reg  [7:0]     exit_code;
reg  [7:0]     response; 
reg  [7:0]     rx_length;
integer l;
reg  [7:0]     rx_count;
reg [31:0]     token;
reg [31:0]     data;
reg [31:0]     status;
reg [31:0]     status_chk;
begin




    usbhw_reg_write(`USB_XFER_DATA, 0);


    token = (pid<<`USB_XFER_TOKEN_PID_BITS_SHIFT) | (device_addr << `USB_XFER_TOKEN_DEV_ADDR_SHIFT) | (endpoint << `USB_XFER_TOKEN_EP_ADDR_SHIFT);
    token= token |(1 << `USB_XFER_TOKEN_START_SHIFT);
    token= token | (1 << `USB_XFER_TOKEN_IN_SHIFT);
    token= token | (1 << `USB_XFER_TOKEN_ACK_SHIFT);

    usbhw_reg_write(`USB_XFER_TOKEN, token);

    status_chk = status & (1 << `USB_RX_STAT_START_PEND);
    while (status_chk) begin
       usbhw_reg_read(`USB_RX_STAT,status);
       status_chk = status & (1 << `USB_RX_STAT_START_PEND);
    end


    usbhw_reg_read(`USB_RX_STAT,status); 
    status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT);
    while (!(status_chk)) begin
       usbhw_reg_read(`USB_RX_STAT,status); 
       status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT);
    end

    if (status & (1 << `USB_RX_STAT_CRC_ERR_SHIFT)) begin
       $display("USB: CRC ERROR\n");
       exit_code = `USB_RES_TIMEOUT;
    end else if (status & (1 << `USB_RX_STAT_RESP_TIMEOUT_SHIFT)) begin
       $display("USB: IN timeout\n");
       exit_code = `USB_RES_TIMEOUT;
    end else begin


        response = ((status >> `USB_RX_STAT_RESP_BITS_SHIFT) & `USB_RX_STAT_RESP_BITS_MASK);

        if (response == `PID_NAK) begin
           $display("USB NAK RECEIVED \n");
           exit_code = `USB_RES_NAK;
        end else if (response == `PID_STALL) begin
           $display("USB: IN STALL\n");
           exit_code = `USB_RES_STALL;
        end else begin


           if (status & (1 << `USB_RX_STAT_CRC_ERR_SHIFT)) begin
                $display("USB: CRC Error\n");
                exit_code = `USB_RES_STALL;
           end else begin


                rx_count = ((status >> `USB_RX_STAT_COUNT_BITS_SHIFT) & `USB_RX_STAT_COUNT_BITS_MASK);








                if(rx_length >= rx_count)
                    $display("USB ERROR Difference in rx len:%d and Rx Data Count: %d",rx_length,rx_count);
   
                for (l=0;l<rx_count;l=l+1) begin
                    usbhw_reg_read(`USB_RD_DATA,data);

                    RecvBuffer[l] = data;
                end
		exit_code = `USB_RES_OK;
	   end
	end
    end
end
endtask

endmodule
module usb_agent;







`define USB_RES_OK      8'h0
`define USB_RES_NAK     8'hFF
`define USB_RES_STALL   8'hFE
`define USB_RES_TIMEOUT 8'hFD



`define PID_OUT        8'hE1
`define PID_IN         8'h69
`define PID_SOF        8'hA5
`define PID_SETUP      8'h2D

`define PID_DATA0      8'hC3
`define PID_DATA1      8'h4B

`define PID_ACK        8'hD2
`define PID_NAK        8'h5A
`define PID_STALL      8'h1E


`define REQ_GET_STATUS        8'h00
`define REQ_CLEAR_FEATURE     8'h01
`define REQ_SET_FEATURE       8'h03
`define REQ_SET_ADDRESS       8'h05
`define REQ_GET_DESCRIPTOR    8'h06
`define REQ_SET_DESCRIPTOR    8'h07
`define REQ_GET_CONFIGURATION 8'h08
`define REQ_SET_CONFIGURATION 8'h09
`define REQ_GET_INTERFACE     8'h0A
`define REQ_SET_INTERFACE     8'h0B
`define REQ_SYNC_FRAME        8'h0C


`define DESC_DEVICE           8'h01
`define DESC_CONFIGURATION    8'h02
`define DESC_STRING           8'h03
`define DESC_INTERFACE        8'h04
`define DESC_ENDPOINT         8'h05
`define DESC_DEV_QUALIFIER    8'h06
`define DESC_OTHER_SPEED_CONF 8'h07
`define DESC_IF_POWER         8'h08


`define DEV_CLASS_RESERVED      8'h00
`define DEV_CLASS_AUDIO         8'h01
`define DEV_CLASS_COMMS         8'h02
`define DEV_CLASS_HID           8'h03
`define DEV_CLASS_MONITOR       8'h04
`define DEV_CLASS_PHY_IF        8'h05
`define DEV_CLASS_POWER         8'h06
`define DEV_CLASS_PRINTER       8'h07
`define DEV_CLASS_STORAGE       8'h08
`define DEV_CLASS_HUB           8'h09
`define DEV_CLASS_TMC           8'hFE
`define DEV_CLASS_VENDOR_CUSTOM 8'hFF


`define REQDIR_HOSTTODEVICE        (0 << 7)
`define REQDIR_DEVICETOHOST        (1 << 7)
`define REQTYPE_STANDARD           (0 << 5)
`define REQTYPE_CLASS              (1 << 5)
`define REQTYPE_VENDOR             (2 << 5)
`define REQREC_DEVICE              (0 << 0)
`define REQREC_INTERFACE           (1 << 0)
`define REQREC_ENDPOINT            (2 << 0)
`define REQREC_OTHER               (3 << 0)


`define ENDPOINT_DIR_MASK          (1 << 7)
`define ENDPOINT_DIR_IN            (1 << 7)
`define ENDPOINT_DIR_OUT           (0 << 7)
`define ENDPOINT_ADDR_MASK         (8'h7F)
`define ENDPOINT_TYPE_MASK         (8'h3)
`define ENDPOINT_TYPE_CONTROL      (0)
`define ENDPOINT_TYPE_ISO          (1)
`define ENDPOINT_TYPE_BULK         (2)
`define ENDPOINT_TYPE_INTERRUPT    (3)





`define USB_CTRL          8'h0
    `define USB_CTRL_TX_FLUSH                    8
    `define USB_CTRL_TX_FLUSH_SHIFT              8
    `define USB_CTRL_TX_FLUSH_MASK               8'h1

    `define USB_CTRL_PHY_DMPULLDOWN              7
    `define USB_CTRL_PHY_DMPULLDOWN_SHIFT        7
    `define USB_CTRL_PHY_DMPULLDOWN_MASK         8'h1

    `define USB_CTRL_PHY_DPPULLDOWN              6
    `define USB_CTRL_PHY_DPPULLDOWN_SHIFT        6
    `define USB_CTRL_PHY_DPPULLDOWN_MASK         8'h1

    `define USB_CTRL_PHY_TERMSELECT              5
    `define USB_CTRL_PHY_TERMSELECT_SHIFT        5
    `define USB_CTRL_PHY_TERMSELECT_MASK         8'h1

    `define USB_CTRL_PHY_XCVRSELECT_SHIFT        3
    `define USB_CTRL_PHY_XCVRSELECT_MASK         8'h3

    `define USB_CTRL_PHY_OPMODE_SHIFT            1
    `define USB_CTRL_PHY_OPMODE_MASK             8'h3

    `define USB_CTRL_ENABLE_SOF                  0
    `define USB_CTRL_ENABLE_SOF_SHIFT            0
    `define USB_CTRL_ENABLE_SOF_MASK             8'h1

`define USB_STATUS        8'h4
    `define USB_STATUS_SOF_TIME_SHIFT            16
    `define USB_STATUS_SOF_TIME_MASK             16'hffff

    `define USB_STATUS_RX_ERROR                  2
    `define USB_STATUS_RX_ERROR_SHIFT            2
    `define USB_STATUS_RX_ERROR_MASK             8'h1

    `define USB_STATUS_LINESTATE_BITS_SHIFT      0
    `define USB_STATUS_LINESTATE_BITS_MASK       8'h3

`define USB_IRQ_ACK       8'h8
    `define USB_IRQ_ACK_DEVICE_DETECT            3
    `define USB_IRQ_ACK_DEVICE_DETECT_SHIFT      3
    `define USB_IRQ_ACK_DEVICE_DETECT_MASK       8'h1

    `define USB_IRQ_ACK_ERR                      2
    `define USB_IRQ_ACK_ERR_SHIFT                2
    `define USB_IRQ_ACK_ERR_MASK                 8'h1

    `define USB_IRQ_ACK_DONE                     1
    `define USB_IRQ_ACK_DONE_SHIFT               1
    `define USB_IRQ_ACK_DONE_MASK                8'h1

    `define USB_IRQ_ACK_SOF                      0
    `define USB_IRQ_ACK_SOF_SHIFT                0
    `define USB_IRQ_ACK_SOF_MASK                 8'h1

`define USB_IRQ_STS       8'hc
    `define USB_IRQ_STS_DEVICE_DETECT            3
    `define USB_IRQ_STS_DEVICE_DETECT_SHIFT      3
    `define USB_IRQ_STS_DEVICE_DETECT_MASK       8'h1

    `define USB_IRQ_STS_ERR                      2
    `define USB_IRQ_STS_ERR_SHIFT                2
    `define USB_IRQ_STS_ERR_MASK                 8'h1

    `define USB_IRQ_STS_DONE                     1
    `define USB_IRQ_STS_DONE_SHIFT               1
    `define USB_IRQ_STS_DONE_MASK                8'h1

    `define USB_IRQ_STS_SOF                      0
    `define USB_IRQ_STS_SOF_SHIFT                0
    `define USB_IRQ_STS_SOF_MASK                 8'h1

`define USB_IRQ_MASK      8'h10
    `define USB_IRQ_MASK_DEVICE_DETECT           3
    `define USB_IRQ_MASK_DEVICE_DETECT_SHIFT     3
    `define USB_IRQ_MASK_DEVICE_DETECT_MASK      8'h1

    `define USB_IRQ_MASK_ERR                     2
    `define USB_IRQ_MASK_ERR_SHIFT               2
    `define USB_IRQ_MASK_ERR_MASK                8'h1

    `define USB_IRQ_MASK_DONE                    1
    `define USB_IRQ_MASK_DONE_SHIFT              1
    `define USB_IRQ_MASK_DONE_MASK               8'h1

    `define USB_IRQ_MASK_SOF                     0
    `define USB_IRQ_MASK_SOF_SHIFT               0
    `define USB_IRQ_MASK_SOF_MASK                8'h1

`define USB_XFER_DATA     8'h14
    `define USB_XFER_DATA_TX_LEN_SHIFT           0
    `define USB_XFER_DATA_TX_LEN_MASK            16'hffff

`define USB_XFER_TOKEN    8'h18
    `define USB_XFER_TOKEN_START                 31
    `define USB_XFER_TOKEN_START_SHIFT           31
    `define USB_XFER_TOKEN_START_MASK            8'h1

    `define USB_XFER_TOKEN_IN                    30
    `define USB_XFER_TOKEN_IN_SHIFT              30
    `define USB_XFER_TOKEN_IN_MASK               8'h1

    `define USB_XFER_TOKEN_ACK                   29
    `define USB_XFER_TOKEN_ACK_SHIFT             29
    `define USB_XFER_TOKEN_ACK_MASK              8'h1

    `define USB_XFER_TOKEN_PID_DATAX             28
    `define USB_XFER_TOKEN_PID_DATAX_SHIFT       28
    `define USB_XFER_TOKEN_PID_DATAX_MASK        8'h1

    `define USB_XFER_TOKEN_PID_BITS_SHIFT        16
    `define USB_XFER_TOKEN_PID_BITS_MASK         8'hff

    `define USB_XFER_TOKEN_DEV_ADDR_SHIFT        9
    `define USB_XFER_TOKEN_DEV_ADDR_MASK         8'h7f

    `define USB_XFER_TOKEN_EP_ADDR_SHIFT         5
    `define USB_XFER_TOKEN_EP_ADDR_MASK          8'hf

`define USB_RX_STAT       8'h1c
    `define USB_RX_STAT_START_PEND               31
    `define USB_RX_STAT_START_PEND_SHIFT         31
    `define USB_RX_STAT_START_PEND_MASK          8'h1

    `define USB_RX_STAT_CRC_ERR                  30
    `define USB_RX_STAT_CRC_ERR_SHIFT            30
    `define USB_RX_STAT_CRC_ERR_MASK             8'h1

    `define USB_RX_STAT_RESP_TIMEOUT             29
    `define USB_RX_STAT_RESP_TIMEOUT_SHIFT       29
    `define USB_RX_STAT_RESP_TIMEOUT_MASK        8'h1

    `define USB_RX_STAT_IDLE                     28
    `define USB_RX_STAT_IDLE_SHIFT               28
    `define USB_RX_STAT_IDLE_MASK                8'h1

    `define USB_RX_STAT_RESP_BITS_SHIFT          16
    `define USB_RX_STAT_RESP_BITS_MASK           8'hff

    `define USB_RX_STAT_COUNT_BITS_SHIFT         0
    `define USB_RX_STAT_COUNT_BITS_MASK          16'hffff

`define USB_WR_DATA       8'h20
    `define USB_WR_DATA_DATA_SHIFT               0
    `define USB_WR_DATA_DATA_MASK                8'hff

`define USB_RD_DATA       8'h20
    `define USB_RD_DATA_DATA_SHIFT               0
    `define USB_RD_DATA_DATA_MASK                8'hff


task usbhw_reg_write;
input [7:0] addr;
input [31:0] wdata;
begin
    `TOP.wb_user_core_write(`ADDR_SPACE_USB+addr,wdata);
end
endtask

task usbhw_reg_read;
input [7:0] addr;
output [31:0] rdata;
begin
    `TOP.wb_user_core_read(`ADDR_SPACE_USB+addr,rdata);
end
endtask

parameter   XMIT_BUF_SIZE       = 64;
parameter   RECV_BUF_SIZE       = 64;


reg [7:0]   XmitBuffer        [0 : XMIT_BUF_SIZE];
reg [7:0]   RecvBuffer        [0 : RECV_BUF_SIZE];




task usb_setup_packet;
input [7:0]  device_address; 
input [7:0]  request_type;
input [7:0]  request; 
input [15:0] value; 
input [15:0] index; 
input [15:0] length;
output       status;
reg   [7:0]  status;
integer idx;
begin
















    idx = 0;
    XmitBuffer[idx] = request_type;           idx = idx+1;
    XmitBuffer[idx] = request;                idx = idx+1;
    XmitBuffer[idx] = (value >> 0)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (value >> 8)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (index >> 0)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (index >> 8)  & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (length >> 0) & 8'hFF;  idx = idx+1;
    XmitBuffer[idx] = (length >> 8) & 8'hFF;  idx = idx+1;


    usbhw_transfer_out(`PID_SETUP, device_address, 0, 1, `PID_DATA0, idx,status);

end
endtask




task setup;
input [7:0] device_address;
input  [3:0] endpoint;
output [7:0]status;
begin


    usbhw_transfer_out(`PID_SETUP, device_address, endpoint, 1, `PID_DATA0, 8,status);

    usbhw_timer_sleep(50);
end
endtask

task printstatus;
   input [3:0] RecvdStatus;
   input [3:0] ExpStatus;
begin
  $display("");
  $display("    #######################################################");
  if(RecvdStatus !== ExpStatus ) begin
     -> `TOP.test_control.error_detected;
     $display("    ERROR: Expected Status and Observed Status didn't match at %0d", $time);
     if(ExpStatus==4'b0000)
        $display("    Expected Status is ACK at %0d", $time);
     else if(ExpStatus==4'b0001)
        $display("    Expected Status is NACK at %0d", $time);
     else if(ExpStatus==4'b0010)
        $display("    Expected Status is STALL at %0d", $time);
     else if(ExpStatus==4'b0011)
        $display("    Expected Status is TIMEOUT at %0d", $time);
     else if(ExpStatus==4'b0100)
        $display("    Expected Status is INVALID RESPONSE at %0d", $time);
     else if(ExpStatus==4'b0101)
        $display("    Expected Status is CRC ERROR at %0d", $time);
  end

  if(RecvdStatus==4'b0000)
     $display("    Received Status is ACK at %0d", $time);
  else if(RecvdStatus==4'b0001)
     $display("    Received Status is NACK at %0d", $time);
  else if(RecvdStatus==4'b0010)
     $display("    Received Status is STALL at %0d", $time);
  else if(RecvdStatus==4'b011)
     $display("    Received Status is TIMEOUT at %0d", $time);
  else if(RecvdStatus==4'b0100)
     $display("    Received Status is INVALID RESPONSE at %0d", $time);
  else if(RecvdStatus==4'b0101)
     $display("    Received Status is CRC ERROR at %0d", $time);
  $display("    #######################################################");
  $display("");
end
endtask



task usbhw_reset;
reg  bflag;
begin
    $display("HW: Applying USB Reset \n");

    usbhw_hub_reset;

    $display("HW: Reset Wait time Started \n");

    usbhw_timer_sleep(11);

    $display("HW: Reset Wait time Over \n");


    usbhw_hub_enable(0);
    usbhw_timer_sleep(3);

    $display("HW: Waiting for device insertion\n");


    usbhw_hub_device_detected(bflag);
    while (!bflag)begin
       usbhw_hub_device_detected(bflag);
    end

    $display("HW: Device detected\n");


    usbhw_hub_enable(1);
end
endtask












task usbhw_hub_reset;
reg [7:0] val;
begin
    $display("HW: Enter USB bus reset\n");


    val = 0;
    val = val | (0 << `USB_CTRL_PHY_XCVRSELECT_SHIFT);
    val = val | (0 << `USB_CTRL_PHY_TERMSELECT_SHIFT);
    val = val | (2 << `USB_CTRL_PHY_OPMODE_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DPPULLDOWN_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DMPULLDOWN_SHIFT);
    usbhw_reg_write(`USB_CTRL, val);

end
endtask






task usbhw_timer_sleep;
input [7:0] ResetTime;
reg [7:0] tskResetTime;
reg [7:0] tskResetTimeCounter;
begin
   tskResetTimeCounter = 0;
   tskResetTime = ResetTime;
   forever @(posedge `TOP.usb_48mhz_clk) begin
      tskResetTimeCounter = tskResetTimeCounter + 1'b1;
      if (tskResetTimeCounter > tskResetTime) begin
            @(posedge `TOP.usb_48mhz_clk);
            @(posedge `TOP.usb_48mhz_clk);
            disable usbhw_timer_sleep;
      end
   end
end
endtask 






task usbhw_hub_enable;
input enable_sof;
reg [7:0] val;
begin
    $display("HW: Enable root hub\n");


    val = 0;
    val = val | (1 << `USB_CTRL_PHY_XCVRSELECT_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_TERMSELECT_SHIFT);
    val = val | (0 << `USB_CTRL_PHY_OPMODE_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DPPULLDOWN_SHIFT);
    val = val | (1 << `USB_CTRL_PHY_DMPULLDOWN_SHIFT);
    val = val | (1 << `USB_CTRL_TX_FLUSH_SHIFT);


    if (enable_sof)
        val = val | (1 << `USB_CTRL_ENABLE_SOF_SHIFT);

    usbhw_reg_write(`USB_CTRL, val);
end
endtask





task usbhw_hub_device_detected;
output bflag;
reg _usb_fs_device;
reg [31:0] status;
reg    bflag;
begin

    usbhw_reg_read(`USB_STATUS,status);
    status = status >> `USB_STATUS_LINESTATE_BITS_SHIFT;
    status = status & `USB_STATUS_LINESTATE_BITS_MASK;



    _usb_fs_device = (status & 1);
    if(status != 1) begin
       $display("ERROR: USB Pull Up Status is not 1, Only Full Seed Supported");
    end else begin
       $display("STATUS: USB Full Speed Detected");
    end

    bflag = (status != 0);
end
endtask

task status_IN;
input [7:0] device_addr;
input [3:0] endpoint;
output [7:0] exit_code;
reg    [7:0] exit_code;
reg   [7:0] status;
reg    [7:0] rx_count;
begin
  usbhw_transfer_in(`PID_IN, device_addr, endpoint, status,exit_code,rx_count);
end
endtask

task status_OUT;
input [7:0] device_addr;
input [3:0] endpoint;
output [7:0] status;
begin
  usbhw_transfer_out(`PID_OUT, device_addr, endpoint, 1, `PID_OUT, 0,status);
end
endtask

task control_OUT;
input [7:0] device_addr;
input [3:0] endpoint;
input [7:0] ByteCount;
output [7:0] status;
begin
  usbhw_transfer_out(`PID_OUT, device_addr, endpoint, 1, `PID_DATA1, ByteCount,status);
end
endtask

task control_IN;
input [7:0] device_addr;
input [3:0] endpoint;
input [7:0] ByteCount;
output [7:0] exit_code;
reg    [7:0] exit_code;
reg    [7:0] status;
reg    [7:0] rx_count;
begin
  usbhw_transfer_in(`PID_IN, device_addr, endpoint, status,exit_code,rx_count);
end
endtask

task SetAddress;
  input [6:0] address;
begin
    XmitBuffer[0] = 8'b0000_0000;
    XmitBuffer[1] = 8'b0000_0101;
    XmitBuffer[2] = {1'b0, address};
    XmitBuffer[3] = 8'b0000_0000;
    XmitBuffer[4] = 8'b0000_0000;
    XmitBuffer[5] = 8'b0000_0000;
    XmitBuffer[6] = 8'b0000_0000;
    XmitBuffer[7] = 8'b0000_0000;
end
endtask


task SetConfiguration;
  input [1:0] cfg_val;
begin
    XmitBuffer[0] = 8'b0000_0000;
    XmitBuffer[1] = 8'b0000_1001;
    XmitBuffer[2] = {6'b000_000, cfg_val};
    XmitBuffer[3] = 8'b0000_0000;
    XmitBuffer[4] = 8'b0000_0000;
    XmitBuffer[5] = 8'b0000_0000;
    XmitBuffer[6] = 8'b0000_0000;
    XmitBuffer[7] = 8'b0000_0000;
end
endtask

task VenRegWordWr;
  input [6:0] address;
  input [31:0] reg_address;
  input [31:0] dataword;
  reg   [7:0]  Status;
begin
   XmitBuffer[0] = 8'b0100_0000;
   XmitBuffer[1] = 8'b0001_0000;
   XmitBuffer[2] = reg_address[31:24];
   XmitBuffer[3] = reg_address[23:16];
   XmitBuffer[4] = reg_address[15:8];
   XmitBuffer[5] = reg_address[7:0];
   XmitBuffer[6] = 8'b0000_0100;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);

   XmitBuffer[0] = dataword[31:24];
   XmitBuffer[1] = dataword[23:16];
   XmitBuffer[2] = dataword[15:8];
   XmitBuffer[3] = dataword[7:0];

  control_OUT(address, 4'h0, 4, Status);
  status_IN (address, 4'h0, Status);
end
endtask

task VenRegWordRd;
  input [6:0] address;
  input [31:0] reg_address;
  output [31:0] dataword;
  reg  [31:0] ByteCount;
  reg  [7:0]  Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = 8'b0001_0001;
   XmitBuffer[2] = reg_address[31:24];
   XmitBuffer[3] = reg_address[23:16];
   XmitBuffer[4] = reg_address[15:8];
   XmitBuffer[5] = reg_address[7:0];
   XmitBuffer[6] = 8'b0000_0100;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
    dataword[7:0]      = RecvBuffer[3];
    dataword[15:8]     = RecvBuffer[2];
    dataword[23:16]    = RecvBuffer[1];
    dataword[31:24]    = RecvBuffer[0];
    dump_recv_buffer(ByteCount);

   status_OUT (address, 4'h0, Status);
end
endtask

task VenRegWordRdCmp;
  input [6:0] address;
  input [31:0] reg_address;
  input [31:0] dataword;
  reg   [31:0] ByteCount;
  reg   [31:0] ReadData;
  reg    [7:0] Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = 8'b0001_0001;
   XmitBuffer[2] = reg_address[31:24];
   XmitBuffer[3] = reg_address[23:16];
   XmitBuffer[4] = reg_address[15:8];
   XmitBuffer[5] = reg_address[7:0];
   XmitBuffer[6] = 8'b0000_0100;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if ((RecvBuffer[3] !== dataword[7:0]) || (RecvBuffer[2] !== dataword[15:8]) 
         || (RecvBuffer[1] !== dataword[23:16]) || (RecvBuffer[0] !== dataword[31:24]))
    begin
      -> `TOP.test_control.error_detected;
       $display( "usb_agent check: ERROR: Register Read Byte Mismatch !!! Address: %x Exp: %x ; Rxd: %x",reg_address,dataword[31:0], {RecvBuffer[0],RecvBuffer[1], RecvBuffer[2],RecvBuffer[3]} );
       dump_recv_buffer(ByteCount);
    end else begin
       $display( "usb_agent check: STATUS: Register Read Byte Match !!! Address: %x ; Rxd: %x",reg_address,{RecvBuffer[0],RecvBuffer[1], RecvBuffer[2],RecvBuffer[3]} );

    end

   status_OUT (address, 4'h0, Status);
end
endtask
task VenRegHalfWordRd;
  input [6:0] address;
  input [21:0] reg_address;
  input [15:0] dataword;
  output [31:0] ByteCount;
  reg    [7:0]  Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = 8'b0000_0010;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if ((RecvBuffer[0] !== dataword[7:0]) || (RecvBuffer[1] !== dataword[15:8])) 
    begin
       -> `TOP.test_control.error_detected;
       $display( "usb_agent check: Register Read Byte Mismatch !!!");
       dump_recv_buffer(ByteCount);
    end
   status_OUT (address, 4'h0, Status);
end
endtask

task VenRegByteRd;
  input [6:0] address;
  input [21:0] reg_address;
  input [7:0] dataword;
  output [31:0] ByteCount;
  reg     [7:0] Status;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = 8'b0000_0001;
   XmitBuffer[7] = 8'b0000_0000;

   setup (address, 4'h0, Status);
   control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if (Status != `PID_ACK)
         control_IN(address, 4'h0, ByteCount, Status);
   if ((RecvBuffer[0] !== dataword[7:0]))
    begin
       -> `TOP.test_control.error_detected;
       $display( "usb_agent check: Register Read Byte Mismatch !!!");
       dump_recv_buffer(ByteCount);
    end
   status_OUT (address, 4'h0, Status);
end
endtask

task VenRegWr;
  input [21:0] reg_address;
  input [2:0]  length;
begin
   XmitBuffer[0] = 8'b0100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = {5'b0000_0,length};
   XmitBuffer[7] = 8'b0000_0000;   

end
endtask

task VenRegRd;
  input [21:0] reg_address;
  input [2:0]  length;
begin
   XmitBuffer[0] = 8'b1100_0000;
   XmitBuffer[1] = {2'b00,reg_address[21:16]};
   XmitBuffer[2] = reg_address[7:0];
   XmitBuffer[3] = reg_address[15:8];
   XmitBuffer[4] = 8'b0000_0000;
   XmitBuffer[5] = 8'b0000_0000;
   XmitBuffer[6] = {5'b0000_0,length};
   XmitBuffer[7] = 8'b0000_0000;   
end
endtask

task VenRegWrWordData;
  input [7:0] Byte0;
  input [7:0] Byte1;
  input [7:0] Byte2;
  input [7:0] Byte3;
begin
   XmitBuffer[0] = Byte0;        
   XmitBuffer[1] = Byte1;
   XmitBuffer[2] = Byte2;
   XmitBuffer[3] = Byte3;
end
endtask

task VenRegWrHWordData;
  input [7:0] Byte0;
  input [7:0] Byte1;
begin
   XmitBuffer[0] = Byte0;        
   XmitBuffer[1] = Byte1;
end
endtask

task VenRegWrByteData;
  input [7:0] Byte0;
begin
   XmitBuffer[0] = Byte0;        
end
endtask

task dump_recv_buffer;
  input [31:0] NumBytes;
  integer i;
begin
  for(i=0; i < NumBytes; i=i+1)
    $display("RecvBuffer[%0d]  = %b  : %0d", i, RecvBuffer[i], RecvBuffer[i]);
end
endtask





task usbhw_transfer_out;
input [7:0]   pid;
input [7:0]   device_addr;
input [3:0]   endpoint; 
input         handshake; 
input [7:0]   request; 
input  [7:0]  tx_length;
output [7:0]  exit_code;

reg    [7:0]  exit_code;

reg  [31:0] tdata;
integer     l;
reg [31:0]  token;
reg [31:0]  ctrl;
reg [31:0]  resp;
reg [31:0]  status;
reg [31:0]  status_chk;
begin





    for (l=0;l<tx_length;l = l + 1) begin
        tdata = XmitBuffer[l];

        usbhw_reg_write(`USB_WR_DATA, tdata);
    end


    usbhw_reg_write(`USB_XFER_DATA, tx_length);


    ctrl = (1 << `USB_XFER_TOKEN_START_SHIFT);


    ctrl= ctrl | (handshake ? (1 << `USB_XFER_TOKEN_ACK_SHIFT) : 0);

    ctrl= ctrl | ((request == `PID_DATA1) ? (1 << `USB_XFER_TOKEN_PID_DATAX_SHIFT) : (0 << `USB_XFER_TOKEN_PID_DATAX_SHIFT));


    token = (pid<<`USB_XFER_TOKEN_PID_BITS_SHIFT) | (device_addr << `USB_XFER_TOKEN_DEV_ADDR_SHIFT) | (endpoint << `USB_XFER_TOKEN_EP_ADDR_SHIFT);
    usbhw_reg_write(`USB_XFER_TOKEN, token | ctrl);


    usbhw_reg_read(`USB_RX_STAT,status) ;
    status_chk = status & (1 << `USB_RX_STAT_START_PEND_SHIFT);
    while (status_chk) begin
        usbhw_reg_read(`USB_RX_STAT,status) ;
        status_chk = status & (1 << `USB_RX_STAT_START_PEND_SHIFT);
    end


    if (!handshake) begin
	exit_code = `USB_RES_OK;
    end


    usbhw_reg_read(`USB_RX_STAT,status) ;
    status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT) ;
    while (!(status_chk)) begin
       usbhw_reg_read(`USB_RX_STAT,status) ;
       status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT) ;
    end

    $display("USB RESPONSE: %x",status);

    if (status & (1 << `USB_RX_STAT_RESP_TIMEOUT_SHIFT)) begin
       $display("  USB TIMEOUT\n");
       $display("USB ERROR: OUT timeout\n");
       exit_code = `USB_RES_TIMEOUT;
    end


    resp = ((status >> `USB_RX_STAT_RESP_BITS_SHIFT) & `USB_RX_STAT_RESP_BITS_MASK);
    if (resp == `PID_ACK) begin
       $display("USB STATUS: ACK\n");
       exit_code = `USB_RES_OK;
    end else if (resp == `PID_NAK) begin
       $display("USB STATUS: NAK\n");
       exit_code = `USB_RES_NAK;
    end else if (resp == `PID_STALL) begin
       $display("USB STATUS:  STALL\n");
       $display("USB ERROR:  OUT STALL\n");
       exit_code = `USB_RES_STALL;
    end else begin
       $display("USB ERROR: Unknown OUT response (%02x)\n", resp);


       exit_code = `USB_RES_STALL;
    end
end
endtask




task usbhw_transfer_in;
input [7:0]    pid; 
input [7:0]    device_addr; 
input [7:0]    endpoint; 
output [7:0]   response; 
output [7:0]   exit_code;
output [7:0]   rx_count;

reg  [7:0]     exit_code;
reg  [7:0]     response; 
reg  [7:0]     rx_length;
integer l;
reg  [7:0]     rx_count;
reg [31:0]     token;
reg [31:0]     data;
reg [31:0]     status;
reg [31:0]     status_chk;
begin




    usbhw_reg_write(`USB_XFER_DATA, 0);


    token = (pid<<`USB_XFER_TOKEN_PID_BITS_SHIFT) | (device_addr << `USB_XFER_TOKEN_DEV_ADDR_SHIFT) | (endpoint << `USB_XFER_TOKEN_EP_ADDR_SHIFT);
    token= token |(1 << `USB_XFER_TOKEN_START_SHIFT);
    token= token | (1 << `USB_XFER_TOKEN_IN_SHIFT);
    token= token | (1 << `USB_XFER_TOKEN_ACK_SHIFT);

    usbhw_reg_write(`USB_XFER_TOKEN, token);

    status_chk = status & (1 << `USB_RX_STAT_START_PEND);
    while (status_chk) begin
       usbhw_reg_read(`USB_RX_STAT,status);
       status_chk = status & (1 << `USB_RX_STAT_START_PEND);
    end


    usbhw_reg_read(`USB_RX_STAT,status); 
    status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT);
    while (!(status_chk)) begin
       usbhw_reg_read(`USB_RX_STAT,status); 
       status_chk = status & (1 << `USB_RX_STAT_IDLE_SHIFT);
    end

    if (status & (1 << `USB_RX_STAT_CRC_ERR_SHIFT)) begin
       $display("USB: CRC ERROR\n");
       exit_code = `USB_RES_TIMEOUT;
    end else if (status & (1 << `USB_RX_STAT_RESP_TIMEOUT_SHIFT)) begin
       $display("USB: IN timeout\n");
       exit_code = `USB_RES_TIMEOUT;
    end else begin


        response = ((status >> `USB_RX_STAT_RESP_BITS_SHIFT) & `USB_RX_STAT_RESP_BITS_MASK);

        if (response == `PID_NAK) begin
           $display("USB NAK RECEIVED \n");
           exit_code = `USB_RES_NAK;
        end else if (response == `PID_STALL) begin
           $display("USB: IN STALL\n");
           exit_code = `USB_RES_STALL;
        end else begin


           if (status & (1 << `USB_RX_STAT_CRC_ERR_SHIFT)) begin
                $display("USB: CRC Error\n");
                exit_code = `USB_RES_STALL;
           end else begin


                rx_count = ((status >> `USB_RX_STAT_COUNT_BITS_SHIFT) & `USB_RX_STAT_COUNT_BITS_MASK);








                if(rx_length >= rx_count)
                    $display("USB ERROR Difference in rx len:%d and Rx Data Count: %d",rx_length,rx_count);
   
                for (l=0;l<rx_count;l=l+1) begin
                    usbhw_reg_read(`USB_RD_DATA,data);

                    RecvBuffer[l] = data;
                end
		exit_code = `USB_RES_OK;
	   end
	end
    end
end
endtask

endmodule