def test_control_transfer_out_in(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.OUT)) yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.IN)) yield harness.write(harness.csrs['usb_address'], 0) yield harness.control_transfer_out( 0, # Set address (to 20) [0x00, 0x05, 20, 0x00, 0x00, 0x00, 0x00, 0x00], # 18 byte descriptor, max packet size 8 bytes None, ) yield harness.write(harness.csrs['usb_address'], 20) yield harness.control_transfer_in( 20, # Get device descriptor [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 00], # 18 byte descriptor, max packet size 8 bytes [ 0x12, 0x01, 0x10, 0x02, 0x02, 0x00, 0x00, 0x40, 0x09, 0x12, 0xB1, 0x70, 0x01, 0x01, 0x01, 0x02, 00, 0x01 ], )
def test_control_transfer_out(dut): """Low-level test for register states during OUT transfer""" harness = get_harness(dut) yield harness.reset() yield harness.connect() yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.OUT)) yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.IN)) epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) ADDR = 20 SETUP_DATA = [0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x0A, 0x00] DESCRIPTOR_DATA = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B ] yield harness.write(harness.csrs['usb_address'], ADDR) yield harness.host_send_sof(0) if (SETUP_DATA[0] & 0x80) == 0x80: raise Exception("setup_data indicated an IN transfer, but you " "requested an OUT transfer") setup_ev = yield harness.read(harness.csrs['usb_setup_ev_pending']) if setup_ev != 0: raise TestFailure("setup_ev should be 0 at the start of the test, " "was: {:02x}".format(setup_ev)) # Setup stage harness.dut._log.info("setup stage") yield harness.transaction_setup(ADDR, SETUP_DATA) setup_ev = yield harness.read(harness.csrs['usb_setup_ev_pending']) if setup_ev != 1: raise TestFailure("setup_ev should be 1, was: {:02x}".format(setup_ev)) yield harness.write(harness.csrs['usb_setup_ev_pending'], setup_ev) # Data stage out_ev = yield harness.read(harness.csrs['usb_out_ev_pending']) if out_ev != 0: raise TestFailure("out_ev should be 0 at the start of the test, " "was: {:02x}".format(out_ev)) harness.dut._log.info("data stage") yield harness.transaction_data_out(ADDR, epaddr_out, DESCRIPTOR_DATA) # Status stage harness.dut._log.info("status stage") yield harness.write(harness.csrs['usb_in_ctrl'], 0) # Send empty IN packet in_ev = yield harness.read(harness.csrs['usb_in_ev_pending']) if in_ev != 0: raise TestFailure("o: in_ev should be 0 at the start of the test, " "was: {:02x}".format(in_ev)) yield harness.transaction_status_in(ADDR, epaddr_in) yield RisingEdge(harness.dut.clk12) yield RisingEdge(harness.dut.clk12) in_ev = yield harness.read(harness.csrs['usb_in_ev_pending']) if in_ev != 1: raise TestFailure("o: in_ev should be 1 at the end of the test, " "was: {:02x}".format(in_ev)) yield harness.write(harness.csrs['usb_in_ev_pending'], in_ev) yield harness.write(harness.csrs['usb_in_ctrl'], 1 << 5) # Reset IN buffer
def test_control_transfer_in(dut): """Low-level test for register states during IN transfer""" harness = get_harness(dut) yield harness.reset() yield harness.connect() yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.OUT)) yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.IN)) epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) ADDR = 20 SETUP_DATA = [0x80, 0x06, 0x00, 0x06, 0x00, 0x00, 0x0A, 0x00] DESCRIPTOR_DATA = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B ] yield harness.write(harness.csrs['usb_address'], 20) yield harness.host_send_sof(0) setup_ev = yield harness.read(harness.csrs['usb_setup_ev_pending']) if setup_ev != 0: raise TestFailure("setup_ev should be 0 at the start of the test, " "was: {:02x}".format(setup_ev)) # Setup stage harness.dut._log.info("setup stage") yield harness.transaction_setup(ADDR, SETUP_DATA) # Data stage in_ev = yield harness.read(harness.csrs['usb_in_ev_pending']) if in_ev != 0: raise TestFailure("in_ev should be 0 at the start of the test, " "was: {:02x}".format(in_ev)) harness.dut._log.info("data stage") yield harness.transaction_data_in(ADDR, epaddr_in, DESCRIPTOR_DATA) # Give the signal two clock cycles to percolate through the event manager yield RisingEdge(harness.dut.clk12) yield RisingEdge(harness.dut.clk12) # Status stage yield harness.write(harness.csrs['usb_out_ctrl'], 0x10) # Empty IN packet harness.dut._log.info("status stage") out_ev = yield harness.read(harness.csrs['usb_out_ev_pending']) if out_ev != 0: raise TestFailure("i: out_ev should be 0 at the start of the test, " "was: {:02x}".format(out_ev)) yield harness.transaction_status_out(ADDR, epaddr_out) yield RisingEdge(harness.dut.clk12) # give two cycles to percolate through multiregs and event manager yield RisingEdge(harness.dut.clk12) yield RisingEdge(harness.dut.clk12) out_ev = yield harness.read(harness.csrs['usb_out_ev_pending']) if out_ev != 1: raise TestFailure("i: out_ev should be 1 at the end of the test, " "was: {:02x}".format(out_ev)) yield harness.write(harness.csrs['usb_out_ctrl'], 0x20) # Reset FIFO yield harness.write(harness.csrs['usb_out_ev_pending'], out_ev)
def control_transfer_in(self, addr, setup_data, descriptor_data=None): epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) if (setup_data[0] & 0x80) == 0x00: raise Exception( "setup_data indicated an OUT transfer, but you requested" "an IN transfer" ) setup_ev = yield self.read(self.csrs['usb_setup_ev_pending']) # Setup stage self.dut._log.info("setup stage") yield self.transaction_setup(addr, setup_data) self.request_deadline = get_sim_time("us") + super().MAX_REQUEST_TIME setup_ev = yield self.read(self.csrs['usb_setup_ev_pending']) yield self.write(self.csrs['usb_setup_ev_pending'], setup_ev) # Data stage in_ev = yield self.read(self.csrs['usb_in_ev_pending']) if (setup_data[7] != 0 or setup_data[6] != 0) and descriptor_data is None: raise Exception( "setup_data indicates data, but no descriptor data" "was specified" ) if (setup_data[7] == 0 and setup_data[6] == 0) and descriptor_data is not None: raise Exception( "setup_data indicates no data, but descriptor data" "was specified" ) if descriptor_data is not None: self.dut._log.info("data stage") yield self.transaction_data_in(addr, epaddr_in, descriptor_data) # Give the signal two clock cycles # to percolate through the event manager yield RisingEdge(self.dut.clk12) yield RisingEdge(self.dut.clk12) in_ev = yield self.read(self.csrs['usb_in_ev_pending']) yield self.write(self.csrs['usb_in_ev_pending'], in_ev) # Status stage self.packet_deadline = get_sim_time("us") + super().MAX_PACKET_TIME yield self.write(self.csrs['usb_out_ctrl'], 0x10) # Send empty packet self.dut._log.info("status stage") out_ev = yield self.read(self.csrs['usb_out_ev_pending']) yield self.transaction_status_out(addr, epaddr_out) yield RisingEdge(self.dut.clk12) out_ev = yield self.read(self.csrs['usb_out_ev_pending']) yield self.write(self.csrs['usb_out_ctrl'], 0x20) # Reset FIFO yield self.write(self.csrs['usb_out_ev_pending'], out_ev) # Was the time limit honored? if get_sim_time("us") > self.request_deadline: raise TestFailure("Failed to process the IN request in time")
def control_transfer_in(self, addr, setup_data, descriptor_data=None): """Perform an IN control transfer. Args: addr (int): Device address. setup_data: Request to be sent, as list of bytes. descriptor_data (optional): Data expected to be received, as list of bytes. """ epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) # Data sanity check if (setup_data[0] & 0x80) == 0x00: raise Exception( "setup_data indicated an OUT transfer, but you requested" "an IN transfer" ) if (setup_data[7] != 0 or setup_data[6] != 0) and descriptor_data is None: raise Exception( "setup_data indicates data, but no descriptor data" "was specified" ) if (setup_data[7] == 0 and setup_data[6] == 0) and descriptor_data is not None: raise Exception( "setup_data indicates no data, but descriptor data" "was specified" ) # Setup stage self.dut._log.info("setup stage") self.packet_deadline = get_sim_time("us") + self.MAX_PACKET_TIME yield self.transaction_setup(addr, setup_data) self.request_deadline = get_sim_time("us") + self.MAX_REQUEST_TIME if descriptor_data is not None: # Data stage self.dut._log.info("data stage") yield self.transaction_data_in(addr, epaddr_in, descriptor_data) # Give the signal one clock cycle to perccolate through # the event manager yield RisingEdge(self.dut.clk48_host) # Status stage self.dut._log.info("status stage") self.packet_deadline = get_sim_time("us") + self.MAX_PACKET_TIME yield self.transaction_status_out(addr, epaddr_out) # Was the time limit honored? if get_sim_time("us") > self.request_deadline: raise TestFailure("Failed to process the IN request in time") yield RisingEdge(self.dut.clk48_host)
def control_transfer_out(self, addr, setup_data, descriptor_data=None): epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) if (setup_data[0] & 0x80) == 0x80: raise Exception( "setup_data indicated an IN transfer, but you requested" "an OUT transfer" ) setup_ev = yield self.read(self.csrs['usb_setup_ev_pending']) # Setup stage self.dut._log.info("setup stage") yield self.transaction_setup(addr, setup_data) self.request_deadline = get_sim_time("us") + super().MAX_REQUEST_TIME setup_ev = yield self.read(self.csrs['usb_setup_ev_pending']) yield self.write(self.csrs['usb_setup_ev_pending'], setup_ev) # Data stage if (setup_data[7] != 0 or setup_data[6] != 0) and descriptor_data is None: raise Exception( "setup_data indicates data, but no descriptor data" "was specified" ) if (setup_data[7] == 0 and setup_data[6] == 0) and descriptor_data is not None: raise Exception( "setup_data indicates no data, but descriptor data" "was specified" ) if descriptor_data is not None: self.dut._log.info("data stage") yield self.transaction_data_out(addr, epaddr_out, descriptor_data) # Status stage self.dut._log.info("status stage") self.packet_deadline = get_sim_time("us") + super().MAX_PACKET_TIME yield self.write(self.csrs['usb_in_ctrl'], 0) # Send empty IN packet yield self.transaction_status_in(addr, epaddr_in) yield RisingEdge(self.dut.clk12) yield RisingEdge(self.dut.clk12) in_ev = yield self.read(self.csrs['usb_in_ev_pending']) yield self.write(self.csrs['usb_in_ev_pending'], in_ev) yield self.write(self.csrs['usb_in_ctrl'], 1 << 5) # Reset IN buffer # Was the time limit honored? if get_sim_time("us") > self.request_deadline: raise TestFailure("Failed to process the OUT request in time")
def test_control_transfer_in_nak_data(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 22 yield harness.write(harness.csrs['usb_address'], addr) # Get descriptor, Index 0, Type 03, LangId 0000, wLength 64 setup_data = [0x80, 0x06, 0x00, 0x03, 0x00, 0x00, 0x40, 0x00] in_data = [0x04, 0x03, 0x09, 0x04] epaddr_in = EndpointType.epaddr(0, EndpointType.IN) # yield harness.clear_pending(epaddr_in) yield harness.write(harness.csrs['usb_address'], addr) # Setup stage # ----------- yield harness.transaction_setup(addr, setup_data) # Data stage # ----------- yield harness.set_response(epaddr_in, EndpointResponse.NAK) yield harness.host_send_token_packet(PID.IN, addr, epaddr_in) yield harness.host_expect_nak() yield harness.set_data(epaddr_in, in_data) yield harness.set_response(epaddr_in, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, addr, epaddr_in) yield harness.host_expect_data_packet(PID.DATA1, in_data) yield harness.host_send_ack()
def test_in_transfer(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 28 epaddr = EndpointType.epaddr(1, EndpointType.IN) yield harness.write(harness.csrs['usb_address'], addr) d = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8] yield harness.clear_pending(epaddr) yield harness.set_response(epaddr, EndpointResponse.NAK) yield harness.set_data(epaddr, d[:4]) yield harness.set_response(epaddr, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, addr, epaddr) yield harness.host_expect_data_packet(PID.DATA0, d[:4]) yield harness.host_send_ack() pending = yield harness.pending(epaddr) if pending: raise TestFailure("data was still pending") yield harness.clear_pending(epaddr) yield harness.set_data(epaddr, d[4:]) yield harness.set_response(epaddr, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, addr, epaddr) yield harness.host_expect_data_packet(PID.DATA1, d[4:]) yield harness.host_send_ack()
def test_debug_out(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 28 yield harness.write(harness.csrs['usb_address'], addr) reg_addr = harness.csrs['ctrl_scratch'] setup_data = [ 0x43, 0x00, (reg_addr >> 0) & 0xff, (reg_addr >> 8) & 0xff, (reg_addr >> 16) & 0xff, (reg_addr >> 24) & 0xff, 0x04, 0x00 ] ep0in_addr = EndpointType.epaddr(0, EndpointType.IN) ep1in_addr = EndpointType.epaddr(1, EndpointType.IN) ep0out_addr = EndpointType.epaddr(0, EndpointType.OUT) # Force Wishbone to acknowledge the packet yield harness.clear_pending(ep0out_addr) yield harness.clear_pending(ep0in_addr) yield harness.clear_pending(ep1in_addr) # Setup stage yield harness.host_send_token_packet(PID.SETUP, addr, ep0out_addr) yield harness.host_send_data_packet(PID.DATA0, setup_data) yield harness.host_expect_ack() # Data stage yield harness.host_send_token_packet(PID.OUT, addr, ep0out_addr) yield harness.host_send_data_packet(PID.DATA1, [0x42, 0, 0, 0]) yield harness.host_expect_ack() # Status stage (wrong endopint) yield harness.host_send_token_packet(PID.IN, addr, ep1in_addr) yield harness.host_expect_nak() # Status stage yield harness.host_send_token_packet(PID.IN, addr, ep0in_addr) yield harness.host_expect_data_packet(PID.DATA1, []) yield harness.host_send_ack() new_value = yield harness.read(reg_addr) if new_value != 0x42: raise TestFailure( "memory at 0x{:08x} should be 0x{:08x}, but memory value\ was 0x{:08x}".format(reg_addr, 0x42, new_value))
def test_control_transfer_in_out_in(dut): """This transaction is pretty much the first thing any OS will do""" harness = get_harness(dut) yield harness.reset() yield harness.connect() yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.OUT)) yield harness.clear_pending(EndpointType.epaddr(0, EndpointType.IN)) yield harness.write(harness.csrs['usb_address'], 0) yield harness.control_transfer_in( 0, # Get device descriptor [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 00], # 18 byte descriptor, max packet size 8 bytes [ 0x12, 0x01, 0x10, 0x02, 0x02, 0x00, 0x00, 0x40, 0x09, 0x12, 0xB1, 0x70, 0x01, 0x01, 0x01, 0x02, 00, 0x01 ], ) yield harness.control_transfer_out( 0, # Set address (to 11) [0x00, 0x05, 11, 0x00, 0x00, 0x00, 0x00, 0x00], # 18 byte descriptor, max packet size 8 bytes None, ) yield harness.write(harness.csrs['usb_address'], 11) yield harness.control_transfer_in( 11, # Get device descriptor [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 00], # 18 byte descriptor, max packet size 8 bytes [ 0x12, 0x01, 0x10, 0x02, 0x02, 0x00, 0x00, 0x40, 0x09, 0x12, 0xB1, 0x70, 0x01, 0x01, 0x01, 0x02, 00, 0x01 ], )
def test_debug_in(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 28 yield harness.write(harness.csrs['usb_address'], addr) # The "scratch" register defaults to 0x12345678 at boot. reg_addr = harness.csrs['ctrl_scratch'] setup_data = [ 0xc3, 0x00, (reg_addr >> 0) & 0xff, (reg_addr >> 8) & 0xff, (reg_addr >> 16) & 0xff, (reg_addr >> 24) & 0xff, 0x04, 0x00 ] epaddr_in = EndpointType.epaddr(0, EndpointType.IN) epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) yield harness.transaction_data_in(addr, epaddr_in, [0x2, 0x4, 0x6, 0x8, 0xa], chunk_size=64) yield harness.clear_pending(epaddr_out) yield harness.clear_pending(epaddr_in) # Setup stage yield harness.host_send_token_packet(PID.SETUP, addr, epaddr_out) yield harness.host_send_data_packet(PID.DATA0, setup_data) yield harness.host_expect_ack() # Data stage yield harness.host_send_token_packet(PID.IN, addr, epaddr_in) yield harness.host_expect_data_packet(PID.DATA1, [0x12, 0, 0, 0]) yield harness.host_send_ack() # Status stage yield harness.host_send_token_packet(PID.OUT, addr, epaddr_in) yield harness.host_send_data_packet(PID.DATA1, []) yield harness.host_expect_ack()
def test_control_setup_clears_stall(dut): harness = get_harness(dut) harness.max_packet_size = model.deviceDescriptor.bMaxPacketSize0 yield harness.reset() yield harness.wait(1e3, units="us") yield harness.port_reset(10e3) yield harness.connect() yield harness.wait(1e3, units="us") # After waiting (bus inactivity) let's start with SOF yield harness.host_send_sof(0x01) addr = 13 yield harness.set_device_address(addr) yield harness.set_configuration(1) yield harness.wait(1e2, units="us") epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) d = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0, 0] # send the data -- just to ensure that things are working yield harness.transaction_data_out(addr, epaddr_out, d) # send it again to ensure we can re-queue things. yield harness.transaction_data_out(addr, epaddr_out, d) # Set endpoint HALT explicitly yield harness.transaction_setup( addr, setFeatureRequest(FeatureSelector.ENDPOINT_HALT, USBDeviceRequest.Type.ENDPOINT, 0)) harness.packet_deadline = get_sim_time("us") + harness.MAX_PACKET_TIME yield harness.transaction_data_in(addr, 0, []) # do another receive, which should fail harness.retry = True harness.packet_deadline = get_sim_time("us") + 1e3 # try for a ms while harness.retry: yield harness.host_send_token_packet(PID.IN, addr, 0) yield harness.host_expect_stall() if get_sim_time("us") > harness.packet_deadline: raise cocotb.result.TestFailure("Did not receive STALL token") # do a setup, which should pass yield harness.get_device_descriptor(response=model.deviceDescriptor.get()) # finally, do one last transfer, which should succeed now # that the endpoint is unstalled. yield harness.get_device_descriptor(response=model.deviceDescriptor.get())
def test_valentyusb_cdc(dut): harness = get_harness(dut) harness.max_packet_size = model.deviceDescriptor.bMaxPacketSize0 yield harness.reset() yield harness.connect() yield harness.wait(1e3, units="us") yield harness.port_reset(1e3) yield harness.get_device_descriptor(response=model.deviceDescriptor.get()) yield harness.set_device_address(DEVICE_ADDRESS) yield harness.get_configuration_descriptor( length=9, # Device must implement at least one configuration response=model.configDescriptor[1].get()[:9]) total_config_len = model.configDescriptor[1].wTotalLength yield harness.get_configuration_descriptor( length=total_config_len, response=model.configDescriptor[1].get()[:total_config_len]) yield harness.set_configuration(1) INTERFACE = 1 line_coding = LineCodingStructure(115200, LineCodingStructure.STOP_BITS_1, LineCodingStructure.PARITY_NONE, LineCodingStructure.DATA_BITS_8) dut._log.info("[Getting line coding]") yield harness.control_transfer_in(DEVICE_ADDRESS, getLineCoding(INTERFACE), line_coding.get()) line_coding.dwDTERate = 9600 line_coding.bCharFormat = LineCodingStructure.STOP_BITS_2 dut._log.info("[Setting line coding]") yield harness.control_transfer_out(DEVICE_ADDRESS, setLineCoding(INTERFACE), line_coding.get()) dut._log.info("[Setting control line state]") yield harness.control_transfer_out( DEVICE_ADDRESS, setControlLineState(interface=0, rts=1, dtr=1), None) data = [ord(i) for i in "abcd"] epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) dut._log.info("[Sending BOOT op code]") yield harness.transaction_data_out(DEVICE_ADDRESS, epaddr_out, data)
def test_sof_is_ignored(dut): harness = get_harness(dut) harness.max_packet_size = model.deviceDescriptor.bMaxPacketSize0 yield harness.reset() yield harness.wait(1e3, units="us") yield harness.port_reset(10e3) yield harness.connect() yield harness.wait(1e3, units="us") # After waiting (bus inactivity) let's start with SOF yield harness.host_send_sof(0x01) DEVICE_ADDRESS = 0x20 epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) yield harness.set_device_address(DEVICE_ADDRESS) data = getDescriptorRequest(descriptor_type=Descriptor.Types.STRING, descriptor_index=0, lang_id=0, length=10) # Send SOF packet yield harness.host_send_sof(2) # Setup stage # ------------------------------------------ # Send SETUP packet yield harness.host_send_token_packet(PID.SETUP, DEVICE_ADDRESS, EndpointType.epnum(epaddr_out)) harness.request_deadline = get_sim_time("us") + harness.MAX_REQUEST_TIME # Send another SOF packet yield harness.host_send_sof(3) # Data stage # ------------------------------------------ # Send DATA packet harness.packet_deadline = get_sim_time("us") + harness.MAX_PACKET_TIME yield harness.host_send_data_packet(PID.DATA1, data) yield harness.host_expect_ack() # Send another SOF packet yield harness.host_send_sof(4) # # Status stage # # ------------------------------------------ harness.packet_deadline = get_sim_time("us") + harness.MAX_PACKET_TIME yield harness.transaction_status_out(DEVICE_ADDRESS, epaddr_out)
def test_sof_is_ignored(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 0x20 epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) yield harness.write(harness.csrs['usb_address'], addr) data = [0, 1, 8, 0, 4, 3, 0, 0] @cocotb.coroutine def send_setup_and_sof(): # Send SOF packet yield harness.host_send_sof(2) # Setup stage # ------------------------------------------ # Send SETUP packet yield harness.host_send_token_packet(PID.SETUP, addr, EndpointType.epnum(epaddr_out)) # Send another SOF packet yield harness.host_send_sof(3) # Data stage # ------------------------------------------ # Send DATA packet yield harness.host_send_data_packet(PID.DATA1, data) yield harness.host_expect_ack() # Send another SOF packet yield harness.host_send_sof(4) # Indicate that we're ready to receive data to EP0 # harness.write(harness.csrs['usb_in_ctrl'], 0) xmit = cocotb.fork(send_setup_and_sof()) yield harness.expect_setup(epaddr_out, data) yield xmit.join() # # Status stage # # ------------------------------------------ yield harness.set_response(epaddr_out, EndpointResponse.ACK) yield harness.transaction_status_out(addr, epaddr_out)
def test_in_transfer_stuff_last(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 28 epaddr = EndpointType.epaddr(1, EndpointType.IN) yield harness.write(harness.csrs['usb_address'], addr) d = [0x37, 0x75, 0x00, 0xe0] yield harness.clear_pending(epaddr) yield harness.set_response(epaddr, EndpointResponse.NAK) yield harness.set_data(epaddr, d) yield harness.set_response(epaddr, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, addr, epaddr) yield harness.host_expect_data_packet(PID.DATA0, d)
def test_in_transfer(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 0 epaddr = EndpointType.epaddr(1, EndpointType.IN) yield harness.write(harness.csrs['usb_address'], addr) d = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8] yield harness.clear_pending(epaddr) yield RisingEdge(harness.dut.clk12) yield RisingEdge(harness.dut.clk12) yield harness.set_response(epaddr, EndpointResponse.NAK) yield harness.set_data(epaddr, d[:4]) yield harness.set_response(epaddr, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, addr, EndpointType.epnum(epaddr)) yield harness.host_expect_data_packet(PID.DATA0, d[:4]) yield harness.host_send_ack() pending = yield harness.pending(epaddr) if pending: raise TestFailure("data was still pending") # need to wait 3 clk12 cycles after packet received for # rx packet machine to reset yield RisingEdge(harness.dut.clk12) yield RisingEdge(harness.dut.clk12) yield RisingEdge(harness.dut.clk12) yield harness.set_data(epaddr, d[4:]) yield harness.set_response(epaddr, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, addr, EndpointType.epnum(epaddr)) yield harness.host_expect_data_packet(PID.DATA1, d[4:]) yield harness.host_send_ack()
def test_control_setup_clears_stall(dut): harness = get_harness(dut) yield harness.reset() yield harness.connect() addr = 28 epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) yield harness.write(harness.csrs['usb_address'], addr) yield harness.host_send_sof(0) d = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0, 0] setup_data = [0x80, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00] # Send the data -- just to ensure that things are working harness.dut._log.info("sending data to confirm things are working") yield harness.transaction_data_out(addr, epaddr_out, d) # Send it again to ensure we can re-queue things. harness.dut._log.info("sending data to confirm we can re-queue") yield harness.transaction_data_out(addr, epaddr_out, d) # STALL the endpoint now harness.dut._log.info("stalling EP0 IN") yield harness.write(harness.csrs['usb_in_ctrl'], 0x40) # Do another receive, which should fail harness.dut._log.info("next transaction should stall") yield harness.host_send_token_packet(PID.IN, addr, 0) yield harness.host_expect_stall() # Do a SETUP, which should pass harness.dut._log.info("doing a SETUP on EP0, which should clear the stall") yield harness.control_transfer_in(addr, setup_data) # Finally, do one last transfer, which should succeed now # that the endpoint is unstalled. harness.dut._log.info("doing an IN transfer to make sure it's cleared") yield harness.transaction_data_in(addr, epaddr_out, d, datax=PID.DATA1)
def test_control_transfer_in_lazy(dut): """Test that we can transfer data in without immediately draining it""" epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) harness = get_harness(dut) yield harness.reset() yield harness.connect() yield harness.write(harness.csrs['usb_address'], 0) # SETUP packet harness.dut._log.info("sending initial SETUP packet") # Send a SETUP packet without draining it on the device side yield harness.host_send_token_packet(PID.SETUP, 0, epaddr_in) yield harness.host_send_data_packet( PID.DATA0, [0x80, 0x06, 0x00, 0x06, 0x00, 0x00, 0x0A, 0x00]) yield harness.host_expect_ack() # Set it up so we ACK the final IN packet data = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B ] for b in data: yield harness.write(harness.csrs['usb_in_data'], b) # Send a few packets while we "process" the data as a slow host for i in range(2): yield harness.host_send_token_packet(PID.IN, 0, 0) dut._log.info("Expecting NAK during processing...") yield harness.host_expect_nak() # Queue the IN response packet yield harness.write(harness.csrs['usb_in_ctrl'], 0) # Read the data setup_data = yield harness.drain_setup() if len(setup_data) != 10: raise TestFailure( "1. expected setup data to be 10 bytes, but was {} bytes: {}". format(len(setup_data), setup_data)) # Perform the final "read" yield harness.host_recv(PID.DATA1, 0, 0, data) # Status stage yield harness.set_response(epaddr_out, EndpointResponse.ACK) yield harness.transaction_status_out(0, epaddr_out) # SET ADDRESS harness.dut._log.info("setting USB address") # Set the address. Again, don't drain the device side yet. yield harness.host_send_token_packet(PID.SETUP, 0, epaddr_out) yield harness.host_send_data_packet( PID.DATA0, [0x00, 0x05, 11, 0x00, 0x00, 0x00, 0x00, 0x00]) yield harness.host_expect_ack() # Send a few packets while we "process" the data as a slow host for i in range(2): yield harness.host_send_token_packet(PID.IN, 0, 0) yield harness.host_expect_nak() setup_data = yield harness.drain_setup() if len(setup_data) != 10: raise TestFailure( "2. expected setup data to be 10 bytes, but was {} bytes: {}". format(len(setup_data), data, len(setup_data), len(setup_data) != 10)) # Note: the `out` buffer hasn't been drained yet yield harness.set_response(epaddr_in, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.IN, 0, 0) yield harness.host_expect_data_packet(PID.DATA1, []) yield harness.host_send_ack() for i in range(1532, 1541): yield harness.host_send_sof(i) # STALL TEST harness.dut._log.info("sending a STALL test") # Send a SETUP packet without draining it on the device side yield harness.host_send_token_packet(PID.SETUP, 0, epaddr_in) yield harness.host_send_data_packet( PID.DATA0, [0x80, 0x06, 0x00, 0x06, 0x00, 0x00, 0x0A, 0x00]) yield harness.host_expect_ack() # Send a few packets while we "process" the data as a slow host for i in range(2): yield harness.host_send_token_packet(PID.IN, 0, 0) yield harness.host_expect_nak() # Read the data, which should unblock the sending setup_data = yield harness.drain_setup() if len(setup_data) != 10: raise TestFailure("1. expected setup data to be 10 bytes, " "but was {} bytes: {}".format( len(setup_data), setup_data)) yield harness.write(harness.csrs['usb_in_ctrl'], 0x40) # Set STALL # Perform the final "read" yield harness.host_send_token_packet(PID.IN, 0, 0) yield harness.host_expect_stall() # RESUMING # Send a SETUP packet to the wrong endpoint harness.dut._log.info("sending a packet to the wrong endpoint " "that should be ignored") yield harness.host_send_token_packet(PID.SETUP, 11, epaddr_in) yield harness.host_send_data_packet( PID.DATA0, [0x80, 0x06, 0x00, 0x06, 0x00, 0x00, 0x0A, 0x00]) # yield harness.host_expect_ack() yield harness.write(harness.csrs['usb_address'], 11) # SETUP packet without draining harness.dut._log.info("sending a packet without draining SETUP") # Send a SETUP packet without draining it on the device side yield harness.host_send_token_packet(PID.SETUP, 11, epaddr_in) yield harness.host_send_data_packet( PID.DATA0, [0x80, 0x06, 0x00, 0x06, 0x00, 0x00, 0x0A, 0x00]) yield harness.host_expect_ack() # Set it up so we ACK the final IN packet data = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B ] for b in data: yield harness.write(harness.csrs['usb_in_data'], b) # Send a few packets while we "process" the data as a slow host for i in range(2): yield harness.host_send_token_packet(PID.IN, 11, 0) yield harness.host_expect_nak() # Read the data and queue the IN packet, which should unblock the sending harness.dut._log.info("draining SETUP which should unblock it") setup_data = yield harness.drain_setup() if len(setup_data) != 10: raise TestFailure( "3. expected setup data to be 10 bytes, but was {} bytes: {}". format(len(setup_data), setup_data)) yield harness.write(harness.csrs['usb_in_ctrl'], 0) # Perform the final send yield harness.host_send_token_packet(PID.IN, 11, 0) yield harness.host_expect_data_packet(PID.DATA1, data) yield harness.host_send_ack()
def transaction_setup(self, addr, data, epnum=0): epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) xmit = cocotb.fork(self.host_setup(addr, epnum, data)) yield self.expect_setup(epaddr_out, data) yield xmit.join()
def test_control_transfer_in_large(dut): """Test that we can transfer data in without immediately draining it""" epaddr_out = EndpointType.epaddr(0, EndpointType.OUT) epaddr_in = EndpointType.epaddr(0, EndpointType.IN) harness = get_harness(dut) yield harness.reset() yield harness.connect() yield harness.write(harness.csrs['usb_address'], 0) # Set address to 11 yield harness.control_transfer_out( 0, # Set address (to 11) [0x00, 0x05, 11, 0x00, 0x00, 0x00, 0x00, 0x00], # 18 byte descriptor, max packet size 8 bytes None, ) yield harness.write(harness.csrs['usb_address'], 11) # Send a packet that's longer than 64 bytes string_data = [ 0x4e, 0x3, 0x46, 0x0, 0x6f, 0x0, 0x6d, 0x0, 0x75, 0x0, 0x20, 0x0, 0x44, 0x0, 0x46, 0x0, 0x55, 0x0, 0x20, 0x0, 0x42, 0x0, 0x6f, 0x0, 0x6f, 0x0, 0x74, 0x0, 0x6c, 0x0, 0x6f, 0x0, 0x61, 0x0, 0x64, 0x0, 0x65, 0x0, 0x72, 0x0, 0x20, 0x0, 0x76, 0x0, 0x31, 0x0, 0x2e, 0x0, 0x38, 0x0, 0x2e, 0x0, 0x37, 0x0, 0x2d, 0x0, 0x38, 0x0, 0x2d, 0x0, 0x67, 0x0, 0x31, 0x0, 0x36, 0x0, 0x36, 0x0, 0x34, 0x0, 0x66, 0x0, 0x33, 0x0, 0x35, 0x0, 0x0, 0x0 ] # Send a SETUP packet without draining it on the device side yield harness.host_send_token_packet(PID.SETUP, 11, epaddr_in) yield harness.host_send_data_packet( PID.DATA0, [0x80, 0x06, 0x02, 0x03, 0x09, 0x04, 0xFF, 0x00]) yield harness.host_expect_ack() yield harness.drain_setup() # Send a few packets while we "process" the data as a slow host for i in range(3): yield harness.host_send_token_packet(PID.IN, 11, 0) yield harness.host_expect_nak() datax = PID.DATA1 sent_data = 0 for i, chunk in enumerate(grouper_tofit(64, string_data)): sent_data = 1 harness.dut._log.debug("Actual data we're expecting: {}".format(chunk)) for b in chunk: yield harness.write(harness.csrs['usb_in_data'], b) yield harness.write(harness.csrs['usb_in_ctrl'], 0) recv = cocotb.fork(harness.host_recv(datax, 11, 0, chunk)) yield recv.join() # Send a few packets while we "process" the data as a slow host for i in range(3): yield harness.host_send_token_packet(PID.IN, 11, 0) yield harness.host_expect_nak() if datax == PID.DATA0: datax = PID.DATA1 else: datax = PID.DATA0 if not sent_data: yield harness.write(harness.csrs['usb_in_ctrl'], 0) recv = cocotb.fork(harness.host_recv(datax, 11, 0, [])) yield harness.send_data(datax, 0, string_data) yield recv.join() yield harness.set_response(epaddr_out, EndpointResponse.ACK) yield harness.host_send_token_packet(PID.OUT, 11, 0) yield harness.host_send_data_packet(PID.DATA0, []) yield harness.host_expect_ack()