URL
https://opencores.org/ocsvn/usb2uart/usb2uart/trunk
Subversion Repositories usb2uart
[/] [usb2uart/] [trunk/] [verify/] [agents/] [usb/] [usb_agent.v] - Rev 8
Compare with Previous | Blame | View Log
`timescale 1 ns/ 1 ns module usb_agent ( dpls, dmns ); inout dpls, dmns; wire [24:0] ControlPkt; assign dpls = 1'bz; assign dmns = 1'bz; pullup(dpls); pulldown(dmns); // ------------------------------ // Module Instantiations.--------------- // ------------------------------ // a. Host Bus Model Instantiation. host_usb_bfm bfm_inst( .DPLS( dpls ), .DMNS( dmns ), .ControlPkt( ControlPkt) ); endmodule module host_usb_bfm( DPLS, DMNS, ControlPkt ); inout DPLS; inout DMNS; output [24:0] ControlPkt; wire DPLS; wire DMNS; reg zDPLS; // this register is driven in host_usb_drvr.v reg zDMNS; // this register is driven in host_usb_drvr.v wire clk; // clock // encoder signals reg enc_enbl; // signal to enable encoder block reg enc_reset_n; // signal to reset encoder block reg [7:0] enc_data_in; // byte wide data being pumped into the encoder wire enc_count_out; // wire for encoder count_out signal wire enc_data_out_valid; // wire for encoder data_out_valid signal reg enc_last_byte; wire [3:0] enc_bit_count_out; // decoder signals reg dec_enbl; // signal to enable decoder block reg dec_reset_n; // signal to reset decoder block wire dec_ser_data_rdy; // signal to indicate serial data is ready wire dec_par_data_rdy; // signal to indicate parallel data is ready wire [7:0] dec_par_data_out; // parallel data out from decoder wire [31:0] dec_recv_bit_count; // gives the number of bits received so far wire dec_bit_stuff_err; // goes high if there is a bit stuff error in // the present data stream // dpll signals reg clk48; reg clk6; reg dpll_reset_n; wire dpll_clk; reg rec_clk; wire clk4x; // Jitter control registers integer tmpJitterPeriod; integer tmpJitterCount; // clock related registers reg HSClkComp; // compensation when generating the 4x clock reg HSClkCompToggle; //////////////////////////////////////////////// // // // Added to accomodate 1 ms slots and files // // // //////////////////////////////////////////////// // reg [24:0] ControlPkt; // Control Packet format; // [0] : 1 - Assert BufOk/0 - Donot assert BufOk. // [1] : 1 - Create BufOk Error/0 - Donot Create BufOk Error. // [9:2] : Start Byte for In Transfers. // [10] : 1 - Create a 4 Clock Protocol violation/0 - donot create vio. // [20:11]: Errors after num transfers. // [21] : Stalled or Not. // [22] : Check for data on Application Bus during Writes. // [23] : Check for the Hshk on the Application Bus. // [24] : If check for hshkis true, 1'b1 = XfrAck, 1'b0 = XfrNack. // integer ByteCount; // integer Status ; reg [6:0] dutAddr; reg sofOnFlag ; integer sofPeriod ; reg interruptOnFlag ; reg interruptRequest ; integer interruptTimer ; integer interruptPeriod ; reg controlRequest ; reg controlGrant ; reg bulkInOnFlag ; reg bulkOutOnFlag ; parameter DumpToFile = 1; parameter IN_OUT_BUF_SIZE = 2048, // outgoing buffer data size IN_OUT_BUF_PTR_SIZE = 12, // number of bits in out buff pointer XMIT_BUF_SIZE = 1028, // Xmitbuffer size RECV_BUF_SIZE = 1028; // Recvbuffer size parameter OUT_TOKEN = 4'b0001, IN_TOKEN = 4'b1001, SOF_TOKEN = 4'b0101, SETUP_TOKEN = 4'b1101, DATA0 = 4'b0011, DATA1 = 4'b1011, ACK = 4'b0010, NAK = 4'b1010, STALL = 4'b1110, PREAMBLE = 4'b1100; parameter GET_CONFIGURATION = 01, // Standard Request Codes for end points GET_DESCRIPTOR = 02, GET_INTERFACE = 03, GET_MAX_PACKET = 04, GET_STATUS = 05, SET_ADDRESS = 06, SET_CONFIGURATION = 07, SET_DESCRIPTOR = 08, SET_IDLE = 09, SET_INTERFACE = 10, SET_MAX_PACKET = 11, SET_REMOTE_WAKEUP = 12, SET_STATUS = 13; parameter DEVICE = 1, // Descriptor Types CONFIGURATION = 2, STRING = 3, INTERFACE = 4, ENDPOINT = 5; parameter GET_HUB_STATUS = 0, // Hub class request codes GET_PORT_STATUS = 0, CLEAR_FEATURE = 1, GET_STATE = 2, SET_FEATURE = 3, // reserved for future use 4-5 GET_HUB_DESCRIPTOR = 6, SET_HUB_DESCRIPTOR = 7; parameter C_HUB_LOCAL_POWER = 00, // Hub class feature selectors C_HUB_OVER_CURRENT = 01, PORT_CONNECTION = 00, PORT_ENABLE = 01, PORT_SUSPEND = 02, PORT_OVER_CURRENT = 03, PORT_RESET = 04, PORT_POWER = 08, PORT_LOW_SPEED = 09, C_PORT_CONNECTION = 16, C_PORT_ENABLE = 17, C_PORT_SUSPEND = 18, C_PORT_OVER_CURRENT = 19, C_PORT_RESET = 20; parameter true = 1'b1, True = 1'b1, TRUE = 1'b1, false = 1'b0, False = 1'b0, FALSE = 1'b0; parameter HIGH_SPEED = 1'b1, LOW_SPEED = 1'b0; parameter J = 2'b10, // high speed idle state {DPLS, DMNS} K = 2'b01, // low speed idle state {DPLS, DMNS} SE0 = 2'b00, // single ended zero {DPLS, DMNS} SE1 = 2'b11; // single ended 1 {DPLS, DMNS} parameter MAX_CNTRL_INTERLEAVE= 6; // number of control transactions that can // interleaved parameter NUM_ENDPT_FILES = 12; // number of transmit files associtated // with endpoints parameter READ = 2'b10; parameter WRITE = 2'b11; parameter BINARY = 1'b0; parameter HEX = 1'b1; parameter XMIT_BUF = 4'b0000; parameter OUT_BUFF = 4'b0001; parameter NumCharsInFileName = 20; // number of characters in a file name parameter CharByte = 8; // number of bits for a character parameter MaxFileSize = 9 * 1024; // 9k file size reg [7:0] in_out_buf [0 : IN_OUT_BUF_SIZE - 1]; reg [11:0] in_out_buf_ptr; reg [7:0] XmitBuffer [0 : XMIT_BUF_SIZE]; // Xmit buffer reg [7:0] RecvBuffer [0 : RECV_BUF_SIZE]; // Recv buffer reg [10:0] FrameNumber; // frame number reg [15:0] InDataToggle [127:0]; // set\unset Data0/Data1 for data Xfers reg [15:0] OutDataToggle [127:0]; // set\unset Data0/Data1 for data Xfers reg TimeOut; // register to specify timeout integer TimeOutVal; // value to specify for how many bit times // to wait for before time out reg [31:0] ResponseLatency; // turnaround time for the host before // responding reg IsoHeadGen; // specifies if a header is generated for an // isochronous transfer or not reg GenCrc16Err; // specifies if a crc error is to be generated or not reg [15:0] Crc16ErrMask; // a particular crc bit is inverted according to the // bit in the Mask is high reg GenCrc5Err; // specifies if a crc error is to be generated or not reg [4:0] Crc5ErrMask; // a particular crc bit is inverted according to the // bit in the Mask is high reg ReportResults; // reports results to a file reg [NumCharsInFileName * CharByte : 1] ResultsFile; // reports file name integer ResultsFp; // filepointer for reults file reg ReportErrors; integer PulseWidth; // PulseWidth of USB clock reg SyncField; // specifies if a correct/incorrect sync field is to // be sent reg [31:0] SyncLevel; // at which point in a task to corrupt the SyncField reg [31:0] SetSyncLevel; // set this value before calling SendData reg [7:0] SyncFieldMask; // specifies how the sync field is to be corrupted reg GenSE0Error; // generate a SE0 error reg [31:0] SE0BitTimes; // generate SE0 for this many bit times reg [31:0] SE0ErrorLevel; // = 0 : generates a SE0 error after a sync field // = 1 : generates a SE0 error after data // = 2 : generates a SE0 error after a handshake reg HshkPidIntegrity; // specifies if correct ACKs should be sent reg [7:0] HshkPidIntegrityMask; // Mask according to which ACK's are corrupted reg BitStuffErr; integer RespTimeOutVal; // bit times to wait for when no response is to be // sent integer tmpCounter; // a scratch variable to be used any where event DoesNotOccur; // an event which will not be triggered to // used to suspend threads reg [31:0] StartTime; // start time of a transaction reg [31:0] StopTime; // stop time of a transaction reg [31:0] SE0StartTime; // start time of a single ended 0 reg [31:0] SE0StopTime; // stop of a single ended 0 reg [31:0] SelfName; // 4 byte wide register to differentiate between // instantiations // info about a current control transaction reg [1:0] CntrlTransType [1 : MAX_CNTRL_INTERLEAVE]; // type of control transaction // 00 no control transaction in progress // 01 control_rd transaction in progress // 11 control_wr transaction in progress reg [6:0] CntrlTransAddr [1 : MAX_CNTRL_INTERLEAVE]; // address to which a cntrl trans is in progress reg [3:0] CntrlTransEndP [1 : MAX_CNTRL_INTERLEAVE]; // End Pnt to which a cntrl trans is in progress reg [15:0] CntrlTransDlen [1 : MAX_CNTRL_INTERLEAVE]; // data length for this control transaction reg [NumCharsInFileName * CharByte : 1] SendDataFileName; // File from which data to be sent is taken from, format is 1 byte per line // in hex format reg [NumCharsInFileName * CharByte : 1] RecvDataFileName; // File to which received data is logged to, format is 1 byte per line in // hex format reg [NumCharsInFileName * CharByte : 1] ErrorFileName; // file name to report errors reg [31:0] RecvDataFp; // file pointer to RecvDataFileName reg [31:0] SendDataOfst; // offset into SendDataFileName reg [31:0] ErrorFileFp; // file pointer of the error file reg [NumCharsInFileName * CharByte : 1] EndPtFileName [1 : NUM_ENDPT_FILES]; // array to store file names associated with end points reg [1:0] EndPtFileMode [1 : NUM_ENDPT_FILES]; // array to store read/write mode info for each file reg [31:0] EndPtFp [1 : NUM_ENDPT_FILES]; reg [10:0] EndPtFileInfo [1 : NUM_ENDPT_FILES]; reg [31:0] EndPtFileOfst [1 : NUM_ENDPT_FILES]; // offset into the file if it is in write mode reg Debug; // debugging messages are turned on if set to true reg GenDataPidErr; // generates a data pid integrity error reg [7:0] DataPidErrMask; // error mask for generating reg GenTokenErr; // generates a token pid integrity error reg [7:0] TokenErrMask; // token error mask reg DeviceSpeed; // low speed or high speed reg GenByteBoundary; // generate a byte boundary error reg SendPreamble; // registers to log simulation results reg [31:0] NumBulkInTrans; // number of bulk in transactions reg [31:0] NumSucBulkInTrans; // number of successful bulk in transctions reg [31:0] NumBulkOutTrans; // number of bulk out transactions reg [31:0] NumSucBulkOutTrans; // number of successful bulk out transactions reg [31:0] NumIsoInTrans; // number of iso in transactions reg [31:0] NumSucIsoInTrans; // number of successful iso in transactions reg [31:0] NumIsoOutTrans; // number of iso out transactions reg [31:0] NumSOF; // number of SOF's sent reg [31:0] NumCntrlRdTrans; // number of control reads reg [31:0] NumSucCntrlRdTrans; // number of successful control reads reg [31:0] NumCntrlWrTrans; // number of control writes reg [31:0] NumSucCntrlWrTrans; // number of successful control writes reg [31:0] NumIntrptTrans; // number of interrupt transactions reg [31:0] NumSucIntrptTrans; // number of successful interrupt transactions reg [31:0] NumIntrOutTrans; // number of interrupt out transactions reg [31:0] NumSucIntrOutTrans; // number of successful interrupt out transactions reg [31:0] NumResets; // number of resets // registers to store jitter information integer HighJitterTime; // time by which high time pulse width is modified integer LowJitterTime; // time by which low time pulse width is modified integer JitterPeriod; // specifies in pulse numbers when the Jitter is // to be repeated integer JitterCount; // number of pulses for which jitter is induced reg JitterOnOff; // specifies if jitter is being induced or not reg task_in_progress; // SOF's reg hs_clk; // high speed clock reg ls_clk; // low-speed clock reg clk_swtch; // clock switch reg [31:0] SetupDataLen; reg GenByteBoundaryPos; reg BoundaryBitVal; integer ModifyGran; task DispErrMsg; input [6:0] address; input [3:0] EndPt; input [31:0] ErrMsgNo; begin if (ReportErrors == FALSE) disable DispErrMsg; if ((ErrorFileFp == 0) & (ErrorFileName == "")) begin $display("No file name specified to log errors."); disable DispErrMsg; end if (ErrorFileFp == 0) ErrorFileFp = $fopen(ErrorFileName); if ((ErrMsgNo >= 0) & (ErrMsgNo <= 32)) $fwrite(ErrorFileFp, "Error %0d :", (500 + ErrMsgNo)); case (ErrMsgNo) 0: $fdisplay(ErrorFileFp, "Time out for bulk in transfer at address %h for End Point %h at time %0t", address, EndPt, $time); 1: $fdisplay(ErrorFileFp, "Time out for iso in transfer at address %h for End Point %h at time %0t", address, EndPt, $time); 2: $fdisplay(ErrorFileFp, "Time out for interrupt transfer at address %h for End Point %h at time %0t", address, EndPt, $time); 3: $fdisplay(ErrorFileFp, "Time out for control transfer at address %h for End Point %h at time %0t", address, EndPt, $time); //this EndPt value should be zero 4: $fdisplay(ErrorFileFp, "Time out for bulk out transfer at address %h for End Point %h at time %0t", address, EndPt, $time); 5: $fdisplay(ErrorFileFp, "Pid error at address %h for End Point %h at time %0t", address, EndPt, $time); 6: $fdisplay(ErrorFileFp, "Short packet at address %h for End Point %h at time %0t", address, EndPt, $time); 7: $fdisplay(ErrorFileFp, "CRC error for token packet at address %h for End Point %h at time %0t", address, EndPt, $time); 8: $fdisplay(ErrorFileFp, "CRC error for data at address %h for End Point %h at time %0t", address, EndPt, $time); 9: $fdisplay(ErrorFileFp, "Incorrect token received at address %h for End Point %h at time %0t", address, EndPt, $time); 10: $fdisplay(ErrorFileFp, "Incorrect Data0/Data1 toggle received at address %h for End Point %h at time %0t", address, EndPt, $time); 11: $fdisplay(ErrorFileFp, "NAK recevied at address %h for End Point %h at time %0t", address, EndPt, $time); 12: $fdisplay(ErrorFileFp, "STALL received at address %h for End Point %h at time %0t", address, EndPt, $time); 13: $fdisplay(ErrorFileFp, "Incorrect handshake received at address %h for End Point %h at time %0t", address, EndPt, $time); 14: $fdisplay(ErrorFileFp, "Long packet at address %h for End Point %h at time %0t", address, EndPt, $time); 15: $fdisplay(ErrorFileFp, "Corrupted handshake received at address %h for End Point %h at time %0t", address, EndPt, $time); 16: $fdisplay(ErrorFileFp, "Device error at address %h for End Point %h at time %0t", address, EndPt, $time); 17: $fdisplay(ErrorFileFp, "Invalid wIndex value for control transfer to address %h at time %0t", address, $time); 18: $fdisplay(ErrorFileFp, "Invalid RequestType for control transfer to address %h at time %0t", address, $time); 19: $fdisplay(ErrorFileFp, "Invalid wValue value for control transfer to address %h at time %0t", address, $time); 20: $fdisplay(ErrorFileFp, "Invalid data length during data phase for control transfer to address %0h and End Point %0h at time %0t", address, EndPt, $time); 21: $fdisplay(ErrorFileFp, "No setup transaction in progress to do a control_in or a control_out or a status transaction at time %0t", $time); 22: $fdisplay(ErrorFileFp, "Doing a control_in when a control_out is expected and vice-versa at time %0t", $time); 23: $fdisplay(ErrorFileFp, "Doing a control_in or control_out when the number of bytes specified by wLength have been received or sent at time %0t", $time); 24: $fdisplay(ErrorFileFp, "Doing a status_in when a status_out is expected and vice-versa at time %0t", $time); 25: $fdisplay(ErrorFileFp, "Received a DATA0 token during the status phase of a control transaction at address %0h, EndPt %0h, at time %0t", address, EndPt, $time); 26: $fdisplay(ErrorFileFp, "Incorrect sync field at time %0t", $time); 27: $fdisplay(ErrorFileFp, "Bit Stuffing error at time %0t", $time); 28: $fdisplay(ErrorFileFp, "Eop incorrect at time %0t", $time); 29: $fdisplay(ErrorFileFp, "Null File Name passed to command at time %0t", $time); 30: $fdisplay(ErrorFileFp, "Offset into file greater than size of file at time %0t", $time); 31: $fdisplay(ErrorFileFp, "Command not supported by a low speed device issued at time %0t.", $time); 32: $fdisplay(ErrorFileFp, "Command not supported by command line interface issued at time %0t.", $time); endcase end endtask //bit 0 has the IN DataToggle and bit 1 has the OUT DataToggle function [1:0] CheckDataToggle; input [6:0] address; input [3:0] EndPt; reg [15:0] tmpReg1; reg [15:0] tmpReg2; begin tmpReg1 = InDataToggle[address]; tmpReg2 = OutDataToggle[address]; if ((EndPt < 16) & (EndPt >= 0)) begin CheckDataToggle[0] = tmpReg1[EndPt]; CheckDataToggle[1] = tmpReg2[EndPt]; end else CheckDataToggle = 0; // default end endfunction function CheckDataToggleIN; input [6:0] address; input [3:0] EndPt; reg [15:0] tmpReg; begin tmpReg = InDataToggle[address]; if ((EndPt < 16) & (EndPt >= 0)) CheckDataToggleIN = tmpReg[EndPt]; else CheckDataToggleIN = 0; // default end endfunction function CheckDataToggleOUT; input [6:0] address; input [3:0] EndPt; reg [15:0] tmpReg; begin tmpReg = OutDataToggle[address]; if ((EndPt < 16) & (EndPt >= 0)) CheckDataToggleOUT = tmpReg[EndPt]; else CheckDataToggleOUT = 0; // default end endfunction task SetDataToggle; input [6:0] address; input [3:0] EndPt; input [1:0] SetVal; //value to which the toggle value should be changed to // index 0 has the IN value and index 1 has the OUT value reg [15:0] tmpReg; begin tmpReg = InDataToggle[address]; if ((SetVal[0] == 0) | (SetVal[0] == 1)) tmpReg[EndPt] = SetVal; else tmpReg[EndPt] = 0; // default InDataToggle[address] = tmpReg; tmpReg = OutDataToggle[address]; if ((SetVal[1] == 0) | (SetVal[1] == 1)) tmpReg[EndPt] = SetVal; else tmpReg[EndPt] = 0; // default OutDataToggle[address] = tmpReg; end endtask task SetDataToggleIN; input [6:0] address; input [3:0] EndPt; input SetVal; //value to which the toggle value should be changed to reg [15:0] tmpReg; begin tmpReg = InDataToggle[address]; if ((SetVal == 0) | (SetVal == 1)) tmpReg[EndPt] = SetVal; else tmpReg[EndPt] = 0; // default InDataToggle[address] = tmpReg; end endtask task SetDataToggleOUT; input [6:0] address; input [3:0] EndPt; input SetVal; //value to which the toggle value should be changed to reg [15:0] tmpReg; begin tmpReg = OutDataToggle[address]; if ((SetVal == 0) | (SetVal == 1)) tmpReg[EndPt] = SetVal; else tmpReg[EndPt] = 0; // default OutDataToggle[address] = tmpReg; end endtask function [7:0] CorruptHshk; input [7:0] funHshk; reg [7:0] tmpReg; reg [4:0] i; begin tmpReg = funHshk; if (HshkPidIntegrity == TRUE) begin for (i = 0; i < 8; i = i + 1) begin if (HshkPidIntegrityMask[i] == 1'b1) tmpReg[i] = ~tmpReg[i]; end end CorruptHshk = tmpReg; end endfunction //////////////////////////////////////////////////////////////////////////////// // // swap2 : swaps around the bits in half a nibble // //////////////////////////////////////////////////////////////////////////////// function [1:0] swap2; input [1:0] SwapBits; begin swap2 = {SwapBits[0], SwapBits[1]}; end endfunction //////////////////////////////////////////////////////////////////////////////// // // swap8 : swaps around the bits in a byte and returns the swapped byte // //////////////////////////////////////////////////////////////////////////////// function [7:0] swap8; input [7:0] SwapByte; begin swap8 = {SwapByte[0], SwapByte[1], SwapByte[2], SwapByte[3], SwapByte[4], SwapByte[5], SwapByte[6], SwapByte[7]}; end endfunction //////////////////////////////////////////////////////////////////////////////// // // DumpData : dumps the data received into in_out_buf to a file // Inputs : address : device address to which data is dumped to the // associated file, 7 bits // EndPt : End Point number, 4 bits // ByteCount : number of bytes to dump from in_out_buf to the file // //////////////////////////////////////////////////////////////////////////////// task DumpData; input [6:0] address; input [3:0] EndPt; input [3:0] DataToggle; input [31:0] ByteCount; integer i; integer j; reg [39:0] DataToggleString; reg Match; begin DataToggleString = (DataToggle == DATA0) ? "DATA0" : "DATA1" ; Match = FALSE; for (i = 1; i <= NUM_ENDPT_FILES; i = i + 1) begin if (EndPtFileInfo[i] == {EndPt, address}) begin if ((EndPtFp[i] > 0) & (EndPtFileMode[i] == WRITE)) begin $fdisplay (EndPtFp[i], "//address = %b, EndPt = %b, Data Toggle = %0s at time = %0t", address, EndPt, DataToggleString, $time); //for (j = 1; j <= ByteCount; j = j + 1) $fwrite (EndPtFp[i], "%h, ", in_out_buf [j]); for (j = 1; j <= ByteCount; j = j + 1) $fdisplay (EndPtFp[i], "%h", in_out_buf[j]); $fdisplay(EndPtFp[i], "\n"); Match = TRUE; end i = NUM_ENDPT_FILES + 1; end end if (Match == FALSE) begin // no file name associated with this address // dump data into the common bucket(file) if (RecvDataFp == 0) RecvDataFp = $fopen(RecvDataFileName); $fdisplay (RecvDataFp, "//address = %b, EndPt = %b, Data Toggle = %0s at time = %0t", address, EndPt, DataToggleString, $time); //for (j = 1; j <= ByteCount; j = j + 1) $fwrite (RecvDataFp, "%h, ", in_out_buf[j]); for (j = 1; j <= ByteCount; j = j + 1) $fdisplay (RecvDataFp, "%h", in_out_buf[j]); $fdisplay(RecvDataFp, "\n"); end end endtask function [7:0] CorruptDataPid; input [7:0] funDataPid; integer i; reg [7:0] tmpReg; begin tmpReg = funDataPid; if (GenDataPidErr == TRUE) begin for ( i = 0; i < 8; i = i + 1) begin if (DataPidErrMask[i] == 1'b1) tmpReg[i] = ~tmpReg[i]; end end CorruptDataPid = tmpReg; end endfunction function [7:0] CorruptToken; input [7:0] funToken; integer i; reg [7:0] tmpReg; begin tmpReg = funToken; if (GenTokenErr == TRUE) begin for ( i = 0; i < 8; i = i + 1) begin if (TokenErrMask[i] == 1'b1) tmpReg[i] = ~tmpReg[i]; end end CorruptToken = tmpReg; end endfunction //////////////////////////////////////////////////////////////////////////////// // // WriteResults : writes out the results to the file pointed to by ResultsFp // //////////////////////////////////////////////////////////////////////////////// task WriteResults; begin if (ResultsFile == "") disable WriteResults; if (ResultsFp != 0) $fclose(ResultsFp); ResultsFp = $fopen(ResultsFile); $fdisplay(ResultsFp, "\n"); $fdisplay(ResultsFp, "--------------------------------------------------------------------------------"); $fdisplay(ResultsFp, "-------------------- Transfer Statistics for the HOST model --------------------"); $fdisplay(ResultsFp, "--------------------------------------------------------------------------------"); $fdisplay(ResultsFp, "\n"); $fdisplay(ResultsFp, " Simulation Start Time ------------------------------ : 0",); $fdisplay(ResultsFp, " Number of Bulk In transactions --------------------- : %0d", NumBulkInTrans); $fdisplay(ResultsFp, " Number of Successful Bulk In transactions ---------- : %0d", NumSucBulkInTrans); $fdisplay(ResultsFp, " Number of Bulk Out transactions -------------------- : %0d", NumBulkOutTrans); $fdisplay(ResultsFp, " Number of Successful Bulk Out transactions --------- : %0d", NumSucBulkOutTrans); $fdisplay(ResultsFp, " Number of Iso In transactions ---------------------- : %0d", NumIsoInTrans); $fdisplay(ResultsFp, " Number of Successful Iso In transactions ----------- : %0d", NumSucIsoInTrans); $fdisplay(ResultsFp, " Number of Iso Out transactions --------------------- : %0d", NumIsoOutTrans); $fdisplay(ResultsFp, " Number of Interrupt transactions ------------------- : %0d", NumIntrptTrans); $fdisplay(ResultsFp, " Number of Successful Interrupt transactions -------- : %0d", NumSucIntrptTrans); $fdisplay(ResultsFp, " Number of resets ----------------------------------- : %0d", NumResets); $fdisplay(ResultsFp, " Number of SOF's sent ------------------------------- : %0d", NumSOF); $fdisplay(ResultsFp, " Number of Control Read transactions ---------------- : %0d", NumCntrlRdTrans); $fdisplay(ResultsFp, " Number of Successful Control Read transactions ----- : %0d", NumSucCntrlRdTrans); $fdisplay(ResultsFp, " Number of Control Write transactions --------------- : %0d", NumCntrlWrTrans); $fdisplay(ResultsFp, " Number of Successful Control Write transactions ---- : %0d", NumSucCntrlWrTrans); $fdisplay(ResultsFp, " Simulation End Time -------------------------------- : %0t", $time); $fdisplay(ResultsFp, "\n"); end endtask //////////////////////////////////////////////////////////////////////////////// // // CorruptCrc16 : Corrupts the crc16 value passed on to it according to the // present crc16 error generation status // //////////////////////////////////////////////////////////////////////////////// function [15:0] CorruptCrc16; input [15:0] funCrc16; reg [5:0] i; begin if (GenCrc16Err == TRUE) begin for (i = 0; i < 16; i = i + 1) begin if (Crc16ErrMask[i] == 1'b1) funCrc16[i] = ~funCrc16[i]; end end CorruptCrc16 = funCrc16; end endfunction //////////////////////////////////////////////////////////////////////////////// // // CorruptCrc5 : Corrupts the crc5 value passed on to it according to the // present crc5 error generation status // //////////////////////////////////////////////////////////////////////////////// function [4:0] CorruptCrc5; input [4:0] funCrc5; reg [5:0] i; begin if (GenCrc5Err == TRUE) begin for (i = 0; i < 5; i = i + 1) begin if (Crc5ErrMask[i] == 1'b1) funCrc5[i] = ~funCrc5[i]; end end CorruptCrc5 = funCrc5; end endfunction //////////////////////////////////////////////////////////////////////////////// // // modify_device_speed : modifies the device speed // //////////////////////////////////////////////////////////////////////////////// task modify_device_speed; input tskDeviceSpeed; begin DeviceSpeed = (tskDeviceSpeed == LOW_SPEED) ? LOW_SPEED:HIGH_SPEED; end endtask //////////////////////////////////////////////////////////////////////////////// // // CorruptSyncField : corrupts the sync field according to SyncFieldMask // //////////////////////////////////////////////////////////////////////////////// function [7:0] CorruptSyncField; input [7:0] funSyncField; reg [7:0] tmpReg; reg [4:0] i; begin tmpReg = funSyncField; if ((SyncField == TRUE) & (SyncLevel == SetSyncLevel)) begin for (i = 0; i < 8; i = i + 1) begin if (SyncFieldMask[i] == 1'b1) tmpReg[i] = ~tmpReg[i]; end end CorruptSyncField = tmpReg; end endfunction //////////////////////////////////////////////////////////////////////////////// // // SendData : serialises and puts out the data in in_out_buf onto DPLS(D+) // and DMNS(D-) // //////////////////////////////////////////////////////////////////////////////// task SendData; integer i; reg [31:0] SE0Counter; // Single Ended Zero Counter reg [31:0] SE0Terminate; event SE0Event; begin i = 0; SE0Counter = 2'b00; if (in_out_buf_ptr > 0) begin @(posedge clk); @(posedge clk) begin // synchronise to positive edge of clock enc_enbl = 1'b1; // active high enc_reset_n = 1'b1; // active low enc_last_byte = 1'b0; enc_data_in = CorruptSyncField(8'h80); end fork forever @(posedge clk) begin if (GenByteBoundary == TRUE) begin if ((i == in_out_buf_ptr) & (enc_bit_count_out == 6)) begin enc_enbl = 1'b0; enc_reset_n = 1'b0; in_out_buf_ptr = 0; -> SE0Event; end end end forever @(posedge clk) begin if (GenByteBoundaryPos == TRUE) begin in_out_buf[in_out_buf_ptr + 1] = {BoundaryBitVal, BoundaryBitVal, BoundaryBitVal, BoundaryBitVal, BoundaryBitVal, BoundaryBitVal, BoundaryBitVal, BoundaryBitVal}; if ((i == (in_out_buf_ptr + 1)) & (enc_bit_count_out == 0)) begin enc_enbl = 1'b0; enc_reset_n = 1'b0; in_out_buf_ptr = 0; -> SE0Event; end end end forever @(negedge enc_count_out) begin if ((i == in_out_buf_ptr) & (GenByteBoundaryPos == FALSE)) begin //@(posedge clk); enc_enbl = 1'b0; // active high enc_reset_n = 1'b0; // active low in_out_buf_ptr = 0; // reset output buffer pointer -> SE0Event; end else begin enc_data_in = in_out_buf[i]; if (i == in_out_buf_ptr - 1) enc_last_byte = 1'b1; else enc_last_byte = 1'b0; //if (Debug) $display("in_out_buf[%h] = %h at time %0t",i, in_out_buf[i], $time); i = i + 1; end end forever @(SE0Event) begin // drive a SE0 for 2 bit times SE0Terminate = ((GenSE0Error == TRUE) & (SE0ErrorLevel == SetSyncLevel)) ? (SE0BitTimes) : 2; if (ModifyGran < -8) ModifyGran = -8; // SE0Terminate = (SE0Terminate * 4) + ModifyGran; // @(posedge clk); // forever @(posedge clk4x) begin forever @(posedge clk) begin if (SE0Counter >= SE0Terminate) begin zDPLS = #1 1'bZ; zDMNS = 1'bZ; @(posedge clk); // wait for one idle state after pulls disable SendData; end if (i >= in_out_buf_ptr) begin zDPLS = #1 1'b0; zDMNS = 1'b0; SE0Counter = SE0Counter + 1; end end end join end end endtask //////////////////////////////////////////////////////////////////////////////// // // WaitForResp : collects the data from DPLS(D+) and DMNS(D-) and fills in_out_buf // //////////////////////////////////////////////////////////////////////////////// task WaitForResp; output [31:0] recv_bit_count; reg [31:0] recv_bit_count; integer EopDetect; reg [4:0] ClkCount; reg [3:0] DplsCount; reg FltrSyncFld; integer tmpTimeOutCounter; reg tmpTimeOut; reg OnlyOnce; reg SyncDetect; time SyncPulseT1; time SyncPulseT2; time SyncPulseDuration; begin if (Debug) $display("In %0s --> In task wait for response at time %0t", SelfName, $time); EopDetect = 0; in_out_buf_ptr = 0; DplsCount = 0; ClkCount = 0; FltrSyncFld = 1'b1; tmpTimeOutCounter = 0; tmpTimeOut = TRUE; recv_bit_count = 0; OnlyOnce = TRUE; SyncDetect = FALSE; // dec_enbl = 1'b1; // active high // dec_reset_n = 1'b1; // active low begin : TimeOutBlock forever @(posedge dpll_clk) begin //if (Debug) $display("In %0s --> waiting for event in WaitForResp %0t", SelfName, $time); if (TimeOut == TRUE) begin if (tmpTimeOutCounter == TimeOutVal) begin if (Debug) $display("In %0s --> Time out at time %0t", SelfName, $time); disable WaitForResp; end tmpTimeOutCounter = tmpTimeOutCounter + 1; end //if (Debug) $display("In %0s --> DeviceSpeed = %b at time %0t", SelfName, DeviceSpeed, $time); //if (DPLS === 1'b0) begin if (DPLS === ~DeviceSpeed) begin if (Debug) $display("In %0s --> DPLS = %b , DeviceSpeed = %b at time %0t", SelfName, DPLS, DeviceSpeed, $time); if (DMNS === DeviceSpeed) begin // differential data @DPLS StartTime = $time; SyncPulseT1 = $time; @DPLS SyncPulseT2 = $time; @DPLS SyncPulseDuration = SyncPulseT2 - SyncPulseT1; @DPLS SyncPulseT1 = $time; @DPLS SyncPulseT2 = $time; @DPLS #SyncPulseDuration #SyncPulseDuration #SyncPulseDuration dec_enbl = 1'b1; // active high dec_reset_n = 1'b1; // active low // StartTime = $time; this time should be start of syncpulse disable TimeOutBlock; end else if ((DMNS === 1'b0) & (DPLS === 1'b0)) begin EopDetect = 1; disable TimeOutBlock; end end end end // TimeOutBlock if (Debug) $display("In %0s --> Decoder enabled at time %0t in host", SelfName, $time); fork begin : DataSink forever @(posedge dec_par_data_rdy) begin if (FltrSyncFld == 1'b1) begin // filter out the sync field in_out_buf[in_out_buf_ptr] = dec_par_data_out; in_out_buf_ptr = in_out_buf_ptr + 1; end if (dec_par_data_out == {~PREAMBLE, PREAMBLE} & in_out_buf_ptr == 1) begin dec_enbl = 1'b0; dec_reset_n = 1'b0; StopTime = $time; disable WaitForResp; end if (Debug) $display("In %0s --> receive data = %h", SelfName, dec_par_data_out); if (FltrSyncFld == 1'b0) begin /* if (dec_par_data_out != 8'h80) begin if (Debug) $display("In %0s --> Incorrect sync field %0h received at time %0t, ...discarding packet", SelfName, dec_par_data_out, $time); in_out_buf_ptr = 0; // equivalent to a time out dec_enbl = 1'b0; dec_reset_n = 1'b0; wait(1==0); // wait while the other block detects a EOP and disables task end */ end FltrSyncFld = 1'b1; end end forever @(posedge dpll_clk) begin if (dec_bit_stuff_err == 1'b1) begin if (OnlyOnce == TRUE) begin DispErrMsg(0, 0, 27); OnlyOnce = FALSE; in_out_buf_ptr = 0; // reset data pointer end disable DataSink; end if((DPLS == DMNS) & (DPLS == 1'b0)) begin EopDetect = EopDetect + 1; recv_bit_count = dec_recv_bit_count - 1; if (StopTime == 0) StopTime = $time; if (SE0StartTime == 0) SE0StartTime = $time; if (Debug) $display("In %0s --> StopTime = %0d, SE0StartTime = %0d", SelfName, StopTime, SE0StartTime); end if (EopDetect == 1) begin if (DPLS == ~DMNS) begin // SE0 seen for only 1 bit time if (Debug) $display("In %0s --> EOP asserted for 1 bit time at time %0t", SelfName, $time); dec_enbl = 1'b0; // disable the decoder dec_reset_n = 1'b0; // reset the decoder SE0StopTime = $time; disable WaitForResp; // incorrect EOP was received end end if (EopDetect == 2) begin dec_enbl = 1'b0; // disable the decoder dec_reset_n = 1'b0; // reset the decoder if (DPLS == ~DMNS) begin if (Debug) $display("In %0s --> EOP asserted for 2 bit time at time %0t", SelfName, $time); dec_enbl = 1'b0; // disable the decoder dec_reset_n = 1'b0; // reset the decoder SE0StopTime = $time; disable WaitForResp; // correct EOP was received end end if ((EopDetect > 2) & (EopDetect < 32)) begin // incorrect EOP received if (DPLS == ~DMNS) begin if (Debug) $display("In %0s --> EOP asserted for %h bit times at time ", SelfName, EopDetect, $time); SE0StopTime = $time; disable WaitForResp; end end if (EopDetect >= 32) begin if (DPLS == ~DMNS) begin if (Debug) $display("In %0s --> Reset at time ", SelfName, $time); SE0StopTime = $time; in_out_buf_ptr = 0; disable WaitForResp; end end end join end endtask //////////////////////////////////////////////////////////////////////////////// // // 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 SendReset; input [7:0] ResetTime; reg [7:0] tskResetTime; reg [7:0] tskResetTimeCounter; begin tskResetTime = ResetTime; //if (tskResetTime <= 32) tskResetTime = 7'b0100000; //if (tskResetTime >= 64) tskResetTime = 7'b1000000; tskResetTimeCounter = 7'b0000000; forever @(posedge clk) begin zDPLS = 1'b0; zDMNS = 1'b0; tskResetTimeCounter = tskResetTimeCounter + 1'b1; if (tskResetTimeCounter > tskResetTime) begin zDPLS = 1'bz; zDMNS = 1'bz; @(posedge clk); @(posedge clk); disable SendReset; end end end endtask parameter M16 = 16'h8005; //mask value to calculate 16 bit crc parameter M05 = 8'h05; //mask value to calculate 5 bit crc function [15:0] crc16; input [7:0] DataByte; input [15:0] PrevCrc; reg [15:0] TempPrevCrc; integer i; begin TempPrevCrc = PrevCrc; for (i = 0; i < 8; i = i + 1) begin if (DataByte[i] ^ TempPrevCrc[15] ) TempPrevCrc = {TempPrevCrc[14:0],1'b0} ^ M16; else TempPrevCrc = {TempPrevCrc[14:0], 1'b0}; end crc16 = TempPrevCrc; end endfunction //////////////////////////////////////////////////////////////////////////////// //function crc5 calculates a 5 bit crc //inputs : // PrevCrc : 5 bit value, initially set to zero by the // calling module, from the next call onwards // it is the previous CRC value returned by // the function. // // DataByte : 8 bit value for which crc is to calculated // //////////////////////////////////////////////////////////////////////////////// function [4:0] crc5; input [10:0] DataByte; input [4:0] PrevCrc; reg [4:0] TempPrevCrc; integer i; begin TempPrevCrc = PrevCrc; for (i = 0; i < 11; i = i + 1) begin if (DataByte[i] ^ TempPrevCrc[4] ) TempPrevCrc = {TempPrevCrc[3:0],1'b0} ^ M05; else TempPrevCrc = {TempPrevCrc[3:0], 1'b0}; end crc5 = TempPrevCrc[4:0]; end endfunction /////////////////////////////////////////////////////////////////////////////// // // FillCrc5 : fills with crc5 given a 11 bit value // input : InVal, in value for which crc5 has to be appended // this is a 11 bit value for which the 7 LSB bits are address and // 4 MSB bits are end point number // returns : 16 bit value for which is InVal with crc5 appended to it. // /////////////////////////////////////////////////////////////////////////////// function [15:0] FillCrc5; input [10:0] InVal; reg [15:0] tmpReg; begin tmpReg[10:0] = InVal; // put address and EndPt into consecutive bits tmpReg[15:11] = crc5(InVal, 5'b11111); // calculate crc5 for the first 8 bits tmpReg[15:11] ={tmpReg[11], tmpReg[12], tmpReg[13], tmpReg[14], tmpReg[15]}; tmpReg[6:0] = InVal[6:0]; // address tmpReg[10:7] = InVal[10:7]; // End Point if (GenCrc5Err == FALSE) tmpReg[15:11] = ~tmpReg[15:11]; // invert the bits in the crc tmpReg[15:11] = CorruptCrc5(tmpReg[15:11]); // crc5 corruption FillCrc5 = tmpReg; end endfunction //////////////////////////////////////////////////////////////////////////////// // // FillCrc16 : Calculates the crc16 value from in_out_buf // input : StartAddr : start address of in_out_buf, 32 bits // StopAddr : stop address of in_out_buf, 32 bits // returns : 16 bit value which is the crc16 for this segment of memory // //////////////////////////////////////////////////////////////////////////////// function [16:0] FillCrc16; input [31:0] StartAddr; input [31:0] StopAddr; reg [16:0] tmpCrc; integer i; begin tmpCrc = 16'hffff; for (i = StartAddr; i <= StopAddr; i = i + 1) begin tmpCrc = crc16(in_out_buf[i], tmpCrc); end FillCrc16 = tmpCrc; end endfunction //////////////////////////////////////////////////////////////////////////////// // // SendAck : sends an ack // //////////////////////////////////////////////////////////////////////////////// task SendAck; begin task_in_progress = TRUE; in_out_buf[0] = CorruptHshk({~ACK, ACK}); in_out_buf_ptr = 1; SetSyncLevel = 2; usb_idle(ResponseLatency - 3); task_in_progress = TRUE; SendData; task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // reset : performs a reset on the USB bus by driving SE0 // // input : Reset Time in bit times // //////////////////////////////////////////////////////////////////////////////// task usb_reset; input [7:0] tskResetTime; begin task_in_progress = TRUE; NumResets = NumResets + 1; SendReset(tskResetTime); WriteResults; task_in_progress = FALSE; end endtask ////////////////////////////////////////////////////////////////////////////////// // usb_idle : idles the USB. // input : IdleTime, which is the number of bit times for which to idle the // bus. // //////////////////////////////////////////////////////////////////////////////// task usb_idle; input [31:0] IdleTime; reg [31:0] tskIdleTime; begin : usb_idle task_in_progress = TRUE; tskIdleTime = 0; forever @(posedge clk) begin if (tskIdleTime >= IdleTime) begin task_in_progress = FALSE; disable usb_idle; end tskIdleTime = tskIdleTime + 1; end task_in_progress = FALSE; end endtask /////////////////////////////////////////////////////////////////////////////// // // task usb_idle_nolock : same as usb_idle except that there is no lock // that is there is no assertion of the task_in_progress // flag // /////////////////////////////////////////////////////////////////////////////// task usb_idle_nolock; input [31:0] IdleTime; reg [31:0] tskIdleTime; begin : usb_idle_nolock tskIdleTime = 0; forever @(posedge clk) begin if (tskIdleTime >= IdleTime) begin task_in_progress = FALSE; disable usb_idle_nolock; end tskIdleTime = tskIdleTime + 1; end end endtask //////////////////////////////////////////////////////////////////////////////// // // setup : issues a setup token with the corresponding data // inputs : address : address of the device, 7 bits // EndPt : end point number, 4 bits // outputs : Status : returns the status of the transaction, 4 bits // //////////////////////////////////////////////////////////////////////////////// task setup; input [6:0] address; input [3:0] EndPt; output [3:0] Status; // 0 : ack received // 3 : no response // 4 : invalid response // 6 : another control transaction in progress // 8 : invalid control data reg [3:0] Status; reg [15:0] tmpCrc; reg [15:0] tmpReg; integer i; integer CntrlNum; // number of the control transaction reg [31:0] recv_bit_count; reg Match; reg [31:0] tmpPulseWidth; // eight bytes of setup data is assumed to be in Xmitbuffer begin : setup task_in_progress = TRUE; tmpPulseWidth = PulseWidth; Match = FALSE; for (i = 1; i <= MAX_CNTRL_INTERLEAVE; i = i + 1) begin if ((address == CntrlTransAddr[i]) & (EndPt == CntrlTransEndP[i])) begin Status = 4'b0110; disable setup; end end for (i = 1; i <= MAX_CNTRL_INTERLEAVE; i = i + 1) begin if (CntrlTransType[i] == 2'b00) begin Match = TRUE; CntrlTransAddr[i] = address; CntrlTransEndP[i] = EndPt; CntrlTransDlen[i] = {XmitBuffer[7], XmitBuffer[6]}; CntrlNum = i; i = MAX_CNTRL_INTERLEAVE + 1; end end if (Match == FALSE) begin Status = 6; // only one control transaction in progress clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable setup; end usb_idle(ResponseLatency - 3); // #27 if ((SendPreamble == TRUE) & (DeviceSpeed == HIGH_SPEED)) begin send_preamble; // a high speed preamble is sent only when a high speed // hub is connected to the host model so in this case // switch clock speeds task_in_progress = TRUE; usb_idle(4); // idle for 4 high speed clock times after a preamble task_in_progress = TRUE; // PulseWidth = PulseWidth * 8; // decrease the clock frequency clk_swtch = LOW_SPEED; end in_out_buf[0] = CorruptToken({~SETUP_TOKEN, SETUP_TOKEN}); tmpReg = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SetSyncLevel = 0; // usb_idle(ResponseLatency - 3); #27 task_in_progress = TRUE; SendData; usb_idle(ResponseLatency - 3); // #27 send_high_speed_preamble; task_in_progress = TRUE; in_out_buf[0] = CorruptDataPid({~DATA0, DATA0}); tmpCrc = 16'hffff; for (i = 1; i <= SetupDataLen; i = i + 1) begin in_out_buf[i] = XmitBuffer[i - 1]; tmpCrc = crc16(in_out_buf[i], tmpCrc); end //if (Debug) $display("In %0s raw crc is %h at time %0t", SelfName, tmpCrc, $time); tmpCrc = CorruptCrc16(~{swap8(tmpCrc[15:8]), swap8(tmpCrc[7:0])}); in_out_buf[9] = tmpCrc[15:8]; in_out_buf[10] = tmpCrc[7:0]; //if (Debug) $display("In %0s bus crc is %h at time %0t", SelfName, {in_out_buf[9], in_out_buf[10]}, $time); in_out_buf_ptr = SetupDataLen + 3; SetSyncLevel = 1; // usb_idle(ResponseLatency - 3); #27 task_in_progress = TRUE; SendData; tmpReg[7:0] = XmitBuffer[0]; //if (Debug) $display("In %0s --> tmpReg = %b at time %0t", SelfName, tmpReg[7:0], $time); case(tmpReg[7]) 1'b1 : CntrlTransType[CntrlNum] = READ; 1'b0 : CntrlTransType[CntrlNum] = WRITE; default : begin Status = 8; // invalid control data in_out_buf_ptr = 0; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable setup; end endcase if (tmpReg[7] == 1'b1) NumCntrlRdTrans = NumCntrlRdTrans + 1; else NumCntrlWrTrans = NumCntrlWrTrans + 1; if (Debug) $display("CntrlTransType = %b", CntrlTransType[CntrlNum]); WaitForResp(recv_bit_count); if (Debug) $display("In %0s --> in_out_buf[0] = %b, in_out_buf_ptr = %d", SelfName, in_out_buf[0], in_out_buf_ptr); case (in_out_buf_ptr) 0 : begin // time out if (dec_bit_stuff_err == TRUE) begin usb_idle(RespTimeOutVal); task_in_progress = TRUE; end Status = 3; CntrlTransType[CntrlNum] = 2'b00; // clear the transaction in progress flag CntrlTransAddr[CntrlNum] = 7'b1111111; CntrlTransEndP[CntrlNum] = 4'b1111; CntrlTransDlen[CntrlNum] = 0; end 1 : begin if (in_out_buf[0] == {~ACK, ACK}) begin Status = 0; //setup initiated successfully SetDataToggle(address, EndPt, 2'b11); end else begin Status = 4; // invalid response CntrlTransType[CntrlNum] = 2'b00; // clear the transaction in progress flag CntrlTransAddr[CntrlNum] = 7'b1111111; CntrlTransEndP[CntrlNum] = 4'b1111; CntrlTransDlen[CntrlNum] = 0; end end default : begin Status = 4; // invalid response CntrlTransType[CntrlNum] = 2'b00; // clear the transaction in progress flag CntrlTransAddr[CntrlNum] = 7'b1111111; CntrlTransEndP[CntrlNum] = 4'b1111; CntrlTransDlen[CntrlNum] = 0; end endcase WriteResults; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // control_IN : does the data phase in a control transaction initiated by // a call to setup // output : ByteCount : number of bytes received during this control_in // Status : Exit Status of this task // //////////////////////////////////////////////////////////////////////////////// task control_IN; input [6:0] address; input [3:0] EndPt; output [31:0] ByteCount; output [3:0] Status; reg [3:0] Status; reg [31:0] tskByteCount; reg [31:0] recv_bit_count; reg [15:0] tmpReg; reg [15:0] tmpCrc; integer i; integer CntrlNum; reg tmpDataToggle; reg [31:0] tmpPulseWidth; begin : control_IN task_in_progress = TRUE; ByteCount = 0; tmpPulseWidth = PulseWidth; CntrlNum = 0; for (i = 1; i <= MAX_CNTRL_INTERLEAVE; i = i + 1) begin if ((CntrlTransType[i] != 2'b00) & (CntrlTransAddr[i] == address) & (CntrlTransEndP[i] == EndPt)) begin CntrlNum = i; i = MAX_CNTRL_INTERLEAVE + 1; end end if (Debug) $display("CntrlTransType = %b", CntrlTransType[CntrlNum]); if (CntrlNum == 0) begin DispErrMsg(0, 0, 21); Status = 7; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_IN; end if (CntrlTransType[CntrlNum] == 2'b00) begin // redundant ?? DispErrMsg(0, 0, 21); Status = 7; // no setup transaction in progress to do a control_in xfer clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_IN; end if (CntrlTransType[CntrlNum] != READ) begin DispErrMsg(0, 0, 22); Status = 9; // wrong type of control transaction clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_IN; end if ((SendPreamble == TRUE) & (DeviceSpeed == HIGH_SPEED)) begin clk_swtch = LOW_SPEED; // #27 usb_idle(ResponseLatency - 3); // #27 clk_swtch = HIGH_SPEED; // #27 send_preamble; // a high speed preamble is sent only when a high speed // hub is connected to the host model so in this case // switch clock speeds task_in_progress = TRUE; usb_idle(4); // idle for 4 high speed clock times after a preamble task_in_progress = TRUE; // PulseWidth = PulseWidth * 8; clk_swtch = LOW_SPEED; end in_out_buf[0] = CorruptToken({~IN_TOKEN, IN_TOKEN}); in_out_buf_ptr = 1; tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SetSyncLevel = 0; // usb_idle(ResponseLatency - 3); #27 task_in_progress = TRUE; SendData; //serialises, encodes and sends the data in in_out_buf, WaitForResp(recv_bit_count); @(posedge dpll_clk); // 10/10/97 case(in_out_buf_ptr) 0 : begin // no response from device abort control transaction Status = 3; if (Debug) $display("In %0s --> time out for control_in transaction at time %0t", SelfName, $time); end 1 : begin tmpReg[7:0] = in_out_buf[0]; //should contain the pid if (tmpReg[7:4] != (~tmpReg[3:0])) begin DispErrMsg(address, EndPt, 5); end if (tmpReg[3:0] == NAK) begin DispErrMsg(address, EndPt, 11); Status = 1; //NAK received from end point end if (tmpReg[3:0] == STALL) begin DispErrMsg(address, EndPt, 12); Status = 2; //STALL received from end point end end 2 : begin DispErrMsg(address, EndPt, 6); // invalid number of data bytes received Status = 4; //invalid response end default : begin tmpReg[7:0] = in_out_buf[0]; //should contain the pid if (tmpReg[7:4] != (~tmpReg[3:0])) begin DispErrMsg(address, EndPt, 5); end if (Debug) $display("In %0s --> Data toggle recevied is %0b at time %0t", SelfName, tmpReg[7:0], $time); ByteCount = 0; tmpCrc = 16'hffff; //if (Debug) $display("In %0s --> calculating crc for in_out_buf[%0d] = %0h", SelfName, i, in_out_buf[i]); for (i = 1; i < (in_out_buf_ptr - 2); i = i + 1) begin tmpCrc = crc16(in_out_buf[i], tmpCrc); RecvBuffer[i - 1] = in_out_buf[i]; ByteCount = ByteCount + 1; if (Debug) $display("In %0s --> received byte[%0d] = %b", SelfName, i, in_out_buf[i]); end if (Debug) $display("In %0s --> calculated crc is %0h at time %0t.", SelfName, tmpCrc, $time); if (Debug) $display("In %0s --> received raw crc is %0h at time %0t.", SelfName, {swap8(~in_out_buf[in_out_buf_ptr - 2]), swap8(~in_out_buf[in_out_buf_ptr - 1])}, $time); tmpCrc = CorruptCrc16(~{swap8(tmpCrc[15:8]), swap8(tmpCrc[7:0])}); if (Debug) $display("In %0s --> received crc is %0h at time %0t.", SelfName, {in_out_buf[in_out_buf_ptr - 2], in_out_buf[in_out_buf_ptr - 1]}, $time); //ByteCount = ByteCount + 1; if (Debug) $display("In %0s --> tmpCrc %0h, at time %0t", SelfName, tmpCrc, $time); if (tmpCrc != {in_out_buf[in_out_buf_ptr - 2], in_out_buf[in_out_buf_ptr - 1]}) begin DispErrMsg(address, EndPt, 8); //CRC Error, send no response Status = 5; usb_idle(RespTimeOutVal); task_in_progress = TRUE; end else begin case (tmpReg[3:0]) //check the token DATA0 : begin if(CheckDataToggleIN(address, EndPt) != 0) begin DispErrMsg(address, EndPt, 10); ByteCount = 0; // discard data end SetDataToggle(address, EndPt, 2'b11); //usb_idle(ResponseLatency - 3); // #27 send_high_speed_preamble; task_in_progress = TRUE; SendAck; task_in_progress = TRUE; Status = 0; if (Debug) $display("In %0s --> sending ACK at time %0t", SelfName, $time); end DATA1 : begin if(CheckDataToggleIN(address, EndPt) != 1) begin DispErrMsg(address, EndPt, 10); ByteCount = 0; // discard data end SetDataToggle(address, EndPt, 2'b00); //usb_idle(ResponseLatency - 3); send_high_speed_preamble; task_in_progress = TRUE; SendAck; task_in_progress = TRUE; Status = 0; if (Debug) $display("In %0s --> sending ACK at time %0t", SelfName, $time); end default : begin Status = 4; ByteCount = 0; // discard data DispErrMsg(address, EndPt, 9); //incorrect token end endcase end //if (tmpCrc ... end // default : endcase if (ByteCount > CntrlTransDlen[CntrlNum]) begin CntrlTransDlen[CntrlNum] = 0; DispErrMsg(address, EndPt, 20); end if (Status == 0) CntrlTransDlen[CntrlNum] = CntrlTransDlen[CntrlNum] - ByteCount; WriteResults; // PulseWidth = tmpPulseWidth; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // control_OUT : does the data phase in control transaction intiated by a setup // input : ByteCount, number of bytes from XmitBuffer to send // Status : exit status // //////////////////////////////////////////////////////////////////////////////// task control_OUT; input [6:0] address; input [3:0] EndPt; input [31:0] ByteCount; output [3:0] Status; reg [3:0] Status; reg [31:0] tskByteCount; reg [31:0] recv_bit_count; reg [15:0] tmpReg; reg [15:0] tmpCrc; integer i; integer CntrlNum; reg tmpDataToggle; reg [31:0] tmpPulseWidth; begin : control_OUT task_in_progress = TRUE; tmpPulseWidth = PulseWidth; CntrlNum = 0; for (i = 1; i <= MAX_CNTRL_INTERLEAVE; i = i + 1) begin if ((CntrlTransType[i] != 2'b00) & (CntrlTransAddr[i] == address) & (CntrlTransEndP[i] == EndPt)) begin CntrlNum = i; i = MAX_CNTRL_INTERLEAVE + 1; end end if (CntrlNum == 0) begin DispErrMsg(0, 0, 21); Status = 7; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_OUT; end if (CntrlTransType[CntrlNum] == 2'b00) begin DispErrMsg(0, 0, 21); Status = 7; // no setup transaction in progress to do a control_in xfer clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_OUT; end if (CntrlTransType[CntrlNum] != WRITE) begin DispErrMsg(0, 0, 22); Status = 9; // wrong type of control transaction clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_OUT; end if (CntrlTransDlen[CntrlNum] == 0) begin DispErrMsg(0, 0, 23); Status = 10; // doing a control transaction when wLength is 0 clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable control_OUT; end // no setup transaction in progress so start a control_in transaction usb_idle(ResponseLatency - 3); if ((DeviceSpeed == HIGH_SPEED) & (SendPreamble == TRUE)) begin clk_swtch = LOW_SPEED; // #27 usb_idle(ResponseLatency - 3); // #27 clk_swtch = HIGH_SPEED; // #27 send_preamble; // a high speed preamble is sent only when a high speed // hub is connected to the host model so in this case // switch clock speeds task_in_progress = TRUE; // PulseWidth = PulseWidth * 8; clk_swtch = LOW_SPEED; end tskByteCount = ByteCount; if (tskByteCount > CntrlTransDlen[CntrlNum]) begin if (Debug) $display("In %0s --> more data is being requested than specified by wLength, ignoring the extra bytes at time %0t", SelfName, $time); tskByteCount = CntrlTransDlen[CntrlNum]; end // else CntrlTransDlen[CntrlNum] = CntrlTransDlen[CntrlNum] - tskByteCount; // decrement data count in_out_buf[0] = CorruptToken({~OUT_TOKEN, OUT_TOKEN}); in_out_buf_ptr = 1; tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; if (Debug) $display("In host --> address = %h, EndPt = %h, crc5 = %h, tmpReg = %h", address, EndPt, tmpReg[15:11], tmpReg); SetSyncLevel = 0; task_in_progress = TRUE; SendData; //serialises, encodes and sends the data in in_out_buf task_in_progress = TRUE; tmpDataToggle = CheckDataToggleIN(address, EndPt); if (Debug) $display("In %0s --> DataToggle is %0h", SelfName, tmpDataToggle); case (tmpDataToggle) 0 : in_out_buf[0] = CorruptDataPid({~DATA0, DATA0}); 1 : in_out_buf[0] = CorruptDataPid({~DATA1, DATA1}); default : in_out_buf[0] = CorruptDataPid({~DATA0, DATA0}); endcase in_out_buf_ptr = 1; if (Debug) $display("In %0s --> DataToggle is %0h at time %0t.", SelfName, in_out_buf[0], $time); tmpCrc = 16'hffff; for (i = 1; i <= ByteCount; i = i + 1) begin in_out_buf[i] = XmitBuffer[i - 1]; tmpCrc = crc16(in_out_buf[i], tmpCrc); in_out_buf_ptr = in_out_buf_ptr + 1; if (Debug) $display("In %0s --> sending byte[%0d] = %b", SelfName, i, in_out_buf[i]); end if (Debug) $display("In %0s --> raw crc is %0h at time", SelfName, tmpCrc, $time); tmpCrc = CorruptCrc16(~{swap8(tmpCrc[15:8]), swap8(tmpCrc[7:0])}); if (Debug) $display("In %0s --> sent crc is %0h at time", SelfName, tmpCrc, $time); in_out_buf[ByteCount + 2] = tmpCrc[7:0]; in_out_buf[ByteCount + 1] = tmpCrc[15:8]; in_out_buf_ptr = in_out_buf_ptr + 2; SetSyncLevel = 1; usb_idle(ResponseLatency - 3); task_in_progress = TRUE; send_high_speed_preamble; task_in_progress = TRUE; SendData; //send the contents of in_out_buf WaitForResp(recv_bit_count); //wait for a response for this transfer if (Debug) $display("In %0s --> bits received are %0h", SelfName, recv_bit_count); case (in_out_buf_ptr) 0 : begin if (dec_bit_stuff_err == TRUE) begin usb_idle(RespTimeOutVal); task_in_progress = TRUE; end Status = 3; DispErrMsg(address, EndPt, 4); end 1 : begin tmpReg[7:0] = in_out_buf[0]; case (tmpReg[3:0]) ACK : begin case (tmpDataToggle) //change the data toggle 0 : SetDataToggle(address, EndPt, 2'b11); 1 : SetDataToggle(address, EndPt, 2'b00); default : SetDataToggle(address, EndPt, 0); endcase Status = 0; if (Debug) $display("In %0s --> ACK received at time %0t.", SelfName, $time); end NAK : begin DispErrMsg(address, EndPt, 11); Status = 1; // nak received end STALL : begin DispErrMsg(address, EndPt, 12); Status = 2; // stall received end default : begin DispErrMsg(address, EndPt, 13); Status = 4; // invalid response end endcase end default : DispErrMsg(address, EndPt, 14); endcase if (Status == 0) CntrlTransDlen[CntrlNum] = CntrlTransDlen[CntrlNum] - tskByteCount; WriteResults; // PulseWidth = tmpPulseWidth; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; end endtask //control_out //////////////////////////////////////////////////////////////////////////////// // // status_in : does the status phase in a control transaction // output : Status : exit status of the transaction // //////////////////////////////////////////////////////////////////////////////// task status_IN; input [6:0] address; input [3:0] EndPt; output Status; reg [3:0] Status; reg [31:0] recv_bit_count; reg [15:0] tmpReg; integer i; reg tmpDataToggle; integer CntrlNum; reg [31:0] tmpPulseWidth; begin : status_IN task_in_progress = TRUE; tmpPulseWidth = PulseWidth; CntrlNum = 0; $display("Input Address:%x, EndPt:%x",address,EndPt); for (i = 1; i <= MAX_CNTRL_INTERLEAVE; i = i + 1) begin $display("i :%d, CntrlTransType:%x; CntrlTransAddr:%x;CntrlTransEndP:%x ", i,CntrlTransType[i],CntrlTransAddr[i],CntrlTransEndP[i]); if ((CntrlTransType[i] != 2'b00) & (CntrlTransAddr[i] == address) & (CntrlTransEndP[i] == EndPt)) begin CntrlNum = i; i = MAX_CNTRL_INTERLEAVE + 1; end end if (CntrlNum == 0) begin DispErrMsg(0, 0, 21); Status = 7; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable status_IN; end if (CntrlTransType[CntrlNum] == 2'b00) begin DispErrMsg(0, 0, 24); Status = 7; // no setup transaction in progress to do a control_in xfer clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable status_IN; end if (Debug) $display("In %0s CntrlTransType = %b, WRITE = %b", SelfName, CntrlTransType[CntrlNum], WRITE); if (CntrlTransType[CntrlNum] != WRITE) begin DispErrMsg(0, 0, 22); Status = 9; // wrong type of control transaction clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable status_IN; end usb_idle(ResponseLatency - 3); task_in_progress = TRUE; if ((DeviceSpeed == HIGH_SPEED) & (SendPreamble == TRUE)) begin clk_swtch = LOW_SPEED; // #27 usb_idle(ResponseLatency - 3); // #27 clk_swtch = HIGH_SPEED; // #27 send_preamble; // a high speed preamble is sent only when a high speed // hub is connected to the host model so in this case // switch clock speeds task_in_progress = TRUE; // PulseWidth = PulseWidth * 8; clk_swtch = LOW_SPEED; end in_out_buf[0] = CorruptToken({~IN_TOKEN, IN_TOKEN}); in_out_buf_ptr = 1; tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SetSyncLevel = 0; SendData; //serialises, encodes and sends the data in in_out_buf, WaitForResp(recv_bit_count); case (in_out_buf_ptr) 0 : begin // timeout if (dec_bit_stuff_err == TRUE) begin usb_idle(RespTimeOutVal); task_in_progress = TRUE; end Status = 3; end 1 : begin tmpReg[7:0] = in_out_buf[0]; //should contain the pid if (tmpReg[7:4] != (~tmpReg[3:0])) begin DispErrMsg(address, EndPt, 5); end if (tmpReg[3:0] == NAK) begin DispErrMsg(address, EndPt, 11); Status = 1; //NAK received from end point end else if (tmpReg[3:0] == STALL) begin DispErrMsg(address, EndPt, 12); Status = 2; //STALL received from end point end else begin Status = 4; // invalid response end end 3 : begin tmpReg[7:0] = in_out_buf[0]; //should contain the pid if (tmpReg[7:4] != (~tmpReg[3:0])) begin DispErrMsg(address, EndPt, 5); end if ({in_out_buf[1], in_out_buf[2]} != 16'h0000) begin DispErrMsg(address, EndPt, 8); usb_idle(RespTimeOutVal); task_in_progress = TRUE; Status = 5; end else begin if (tmpReg[3:0] == DATA1) begin NumSucCntrlWrTrans = NumSucCntrlWrTrans + 1; //usb_idle(ResponseLatency - 3); // #27 send_high_speed_preamble; task_in_progress = TRUE; SendAck; task_in_progress = TRUE; Status = 0; end else begin DispErrMsg(address, EndPt, 25); usb_idle(RespTimeOutVal); task_in_progress = TRUE; end end end default : begin Status = 4; // invalid response end endcase //reset control transaction flags if (Status != 1) begin CntrlTransEndP[CntrlNum] = 4'b1111; CntrlTransAddr[CntrlNum] = 7'b1111111; CntrlTransDlen[CntrlNum] = 0; CntrlTransType[CntrlNum] = 0; end WriteResults; // PulseWidth = tmpPulseWidth; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // status_out : does the status phase of a control transaction // output : Status : Exit Status // //////////////////////////////////////////////////////////////////////////////// task status_OUT; input [6:0] address; input [3:0] EndPt; output Status; reg [3:0] Status; reg [31:0] recv_bit_count; reg [15:0] tmpReg; integer i; reg tmpDataToggle; integer CntrlNum; reg [31:0] tmpPulseWidth; begin : status_OUT task_in_progress = TRUE; tmpPulseWidth = PulseWidth; CntrlNum = 0; for (i = 1; i <= MAX_CNTRL_INTERLEAVE; i = i + 1) begin if ((CntrlTransType[i] != 2'b00) & (CntrlTransAddr[i] == address) & (CntrlTransEndP[i] == EndPt)) begin CntrlNum = i; i = MAX_CNTRL_INTERLEAVE + 1; end end if (CntrlNum == 0) begin DispErrMsg(0, 0, 21); Status = 7; clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable status_OUT; end if (CntrlTransType [CntrlNum]== 2'b00) begin DispErrMsg(0, 0, 24); Status = 7; // no setup transaction in progress to do a control_in xfer clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable status_OUT; end if (CntrlTransType[CntrlNum] != READ) begin DispErrMsg(0, 0, 22); Status = 9; // wrong type of control transaction clk_swtch = HIGH_SPEED; task_in_progress = FALSE; disable status_OUT; end usb_idle(ResponseLatency - 3); task_in_progress = TRUE; if ((DeviceSpeed == HIGH_SPEED) & (SendPreamble == TRUE)) begin clk_swtch = LOW_SPEED; // #27 usb_idle(ResponseLatency - 3); // #27 clk_swtch = HIGH_SPEED; // #27 send_preamble; // a high speed preamble is sent only when a high speed // hub is connected to the host model so in this case // switch clock speeds task_in_progress = TRUE; usb_idle(4); // idle for 4 high speed clock times after a preamble task_in_progress = TRUE; // PulseWidth = PulseWidth * 8; clk_swtch = LOW_SPEED; end in_out_buf[0] = CorruptToken({~OUT_TOKEN, OUT_TOKEN}); in_out_buf_ptr = 1; tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SetSyncLevel = 0; SendData; usb_idle(ResponseLatency - 3); task_in_progress = TRUE; send_high_speed_preamble; task_in_progress = TRUE; in_out_buf[0] = CorruptDataPid({~DATA1, DATA1}); in_out_buf[1] = 0; in_out_buf[2] = 0; in_out_buf_ptr = 3; SetSyncLevel = 1; SendData; WaitForResp(recv_bit_count); case (in_out_buf_ptr) 0 : begin if (dec_bit_stuff_err == TRUE) begin usb_idle(RespTimeOutVal); task_in_progress = TRUE; end Status = 3; // time out end 1 : begin tmpReg[7:0] = in_out_buf[0]; //should contain the pid if (tmpReg[7:4] != (~tmpReg[3:0])) begin DispErrMsg(address, EndPt, 5); end if (tmpReg[3:0] == NAK) begin DispErrMsg(address, EndPt, 11); Status = 1; //NAK received from end point end else if (tmpReg[3:0] == STALL) begin DispErrMsg(address, EndPt, 12); Status = 2; //STALL received from end point end else if (tmpReg[3:0] == ACK) begin NumSucCntrlRdTrans = NumSucCntrlRdTrans + 1; Status = 0; end else begin Status = 4; // invalid response end end default : begin Status = 4; // invalid response end endcase //reset control transaction flags if (Status != 1) begin CntrlTransEndP[CntrlNum] = 0; CntrlTransAddr[CntrlNum] = 7'b1111111; CntrlTransDlen[CntrlNum] = 4'b1111; CntrlTransType[CntrlNum] = 0; end // PulseWidth = tmpPulseWidth; clk_swtch = HIGH_SPEED; WriteResults; task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // usb_resume : drives a K state on the bus for ResumeTime number of bit times // //////////////////////////////////////////////////////////////////////////////// task usb_resume; input [31:0] ResumeTime; reg [31:0] tskResumeTime; begin : usb_resume task_in_progress = TRUE; tskResumeTime = 0; forever @(posedge clk) begin if (tskResumeTime >= ResumeTime) begin zDPLS = 1'b0; zDMNS = 1'b0; if (DeviceSpeed == HIGH_SPEED) begin // wait for two low speed bit times #667; #667; end else begin @(posedge clk); @(posedge clk); end zDPLS = 1'bZ; zDMNS = 1'bZ; task_in_progress = FALSE; disable usb_resume; end if (DeviceSpeed == HIGH_SPEED) begin zDPLS = 1'b0; zDMNS = 1'b1; end else begin zDPLS = 1'b1; zDMNS = 1'b0; end tskResumeTime = tskResumeTime + 1; end task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // send_preamble : sends a Preamble token and idles the bus for the required // 4 bit times which is the hub setup time for low speed devices // //////////////////////////////////////////////////////////////////////////////// task send_preamble; reg tskGenSE0Error; reg [31:0] tskSE0BitTimes; reg [31:0] tskSE0ErrorLevel; begin task_in_progress = TRUE; // SE0 should not be generated after sending a preamble 10/03/1996 // modify SE0 error generation logic tskGenSE0Error = GenSE0Error; tskSE0BitTimes = SE0BitTimes; tskSE0ErrorLevel = SE0ErrorLevel; GenSE0Error = TRUE; SE0BitTimes = 0; SE0ErrorLevel = SetSyncLevel; in_out_buf[0] = {~PREAMBLE, PREAMBLE}; in_out_buf_ptr = 1; SendData; // restore SE0 error generation logic 10/03/1996 GenSE0Error = tskGenSE0Error; SE0BitTimes = tskSE0BitTimes; SE0ErrorLevel = tskSE0ErrorLevel; usb_idle(4); // hub setup time task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // transfer_buf : transfers whatever data from the xmit buffer with a sync // field in the front // input : ByteCount : number of bytes to be transferred from buffer, 32 bits // FromFile : TRUE/FALSE, if TRUE data is taken from host_usb_recv.dat // //////////////////////////////////////////////////////////////////////////////// task transfer_buf; input [31:0] ByteCount; input FromFile; input [160:1] FileName; reg [3:0] Status; integer i; begin : transfer_buf task_in_progress = TRUE; for (i = 0; i < ByteCount; i = i + 1) begin in_out_buf[i] = XmitBuffer[i]; // addition 5/29/1996 end in_out_buf_ptr = ByteCount; SendData; task_in_progress = FALSE; end endtask //////////////////////////////////////////////////////////////////////////////// // // receive_buf : receives the data from the bus and puts in RecvBuf // input : DumpToFile : if true data is dumped to a file // output : ByteCount : number of bytes received // //////////////////////////////////////////////////////////////////////////////// task receive_buf; input DumpToFile; output [31:0] ByteCount; reg [31:0] recv_bit_count; integer i; begin task_in_progress = TRUE; WaitForResp(recv_bit_count); for (i = 0; i < in_out_buf_ptr; i = i + 1) begin RecvBuffer[i] = in_out_buf[i]; end ByteCount = in_out_buf_ptr; if (DumpToFile == TRUE && ByteCount > 0) DumpData(7'b1111111, 4'b1111, DATA0, ByteCount-1); task_in_progress = FALSE; end endtask /////////////////////////////////////////////////////////////////////////////// // // task send_high_speed_preamble : sends a preamble by switching clock // during a low speed transaction // //////////////////////////////////////////////////////////////////////////////// task send_high_speed_preamble; begin task_in_progress = TRUE; if ((SendPreamble == TRUE) & (DeviceSpeed == HIGH_SPEED)) begin // PulseWidth = PulseWidth / 8; clk_swtch = HIGH_SPEED; send_preamble; task_in_progress = TRUE; // a high speed preamble is sent only when a high speed // hub is connected to the host model so in this case // switch clock speeds usb_idle(4); task_in_progress = TRUE; // idle for 4 high speed clock times after a preamble // PulseWidth = PulseWidth * 8; clk_swtch = LOW_SPEED; end task_in_progress = FALSE; end endtask initial begin // initilaise the input and output buffers for(tmpCounter = 0; tmpCounter <= 2048; tmpCounter = tmpCounter + 1) begin XmitBuffer[tmpCounter] = 8'b00000000; end for(tmpCounter = 0; tmpCounter <= RECV_BUF_SIZE; tmpCounter = tmpCounter + 1) begin RecvBuffer[tmpCounter] = 8'b00000000; end for (tmpCounter = 0; tmpCounter < IN_OUT_BUF_SIZE; tmpCounter = tmpCounter + 1) begin in_out_buf[tmpCounter] = 0; end //for (tmpCounter = 0; tmpCounter < OUT_BUF_SIZE; tmpCounter = tmpCounter + 1) begin //out_buf[tmpCounter] = 0; //end for (tmpCounter = 0; tmpCounter < 128; tmpCounter = tmpCounter + 1) begin InDataToggle[tmpCounter] = 16'h0000; OutDataToggle[tmpCounter] = 16'h0000; end TimeOut = TRUE; TimeOutVal = 16; // timeout after 16 bit times RespTimeOutVal = 16; ResponseLatency = 3; GenCrc16Err = FALSE; Crc16ErrMask = 16'hffff; GenCrc5Err = FALSE; Crc5ErrMask = 5'b00000; ReportResults = TRUE; // default : turned on ResultsFile = "host_usb_res.log"; // default file name ResultsFp = 0; // initially log file pointer is 0 PulseWidth = 42; SyncField = FALSE; // default : sync field corruption is turned off SyncFieldMask = 8'hf0; // default no sync field corruption specified SyncLevel = 0; SetSyncLevel = 0; GenSE0Error = FALSE; SE0BitTimes = 2; // default conforms to the spec SE0ErrorLevel = 0; HshkPidIntegrity = FALSE; // no corruption HshkPidIntegrityMask = 8'hf0; // corruption mask for ACK's BitStuffErr = FALSE; // changed TRUE to FALSE 02/18/97 for (tmpCounter = 1; tmpCounter <= MAX_CNTRL_INTERLEAVE; tmpCounter = tmpCounter + 1) begin CntrlTransType[tmpCounter] = 2'b00; // no control transaction in progress CntrlTransAddr[tmpCounter] = 7'b1111111; // address of a control transaction CntrlTransEndP[tmpCounter] = 4'b1111; // endpoint number of a control transaction CntrlTransDlen[tmpCounter] = 16'h0000; // data length for this control transaction end SendDataFileName = "host_usb_xmit.dat"; RecvDataFileName = "host_usb_recv.dat"; RecvDataFp = 0; ReportErrors = TRUE; ErrorFileName = "host_usb_err.log"; ErrorFileFp = 0; for ( tmpCounter = 1; tmpCounter <= NUM_ENDPT_FILES; tmpCounter = tmpCounter + 1) begin EndPtFileName[tmpCounter] = ""; EndPtFileMode[tmpCounter] = 2'b00; // no mode is assigned to it EndPtFileInfo[tmpCounter] = 11'b00000000000; EndPtFp[tmpCounter] = 0; EndPtFileOfst[tmpCounter] = 0; end SendDataOfst = 0; Debug = FALSE; GenDataPidErr = FALSE; DataPidErrMask = 8'hff; GenTokenErr = FALSE; TokenErrMask = 8'hff; //DeviceSpeed = LOW_SPEED; DeviceSpeed = HIGH_SPEED; GenByteBoundary = FALSE; SendPreamble = FALSE; // assumes a low speed device is connected to the // host FrameNumber = 0; NumBulkInTrans = 0; // number of bulk in transactions NumSucBulkInTrans = 0; // number of successful bulk in transctions NumBulkOutTrans = 0; // number of bulk out transactions NumSucBulkOutTrans = 0; // number of successful bulk out transactions NumIsoInTrans = 0; // number of iso in transactions NumSucIsoInTrans = 0; // number of successful iso in transactions NumIsoOutTrans = 0; // number of iso out transactions NumSOF = 0; // number of SOF's sent NumCntrlRdTrans = 0; // number of control reads NumSucCntrlRdTrans = 0; // number of successful control reads NumCntrlWrTrans = 0; // number of control writes NumSucCntrlWrTrans = 0; // number of successful control writes NumIntrptTrans = 0; // number of interrupts NumSucIntrptTrans = 0; // number of successful interrupts NumIntrOutTrans = 0; // number of interrupt out transactions NumSucIntrOutTrans = 0; // number of successful interrupt out transactions NumResets = 0; // number of resets // intialize Jitter registers HighJitterTime = 0; LowJitterTime = 0; JitterPeriod = 0; JitterCount = 0; JitterOnOff = FALSE; // Jitter generation is off by default; task_in_progress = FALSE; clk_swtch = HIGH_SPEED; SetupDataLen = 8; GenByteBoundaryPos = FALSE; BoundaryBitVal = 1'b0; ModifyGran = 0; end assign clk = (clk_swtch == LOW_SPEED) ? ls_clk : hs_clk; assign clk4x = (clk_swtch == LOW_SPEED) ? clk6 : clk48; /////////////////////////////////////////////////////////////////////////////// // // task in_token : sends an in token on to the bus. // inputs : address : 7 bits : endpoint address // EndPt : 4 bits : endpoint number // /////////////////////////////////////////////////////////////////////////////// task in_token; input [6:0] address; input [3:0] EndPt; reg [15:0] tmpReg; begin in_out_buf[0] = CorruptToken({~IN_TOKEN, IN_TOKEN}); tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SendData; end endtask /////////////////////////////////////////////////////////////////////////////// // // task out_token : sends an out token on to the bus. // inputs : address : 7 bits : endpoint address // EndPt : 4 bits : endpoint number // /////////////////////////////////////////////////////////////////////////////// task out_token; input [6:0] address; input [3:0] EndPt; reg [15:0] tmpReg; begin in_out_buf[0] = CorruptToken({~OUT_TOKEN, OUT_TOKEN}); tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SendData; end endtask /////////////////////////////////////////////////////////////////////////////// // // task setup_token : sends an setup token on to the bus // inputs : address : 7 bits : endpoint address // EndPt : 4 bits : endpoint number // /////////////////////////////////////////////////////////////////////////////// task setup_token; input [6:0] address; input [3:0] EndPt; reg [15:0] tmpReg; begin in_out_buf[0] = CorruptToken({~SETUP_TOKEN, SETUP_TOKEN}); tmpReg[15:0] = FillCrc5({EndPt, address}); in_out_buf[1] = tmpReg[7:0]; in_out_buf[2] = tmpReg[15:8]; in_out_buf_ptr = 3; SendData; end endtask /////////////////////////////////////////////////////////////////////////////// // // task send_ack : sends an ACK on to the bus // /////////////////////////////////////////////////////////////////////////////// task send_ack; begin in_out_buf[0] = CorruptHshk({~ACK, ACK}); in_out_buf_ptr = 1; SendData; end endtask /////////////////////////////////////////////////////////////////////////////// // // task send_nak : sends a NAK on the bus (though an host is not supposed // to send a NAK) // /////////////////////////////////////////////////////////////////////////////// task send_nak; begin in_out_buf[0] = CorruptHshk({~NAK, NAK}); in_out_buf_ptr = 1; SendData; end endtask /////////////////////////////////////////////////////////////////////////////// // // task send_stall : sends a STALL on to the bus (though an host is not // supposed to send a STALL) // /////////////////////////////////////////////////////////////////////////////// task send_stall; begin in_out_buf[0] = CorruptHshk({~STALL, STALL}); in_out_buf_ptr = 1; SendData; end endtask /////////////////////////////////////////////////////////////////////////////// // // task wait_for_data : waits for a response on the bus and decodes the // data packet and returns a status indicating what // type of packet was received. // Output : PackType : 4'b0010 : ACK // 4'b1010 : NAK // 4'b1110 : STALL // 4'b0011 : DATA0 // 4'b1011 : DATA1 // 4'b1111 : Unknown // ByteCount : indicates the number of bytes of data present if // PackType is of DATA0 or DATA1 // Status : 0 : command executed successfully. // 3 : time out, no response. // 4 : invalid response, unknown packet type // 5 : CRC error on received data // 11 : corrupted ACK/NAK/STALL // 12 : corrupted DATA0/DATA1 pid, CRC correct // 13 : corrupted DATA0/DATA1 pid, CRC incorrect // // /////////////////////////////////////////////////////////////////////////////// task wait_for_data; output [31:0] ByteCount; output [3:0] PackType; output [3:0] Status; reg [15:0] tmpReg; reg [15:0] tmpCrc; reg [31:0] recv_bit_count; integer i; begin WaitForResp(recv_bit_count); PackType = 4'b1111; Status = 0; case (in_out_buf_ptr) 0 : begin Status = 3; // timeout if (dec_bit_stuff_err == TRUE) usb_idle(RespTimeOutVal); end 1 : begin tmpReg[7:0] = in_out_buf[0]; case (tmpReg[3:0]) ACK : PackType = ACK; NAK : PackType = NAK; STALL : PackType = STALL; default : PackType = 4'b1111; endcase if (((tmpReg == ACK) | (tmpReg == NAK) | (tmpReg == STALL)) & (~tmpReg[7:4] != tmpReg[3:0])) Status = 11; end 2 : begin Status = 4; PackType = 4'b1111; end default : begin // since the number of bytes received is greater than 2 this // obviously should be a data packet tmpReg[7:0] = in_out_buf[0]; ByteCount = 0; tmpCrc = 16'hffff; if ((tmpReg[3:0] == DATA0) | (tmpReg[3:0] == DATA1)) begin for ( i = 1; i < (in_out_buf_ptr - 2); i = i + 1) begin tmpCrc = crc16(in_out_buf[i], tmpCrc); RecvBuffer[i - 1] = in_out_buf[i]; ByteCount = ByteCount + 1; end tmpCrc = ~{swap8(tmpCrc[15:8]), swap8(tmpCrc[7:0])}; if (tmpCrc != {in_out_buf[in_out_buf_ptr - 2], in_out_buf[in_out_buf_ptr - 1]}) Status = 5; if (~tmpReg[7:4] != tmpReg[3:0]) begin if (Status == 5) Status = 13; else Status = 12; end PackType = tmpReg[3:0]; end else PackType = 4'b1111; end endcase end endtask parameter MYACK = 4'b0000, MYNAK = 4'b0001, MYSTALL = 4'b0010, MYTOUT = 4'b0011, MYIVRES = 4'b0100, MYCRCER = 4'b0101; parameter OUT = 2'b00, IN = 2'b10, SOF = 2'b01, SETUP=2'b11; // Control Packet format; reg [24:0] ControlPkt; reg [3:0] Status; integer ByteCount; task printstatus; input [3:0] RecvdStatus; input [3:0] ExpStatus; begin $display(""); $display(" #######################################################"); if(RecvdStatus !== ExpStatus ) begin $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 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 send_token; input [1:0] tkn; input [6:0] adr; input [3:0] ep; reg [2:0] Status; reg [15:0] tmpreg; begin XmitBuffer[0] = {~tkn,2'b10, tkn, 2'b01}; tmpreg = FillCrc5({ep, adr}); XmitBuffer[1] = tmpreg[7:0]; XmitBuffer[2] = tmpreg[15:8]; transfer_buf(3, 0, Status); end endtask task send_datapkt; input datatgl; input [10:0] numbytes; integer i; reg [15:0] tmpcrc; reg [2:0] Status; begin // Shifting the XmitBuffer Values to put the DataTkn in Byte0. for(i=numbytes; i > 0; i=i-1) begin XmitBuffer[i] = XmitBuffer[i-1]; end XmitBuffer[0] = {!datatgl, 3'b100, datatgl, 3'b011}; tmpcrc = crc16(XmitBuffer[1], 16'hffff); for(i=1; i < numbytes; i=i+1) begin tmpcrc = crc16(XmitBuffer[i+1], tmpcrc); end if(numbytes > 0) begin XmitBuffer[numbytes+1] = ~swap8(tmpcrc[15:8]); XmitBuffer[numbytes+2] = ~swap8(tmpcrc[7:0]); end else begin XmitBuffer[numbytes+1] = 8'b0000_0000; XmitBuffer[numbytes+2] = 8'b0000_0000; end transfer_buf(numbytes+3, 0, Status); 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 GetConfiguration; begin XmitBuffer[0] = 8'b1000_0000; XmitBuffer[1] = 8'b0000_1000; // get config. XmitBuffer[2] = 8'b0000_0000; XmitBuffer[3] = 8'b0000_0000; XmitBuffer[4] = 8'b0000_0000; XmitBuffer[5] = 8'b0000_0000; XmitBuffer[6] = 8'b0000_0001; 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 GetDescriptor; input [2:0] des_type_new; input [2:0] des_index; input [15:0] des_size; begin XmitBuffer[0] = 8'b1000_0000; XmitBuffer[1] = 8'b0000_0110; XmitBuffer[2] = {5'b00000, des_index}; XmitBuffer[3] = {5'b00000, des_type_new}; XmitBuffer[4] = 8'b0000_0000; XmitBuffer[5] = 8'b0000_0000; XmitBuffer[6] = des_size[7:0]; XmitBuffer[7] = des_size[15:8]; end endtask task SetDescriptor; input [2:0] des_type_new; input [2:0] des_index; input [15:0] des_size; begin XmitBuffer[0] = 8'b0000_0000; XmitBuffer[1] = 8'b0000_0111; XmitBuffer[2] = {5'b00000, des_index}; XmitBuffer[3] = {5'b00000, des_type_new}; XmitBuffer[4] = 8'b0000_0000; XmitBuffer[5] = 8'b0000_0000; XmitBuffer[6] = des_size[7:0]; XmitBuffer[7] = des_size[15:8]; end endtask task SynchFrame; begin XmitBuffer[0] = 8'b1000_0010; XmitBuffer[1] = 8'b0000_1100; XmitBuffer[2] = 8'b0000_0000; 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; 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; 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 != MYACK) control_IN(address, 4'h0, ByteCount, Status); if (Status != MYACK) 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; output [31:0] ByteCount; 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 != MYACK) control_IN(address, 4'h0, ByteCount, Status); if (Status != MYACK) 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 -> tb.test_control.error_detected; $display( "usb_agent check: Register Read Byte Mismatch !!! Exp: %x ; Rxd: %x",dataword[31:0], {RecvBuffer[0],RecvBuffer[1], RecvBuffer[2],RecvBuffer[3]} ); dump_recv_buffer(ByteCount); 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; 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 != MYACK) control_IN(address, 4'h0, ByteCount, Status); if (Status != MYACK) control_IN(address, 4'h0, ByteCount, Status); if ((RecvBuffer[0] !== dataword[7:0]) || (RecvBuffer[1] !== dataword[15:8])) begin -> tb.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; 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 != MYACK) control_IN(address, 4'h0, ByteCount, Status); if (Status != MYACK) control_IN(address, 4'h0, ByteCount, Status); if ((RecvBuffer[0] !== dataword[7:0])) begin -> tb.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 /*****************************************/ assign DPLS = zDPLS; assign DMNS = zDMNS; //instantiate the encoder usb_bfm_encoder u_usb_enc ( .enable_in (enc_enbl), .reset_n (enc_reset_n), .clk (clk), .bit_count_out (enc_bit_count_out), .count_out (enc_count_out), .data_out_valid (enc_data_out_valid), .gen_bit_stuff_err (BitStuffErr), .last_byte (enc_last_byte), .start_bit (DeviceSpeed), .data_in (enc_data_in), .data_out (DPLS), .data_out_n (DMNS) ); //instantiate the decoder usb_bfm_decoder u_usb_dec ( .enable_in (dec_enbl), .ser_data_rdy (dec_ser_data_rdy), .par_data_rdy (dec_par_data_rdy), .reset_n (dec_reset_n), .clk (dpll_clk), .start_bit (DeviceSpeed), // 1'b1), .data_in (DPLS), .data_in_n (DMNS), .recv_bit_count (dec_recv_bit_count), .bit_stuff_err (dec_bit_stuff_err), .ser_data_out (), .par_data_out (dec_par_data_out) ); usb_bfm_dpll dpll_inst ( .clk48 (clk4x), .clk6 (clk4x), .switch (~DeviceSpeed), .reset_n (dpll_reset_n), .data_in (DPLS), .rec_clk (dpll_clk), .data_out () ); always begin if (JitterOnOff == TRUE) begin if (tmpJitterCount > 0) begin #(PulseWidth - LowJitterTime) hs_clk = 1'b1; #(PulseWidth - HighJitterTime) hs_clk = 1'b0; tmpJitterCount = tmpJitterCount - 1; if (tmpJitterCount == 0) begin tmpJitterPeriod = JitterPeriod; end end else begin #PulseWidth hs_clk = 1'b1; #PulseWidth hs_clk = 1'b0; if (tmpJitterPeriod == 0) begin tmpJitterCount = JitterCount; end tmpJitterPeriod = tmpJitterPeriod - 1; end end else begin #PulseWidth hs_clk = 1'b1; #PulseWidth hs_clk = 1'b0; end end always begin if (JitterOnOff == TRUE) begin if (tmpJitterCount > 0) begin #((PulseWidth * 8) - LowJitterTime) ls_clk = 1'b1; #((PulseWidth * 8) - HighJitterTime) ls_clk = 1'b0; tmpJitterCount = tmpJitterCount - 1; if (tmpJitterCount == 0) begin tmpJitterPeriod = JitterPeriod; end end else begin #(PulseWidth * 8) ls_clk = 1'b1; #(PulseWidth * 8) ls_clk = 1'b0; if (tmpJitterPeriod == 0) begin tmpJitterCount = JitterCount; end tmpJitterPeriod = tmpJitterPeriod - 1; end end else begin #(PulseWidth * 8) ls_clk = 1'b1; #(PulseWidth * 8) ls_clk = 1'b0; end end initial // intialise pll clock signals begin tmpJitterPeriod = 0; tmpJitterCount = 0; dpll_reset_n = 1'b0; #1 dpll_reset_n = 1'b1; end initial // drive 6 MHz clock begin clk6 = 1'b0; forever #(PulseWidth * 2) clk6 = ~clk6; end initial // drive 48 MHz clock begin clk48 = 1'b0; HSClkComp = 1'b0; HSClkCompToggle = 1'b0; case ((PulseWidth) % 4) 0 : HSClkComp = 1'b0; 1 : HSClkComp = 1'b0; 2 : HSClkComp = 1'b1; 3 : HSClkComp = 1'b1; default : HSClkComp = 1'b0; endcase forever begin #((PulseWidth / 4) + HSClkComp) clk48 = 1'b1; case ((PulseWidth) % 4) 0, 2 : begin #(PulseWidth / 4) clk48 = 1'b0; HSClkComp = ((PulseWidth % 4) == 0) ? 1'b0 : 1'b1; end 1, 3 : begin if (HSClkCompToggle == 1'b0) begin #(PulseWidth / 4) clk48 = 1'b0; HSClkCompToggle = 1'b1; end else begin #((PulseWidth / 4) + HSClkCompToggle) clk48 = 1'b0; HSClkCompToggle = 1'b0; end HSClkComp = ((PulseWidth % 4) == 1) ? 1'b0 : 1'b1; end default : clk48 = 1'b1; endcase end end always @(dpll_clk) rec_clk = dpll_clk; //initialise the encoder signals initial begin hs_clk = 1'b1; ls_clk = 1'b1; enc_enbl = 1'b0; // active high enc_reset_n = 1'b0; // active low enc_data_in = 8'bZZZZZZZZ; zDPLS = 1'bZ; zDMNS = 1'bZ; dec_enbl = 1'b0; // active high dec_reset_n = 1'b0; // active low // dec_cnt; // user_commands; // Invoking the User Commands. end initial begin `ifdef USBF_DEBUG Debug = TRUE ; `else Debug = FALSE ; `endif sofOnFlag = FALSE ; //sofPeriod = 1_000_000 ; sofPeriod = 100_000 ; interruptOnFlag = FALSE ; interruptRequest = FALSE ; interruptTimer = 0 ; interruptPeriod = 0 ; controlRequest = FALSE ; controlGrant = FALSE ; bulkInOnFlag = FALSE ; bulkOutOnFlag = FALSE ; end endmodule module usb_bfm_decoder( enable_in, ser_data_rdy, par_data_rdy, reset_n, clk, start_bit, data_in, data_in_n, recv_bit_count, bit_stuff_err, ser_data_out, par_data_out ); input enable_in; output ser_data_rdy; output par_data_rdy; input clk; input start_bit; input data_in; input data_in_n; output [31:0] recv_bit_count; output bit_stuff_err; output ser_data_out; output [7:0] par_data_out; input reset_n; reg enable_out; reg [7:0] par_data_out; reg ser_data_out; reg prev_bit; reg prev_bit1; reg tmpDataOut1; reg [7:0] tmpDataOut; reg [31:0] recv_bit_count; reg bit_stuff_err; reg ser_data_rdy; reg par_data_rdy; reg JustEnabled; reg [3:0] bit_count; reg [3:0] count; reg SyncDetect; initial begin enable_out = 1; ser_data_out = 1'bz; ser_data_rdy = 1'b0; par_data_out = 8'b0000_0000; bit_count = 0; count = 0; tmpDataOut = 8'b00000000; tmpDataOut1 = 0; JustEnabled = 1; par_data_rdy = 1'b0; recv_bit_count = 32'h0000_0000; bit_stuff_err = 1'b0; end always @(posedge clk) #1 prev_bit1 <= data_in; always @(posedge clk) begin if (!reset_n) begin count <= 0; recv_bit_count <= 1'b0; bit_count <= 0; par_data_out <= 8'b0000_0000; end if (enable_in) begin if (count == 7 && !(bit_count==5 & (tmpDataOut1!=prev_bit))) begin par_data_rdy <= 1'b1; end if (bit_count < 5) begin if (count == 7) count <= 0; else count <= count + 1; par_data_out[count] <= tmpDataOut1; recv_bit_count <= recv_bit_count + 1; ser_data_rdy <= 1'b1; ser_data_out <= tmpDataOut1; end else begin if (tmpDataOut1 != 1'b0) begin bit_stuff_err <= 1'b1; end ser_data_rdy <= 1'b0; end end else begin bit_stuff_err <= 1'b0; par_data_rdy <= 1'b0; end prev_bit <= tmpDataOut1; if ((tmpDataOut1 == prev_bit) & (tmpDataOut1 == 1'b1)) begin bit_count <= bit_count + 1; end else begin bit_count <= 0; end if (bit_count == 5) bit_count <= 0; if (prev_bit1 == data_in) tmpDataOut1 <= 1'b1; else tmpDataOut1 <= 1'b0; if (par_data_rdy == 1'b1) par_data_rdy <= 1'b0; end endmodule module usb_bfm_encoder( enable_in, reset_n, clk, bit_count_out, count_out, data_out_valid, gen_bit_stuff_err, last_byte, start_bit, data_in, data_out, data_out_n ); //enable_in : 0 disables the block // 1 enables the block //data_in : 8 bit wide register containing the parallel data //clk : Clock !! //not used//data_in_valid : the data in data_in is a valid next block of data //count_out : count[2] //data_out : serial data out //data_out_n : invert of data_out //data_out_valid : the data on data_out is valid and can be sampled //reset_n : synchronous reset of the block input enable_in; input clk; input gen_bit_stuff_err; input [7:0] data_in; input reset_n; input last_byte; input start_bit; output [3:0] bit_count_out; output count_out; output data_out; output data_out_n; output data_out_valid; reg [3:0] bit_count_out; reg count_out; reg data_out; reg data_out_n; reg data_out_valid; reg tmpDataOut1; reg tmpDataOut2; reg prev_bit; reg tmpDataOut; reg [3:0] count; reg [3:0] bit_count; reg [7:0] tmpDataIn; initial begin data_out = 1'bZ; data_out_n = 1'bZ; count = 0; bit_count = 0; bit_count_out = 0; count_out = 0; data_out_valid = 0; tmpDataOut1 = start_bit; tmpDataOut = 0; prev_bit = 0; end always @(posedge clk) begin if (enable_in) begin if (count == 0) tmpDataIn = data_in; if (count < 8) begin tmpDataOut = tmpDataIn[count]; if ((tmpDataOut) & (prev_bit)) begin bit_count = bit_count + 1; end else begin if (tmpDataOut) bit_count = 1; else begin if (bit_count == 6) bit_count = 7; else bit_count = 0; end end if (bit_count == 7) begin if (gen_bit_stuff_err == 1'b0) begin tmpDataOut1 = ~tmpDataOut1; prev_bit = 1'b0; end else begin tmpDataOut1 = tmpDataOut1; prev_bit = 1'b1; end bit_count = 0; end else begin if (tmpDataIn[count] == 0) tmpDataOut1 = ~tmpDataOut1; count = count + 1; prev_bit = tmpDataOut; end data_out = #1 tmpDataOut1; data_out_n = ~tmpDataOut1; data_out_valid = 1; end if (count == 8) count = 0; if (bit_count != 6) count_out = count[2]; bit_count_out = count; end else begin data_out = #1 1'bz; data_out_n = 1'bz; data_out_valid = 0; end if (!reset_n) begin count = 0; count_out = 0; bit_count = 0; data_out_valid = 0; tmpDataIn = 8'h00; tmpDataOut1 = start_bit; tmpDataOut = 0; prev_bit = 0; data_out = #1 1'bz; data_out_n = 1'bz; end end endmodule module usb_bfm_dpll (clk48, clk6, switch, reset_n, data_in, rec_clk, data_out); input clk48, clk6, switch, reset_n, data_in; output rec_clk, data_out; wire rec_clk; wire data_out; wire nrz; wire dpll_clk; assign data_out = nrz; wire diff_pulse; // Instance of the clock switch usb_bfm_clk_switch clk_switch (.clk1 (clk48), .clk2 (clk6), .switch (switch), .reset_n (reset_n), .clk_out (dpll_clk)); // Instance of NRZI to NRZ converter usb_bfm_nrzi2nrz nrzi2nrz_inst (.nrzi (data_in), .rec_clk (rec_clk), .reset_n (reset_n), .nrz (nrz)); // Instance of the phase detect usb_bfm_ph_detect ph_detect (.dpll_clk (dpll_clk), .rst_n (reset_n), .data_in (data_in), .rec_clk (rec_clk), .diff_pulse (diff_pulse)); // Instance of the pulse puller state machine usb_bfm_pulse_puller pulse_puller (.clk (dpll_clk), .diff_pulse (diff_pulse), .rst_n (reset_n), .rec_clk (rec_clk)); endmodule // The clock switch module for selecting a low/high speed PLL module usb_bfm_clk_switch (clk1, clk2, switch, reset_n, clk_out); input clk1, clk2, switch, reset_n; output clk_out; wire ff1set, ff1clr, ff3clr, clk_out; reg ff1out, ff2out_bar, ff3out, ff3out_bar, ff4out_bar; assign ff1set = ff4out_bar; assign ff1clr = reset_n; assign ff3clr = ff2out_bar; assign clk_out = ((ff1out | clk1) & (ff3out_bar | clk2)); parameter LOW = 1'b0; parameter HIGH = 1'b1; //Filp Flop # 1 always @ (posedge clk1 or negedge ff1set or negedge ff1clr) begin if (ff1clr === LOW) begin ff1out = LOW; end else if (ff1set === LOW) begin ff1out = HIGH; end else ff1out <= switch; end //Flip Flop # 2 always @ (posedge clk2) begin ff2out_bar <= (ff1out); end //Flip Flop #3 always @ (posedge clk2 or negedge ff3clr) begin if (ff3clr === LOW) begin ff3out <= LOW; ff3out_bar <= HIGH; end else begin ff3out <= switch; ff3out_bar <= !switch; end end //Flip Flop #4 always @ (posedge clk1) begin ff4out_bar <= ! (ff3out); end endmodule // The NRZI to NRZ converter module usb_bfm_nrzi2nrz (nrzi, rec_clk, reset_n, nrz); input nrzi, rec_clk, reset_n; output nrz; wire nrz; wire D1, D2, D0; reg Q1, Q2, Q0; reg del_rec_clk; assign D0 = nrzi; assign D1 = Q0; assign D2 = !(Q0^Q1); assign nrz = Q2; //NRZI to NRZ converter always @ (reset_n) begin if (!reset_n) begin Q0 <= 1'b0; Q1 <= 1'b0; Q2 <= 1'b0; end end always @ (rec_clk) begin del_rec_clk <= #21 rec_clk; end always @(posedge del_rec_clk) begin Q0 <= D0; Q1 <= D1; Q2 <= D2; end endmodule // The Phase detector module usb_bfm_ph_detect (dpll_clk, rst_n, data_in, rec_clk, diff_pulse); input dpll_clk, rst_n, data_in, rec_clk; output diff_pulse; wire diff_pulse; reg Q0; reg rec_clk_neg_edge; reg gate_control; assign diff_pulse = (Q0 ^ data_in) & gate_control; always @ (posedge dpll_clk or negedge rst_n) begin if (rst_n) begin if ((Q0 ^ data_in) & rec_clk_neg_edge) begin gate_control <= 1'b0; rec_clk_neg_edge <= 1'b0; end end else begin gate_control <= 1'b1; rec_clk_neg_edge <= 1'b0; end rec_clk_neg_edge <= 1'b0; end always @ (negedge rec_clk or negedge rst_n) begin if (rst_n) begin Q0 <= data_in; rec_clk_neg_edge <= 1'b1; gate_control <= 1'b1; end else begin Q0 <= 1'b0; end end endmodule // The State m/c which does the Phase Correction module usb_bfm_pulse_puller (clk, diff_pulse, rst_n, rec_clk); input clk, rst_n, diff_pulse; output rec_clk; reg rec_clk; reg [3:0] State; reg correct_pulse; reg Q0; parameter HIGH = 1'b1; parameter LOW = 1'b0; parameter S0 = 3'b000; parameter S1 = 3'b001; parameter S2 = 3'b010; parameter S3 = 3'b011; parameter S4 = 3'b100; // Generation of the correcting pulse from the Phase difference between the // data transition and negative edge of recovered clock always @ (posedge clk) begin Q0 <= diff_pulse; correct_pulse <= Q0 & diff_pulse; end // The pulse_puller state machine always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin State <= S0; rec_clk <= LOW; end else begin case (State) S0 : begin State <= S1; rec_clk <= ~rec_clk; end S1 : if (correct_pulse) begin rec_clk <= ~rec_clk; State <= S3; end else begin rec_clk <= rec_clk; State <= S2; end S2 : begin if (correct_pulse) begin State <= S4; end else begin State <= S3; end rec_clk <= ~rec_clk; end S3 : if (correct_pulse) begin State <= S1; rec_clk <= ~rec_clk; end else begin rec_clk <= rec_clk; State <= S4; end S4 : begin if (correct_pulse) begin State <= S2; end else begin State <= S1; end rec_clk <= ~rec_clk; end default : $display ("Illegal State at ",$time); endcase end end endmodule