blob: c2665679f45d06005292f883fbd0fa4a4af8c5f0 [file] [log] [blame]
`define TOP user_usb_tb
module usb_agent;
//-----------------------------------------------------------------
// Defines:
//-----------------------------------------------------------------
// Response values
`define USB_RES_OK 8'h0
`define USB_RES_NAK 8'hFF
`define USB_RES_STALL 8'hFE
`define USB_RES_TIMEOUT 8'hFD
// USB PID values
`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
// Standard requests (via SETUP packets)
`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
// Descriptor types
`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
// Device class
`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
// Device Requests (bmRequestType)
`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)
// Endpoints
`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)
//-----------------------------------------------------------------
// Defines:
//-----------------------------------------------------------------
`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; // Xmitbuffer size
parameter RECV_BUF_SIZE = 64; // Recvbuffer size
reg [7:0] XmitBuffer [0 : XMIT_BUF_SIZE]; // Xmit buffer
reg [7:0] RecvBuffer [0 : RECV_BUF_SIZE]; // Recv buffer
//-----------------------------------------------------------------
// usb_setup_packet: Create & send SETUP packet
//-----------------------------------------------------------------
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
// bmRequestType:
// D7 Data Phase Transfer Direction
// 0 = Host to Device
// 1 = Device to Host
// D6..5 Type
// 0 = Standard
// 1 = Class
// 2 = Vendor
// 3 = Reserved
// D4..0 Recipient
// 0 = Device
// 1 = Interface
// 2 = Endpoint
// 3 = Other
//
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;
// Send SETUP token + DATA0 (always DATA0)
usbhw_transfer_out(`PID_SETUP, device_address, 0, 1, `PID_DATA0, idx,status);
end
endtask
//-----------------------------------------------------------------
// SetAddress: Set device address
//-----------------------------------------------------------------
task setup;
input [7:0] device_address;
input [3:0] endpoint;
output [7:0]status;
begin
//$display("USB: Set device address %d\n", device_address);
// Send SETUP token + DATA0 (always DATA0)
usbhw_transfer_out(`PID_SETUP, device_address, endpoint, 1, `PID_DATA0, 8,status);
// Device has 50mS to apply the address
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
//-----------------------------------------------------------------
// usbhw_reset: Perform USB reset
//-----------------------------------------------------------------
task usbhw_reset;
reg bflag;
begin
$display("HW: Applying USB Reset \n");
// Assert SE0 / reset
usbhw_hub_reset;
$display("HW: Reset Wait time Started \n");
// Wait for some time
usbhw_timer_sleep(11);
$display("HW: Reset Wait time Over \n");
// Stop asserting SE0, set data lines to Hi-Z
usbhw_hub_enable(0);
usbhw_timer_sleep(3);
$display("HW: Waiting for device insertion\n");
// Wait for device detect
usbhw_hub_device_detected(bflag);
while (!bflag)begin
usbhw_hub_device_detected(bflag);
end
$display("HW: Device detected\n");
// Enable SOF
usbhw_hub_enable(1);
end
endtask
//-----------------------------------------------------------------
// usbhw_hub_reset: Put bus into SE0 state (reset)
//-----------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////////
//
// SendReset : asserts a SE0 on the USB for the number of bit times specified
// by ResetTime.
// Input : ResetTime, number of bit times for which to drive a reset on
// the USB
//
////////////////////////////////////////////////////////////////////////////////
task usbhw_hub_reset;
reg [7:0] val;
begin
$display("HW: Enter USB bus reset\n");
// Power-up / SE0
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
//-----------------------------------------------------------------
// usbhw_timer_sleep: Perform Sleep
//-----------------------------------------------------------------
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
//-----------------------------------------------------------------
// usbhw_hub_enable: Enable root hub (drive data lines to HiZ)
// and optionally start SOF periods
//-----------------------------------------------------------------
task usbhw_hub_enable;
input enable_sof;
reg [7:0] val;
begin
$display("HW: Enable root hub\n");
// Host Full Speed
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);
// Enable SOF
if (enable_sof)
val = val | (1 << `USB_CTRL_ENABLE_SOF_SHIFT);
usbhw_reg_write(`USB_CTRL, val);
end
endtask
//-----------------------------------------------------------------
// usbhw_hub_device_detected: Detect device inserted
//-----------------------------------------------------------------
task usbhw_hub_device_detected;
output bflag;
reg _usb_fs_device;
reg [31:0] status;
reg bflag;
begin
// Get line state
usbhw_reg_read(`USB_STATUS,status);
status = status >> `USB_STATUS_LINESTATE_BITS_SHIFT;
status = status & `USB_STATUS_LINESTATE_BITS_MASK;
// FS: D+ pulled high
// LS: D- pulled high
_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; // SetAddress
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; // Set Configuration
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
//-----------------------------------------------------------------
// usbhw_transfer_out: Send token then some DATA to the device
//-----------------------------------------------------------------
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
//$display("USB TOKEN: %s", (pid == `PID_SETUP) ? "SETUP" : (pid == `PID_DATA0) ? "DATA0": (pid == `PID_DATA1) ? "DATA1" : (pid == `PID_IN) ? "IN" : "OUT");
//$display("USB DEV %d EP %d\n", device_addr, endpoint);
// Load DATAx transfer into address 0+
//$display(" USB Tx: %02x", request);
for (l=0;l<tx_length;l = l + 1) begin
tdata = XmitBuffer[l];
//$display("USB TX DATA %02x", tdata);
usbhw_reg_write(`USB_WR_DATA, tdata);
end
// Transfer data length
usbhw_reg_write(`USB_XFER_DATA, tx_length);
// Configure transfer for DATAx portion
ctrl = (1 << `USB_XFER_TOKEN_START_SHIFT);
// Wait for response or timeout
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));
// Setup token details (don't start transfer yet)
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);
// Wait for Tx to start
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
// No handshaking? We are done
if (!handshake) begin
exit_code = `USB_RES_OK;
end
// Wait for idle
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
// Check for NAK / STALL
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);
// Unknown
exit_code = `USB_RES_STALL;
end
end
endtask
//-----------------------------------------------------------------
// usbhw_transfer_in: Perform IN request and expect DATA from device
//-----------------------------------------------------------------
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
//$display("USB TOKEN: %s", (pid == `PID_SETUP) ? "SETUP" : (pid == `PID_DATA0) ? "DATA0": (pid == `PID_DATA1) ? "DATA1" : (pid == `PID_IN) ? "IN" : "OUT");
//$display("USB DEV %d EP %d\n", device_addr, endpoint);
// No data to send
usbhw_reg_write(`USB_XFER_DATA, 0);
// Configure transfer
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);
//$display("USB TOKEN CONFIG : %x",token);
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
// Wait for rx idle
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
// Check for NAK / STALL
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
// Check CRC is ok
if (status & (1 << `USB_RX_STAT_CRC_ERR_SHIFT)) begin
$display("USB: CRC Error\n");
exit_code = `USB_RES_STALL;
end else begin
// How much data was actually received?
rx_count = ((status >> `USB_RX_STAT_COUNT_BITS_SHIFT) & `USB_RX_STAT_COUNT_BITS_MASK);
//$display(" Rx %d (PID=%x):\n", rx_count, response);
// Assert that user buffer is big enough for the response.
// NOTE: It's not critical to do this, but we can't easily check CRCs without
// reading the whole response into a buffer.
// Hitting this condition may point towards issues with higher level protocol
// implementation...
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);
//$display(" USB RX Cnt: %d Data: %02x", l, data);
RecvBuffer[l] = data;
end
exit_code = `USB_RES_OK;
end
end
end
end
endtask
endmodule