Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d6335e0

Browse files
committedNov 10, 2019
(WIP) Add an alternative setting using interrupt endpoints.
To improve worst-case latency while still keeping guaranteed delivery.
1 parent e6ff3cb commit d6335e0

File tree

6 files changed

+122
-51
lines changed

6 files changed

+122
-51
lines changed
 

‎firmware/main.c

+67-29
Original file line numberDiff line numberDiff line change
@@ -53,37 +53,64 @@ usb_desc_device_qualifier_c usb_device_qualifier = {
5353
usb_desc_interface_c usb_interface_0_disabled =
5454
USB_INTERFACE(/*bInterfaceNumber=*/0, /*bAlternateSetting=*/0, /*bNumEndpoints=*/0,
5555
/*iInterface=*/6);
56-
usb_desc_interface_c usb_interface_0_double =
56+
usb_desc_interface_c usb_interface_0_double_bulk =
5757
USB_INTERFACE(/*bInterfaceNumber=*/0, /*bAlternateSetting=*/1, /*bNumEndpoints=*/2,
5858
/*iInterface=*/7);
59-
usb_desc_interface_c usb_interface_0_quad =
59+
usb_desc_interface_c usb_interface_0_quad_bulk =
6060
USB_INTERFACE(/*bInterfaceNumber=*/0, /*bAlternateSetting=*/1, /*bNumEndpoints=*/2,
6161
/*iInterface=*/8);
62+
usb_desc_interface_c usb_interface_0_double_interrupt =
63+
USB_INTERFACE(/*bInterfaceNumber=*/0, /*bAlternateSetting=*/2, /*bNumEndpoints=*/2,
64+
/*iInterface=*/9);
65+
usb_desc_interface_c usb_interface_0_quad_interrupt =
66+
USB_INTERFACE(/*bInterfaceNumber=*/0, /*bAlternateSetting=*/2, /*bNumEndpoints=*/2,
67+
/*iInterface=*/10);
68+
6269
usb_desc_interface_c usb_interface_1_disabled =
6370
USB_INTERFACE(/*bInterfaceNumber=*/1, /*bAlternateSetting=*/0, /*bNumEndpoints=*/0,
6471
/*iInterface=*/6);
65-
usb_desc_interface_c usb_interface_1_double =
72+
usb_desc_interface_c usb_interface_1_double_bulk =
6673
USB_INTERFACE(/*bInterfaceNumber=*/1, /*bAlternateSetting=*/1, /*bNumEndpoints=*/2,
6774
/*iInterface=*/7);
75+
usb_desc_interface_c usb_interface_1_double_interrupt =
76+
USB_INTERFACE(/*bInterfaceNumber=*/1, /*bAlternateSetting=*/2, /*bNumEndpoints=*/2,
77+
/*iInterface=*/9);
6878

69-
#define USB_BULK_ENDPOINT(bEndpointAddress_) \
79+
#define USB_ENDPOINT(bEndpointAddress_, bmAttributes_, wMaxPacketSize_, bInterval_) \
7080
{ \
7181
.bLength = sizeof(struct usb_desc_endpoint), \
7282
.bDescriptorType = USB_DESC_ENDPOINT, \
7383
.bEndpointAddress = bEndpointAddress_, \
74-
.bmAttributes = USB_XFER_BULK, \
75-
.wMaxPacketSize = 512, \
76-
.bInterval = 0, \
84+
.bmAttributes = bmAttributes_, \
85+
.wMaxPacketSize = wMaxPacketSize_, \
86+
.bInterval = bInterval_, \
7787
}
7888

79-
usb_desc_endpoint_c usb_endpoint_2_out =
80-
USB_BULK_ENDPOINT(/*bEndpointAddress=*/2|USB_DIR_OUT);
81-
usb_desc_endpoint_c usb_endpoint_4_out =
82-
USB_BULK_ENDPOINT(/*bEndpointAddress=*/4|USB_DIR_OUT);
83-
usb_desc_endpoint_c usb_endpoint_6_in =
84-
USB_BULK_ENDPOINT(/*bEndpointAddress=*/6|USB_DIR_IN );
85-
usb_desc_endpoint_c usb_endpoint_8_in =
86-
USB_BULK_ENDPOINT(/*bEndpointAddress=*/8|USB_DIR_IN );
89+
usb_desc_endpoint_c usb_endpoint_2_out_bulk =
90+
USB_ENDPOINT(/*bEndpointAddress=*/2|USB_DIR_OUT, /*bmAttributes=*/USB_XFER_BULK,
91+
/*wMaxPacketSize=*/512, /*bInterval=*/0);
92+
usb_desc_endpoint_c usb_endpoint_4_out_bulk =
93+
USB_ENDPOINT(/*bEndpointAddress=*/4|USB_DIR_OUT, /*bmAttributes=*/USB_XFER_BULK,
94+
/*wMaxPacketSize=*/512, /*bInterval=*/0);
95+
usb_desc_endpoint_c usb_endpoint_6_in_bulk =
96+
USB_ENDPOINT(/*bEndpointAddress=*/6|USB_DIR_IN , /*bmAttributes=*/USB_XFER_BULK,
97+
/*wMaxPacketSize=*/512, /*bInterval=*/0);
98+
usb_desc_endpoint_c usb_endpoint_8_in_bulk =
99+
USB_ENDPOINT(/*bEndpointAddress=*/8|USB_DIR_IN , /*bmAttributes=*/USB_XFER_BULK,
100+
/*wMaxPacketSize=*/512, /*bInterval=*/0);
101+
102+
usb_desc_endpoint_c usb_endpoint_2_out_interrupt =
103+
USB_ENDPOINT(/*bEndpointAddress=*/2|USB_DIR_OUT, /*bmAttributes=*/USB_XFER_INTERRUPT,
104+
/*wMaxPacketSize=*/512|USB_TX_3_PER_MICROFRAME, /*bInterval=*/1);
105+
usb_desc_endpoint_c usb_endpoint_4_out_interrupt =
106+
USB_ENDPOINT(/*bEndpointAddress=*/4|USB_DIR_OUT, /*bmAttributes=*/USB_XFER_INTERRUPT,
107+
/*wMaxPacketSize=*/512|USB_TX_3_PER_MICROFRAME, /*bInterval=*/1);
108+
usb_desc_endpoint_c usb_endpoint_6_in_interrupt =
109+
USB_ENDPOINT(/*bEndpointAddress=*/6|USB_DIR_IN , /*bmAttributes=*/USB_XFER_INTERRUPT,
110+
/*wMaxPacketSize=*/512|USB_TX_3_PER_MICROFRAME, /*bInterval=*/1);
111+
usb_desc_endpoint_c usb_endpoint_8_in_interrupt =
112+
USB_ENDPOINT(/*bEndpointAddress=*/8|USB_DIR_IN , /*bmAttributes=*/USB_XFER_INTERRUPT,
113+
/*wMaxPacketSize=*/512|USB_TX_3_PER_MICROFRAME, /*bInterval=*/1);
87114

88115
usb_configuration_c usb_config_2_pipes = {
89116
{
@@ -96,14 +123,20 @@ usb_configuration_c usb_config_2_pipes = {
96123
.bMaxPower = 250,
97124
},
98125
{
99-
{ .interface = &usb_interface_0_disabled },
100-
{ .interface = &usb_interface_0_double },
101-
{ .endpoint = &usb_endpoint_2_out },
102-
{ .endpoint = &usb_endpoint_6_in },
103-
{ .interface = &usb_interface_1_disabled },
104-
{ .interface = &usb_interface_1_double },
105-
{ .endpoint = &usb_endpoint_4_out },
106-
{ .endpoint = &usb_endpoint_8_in },
126+
{ .interface = &usb_interface_0_disabled },
127+
{ .interface = &usb_interface_0_double_bulk },
128+
{ .endpoint = &usb_endpoint_2_out_bulk },
129+
{ .endpoint = &usb_endpoint_6_in_bulk },
130+
{ .interface = &usb_interface_0_double_interrupt },
131+
{ .endpoint = &usb_endpoint_2_out_interrupt },
132+
{ .endpoint = &usb_endpoint_6_in_interrupt },
133+
{ .interface = &usb_interface_1_disabled },
134+
{ .interface = &usb_interface_1_double_bulk },
135+
{ .endpoint = &usb_endpoint_4_out_bulk },
136+
{ .endpoint = &usb_endpoint_8_in_bulk },
137+
{ .interface = &usb_interface_1_double_interrupt },
138+
{ .endpoint = &usb_endpoint_4_out_interrupt },
139+
{ .endpoint = &usb_endpoint_8_in_interrupt },
107140
{ 0 }
108141
}
109142
};
@@ -119,10 +152,13 @@ usb_configuration_c usb_config_1_pipe = {
119152
.bMaxPower = 250,
120153
},
121154
{
122-
{ .interface = &usb_interface_0_disabled },
123-
{ .interface = &usb_interface_0_quad },
124-
{ .endpoint = &usb_endpoint_2_out },
125-
{ .endpoint = &usb_endpoint_6_in },
155+
{ .interface = &usb_interface_0_disabled },
156+
{ .interface = &usb_interface_0_quad_bulk },
157+
{ .endpoint = &usb_endpoint_2_out_bulk },
158+
{ .endpoint = &usb_endpoint_6_in_bulk },
159+
{ .interface = &usb_interface_0_quad_interrupt },
160+
{ .endpoint = &usb_endpoint_2_out_interrupt },
161+
{ .endpoint = &usb_endpoint_6_in_interrupt },
126162
{ 0 }
127163
}
128164
};
@@ -146,8 +182,10 @@ usb_ascii_string_c usb_strings[] = {
146182
[4] = "Pipe P at {4x512B EP2OUT/EP6IN}",
147183
// Interfaces
148184
[5] = "Disabled",
149-
[6] = "Double-buffered 512B",
150-
[7] = "Quad-buffered 512B",
185+
[6] = "Double-buffered 512B BULK",
186+
[7] = "Quad-buffered 512B BULK",
187+
[8] = "Double-buffered 512B INTERRUPT",
188+
[9] = "Quad-buffered 512B INTERRUPT",
151189
};
152190

153191
usb_descriptor_set_c usb_descriptor_set = {

‎software/glasgow/access/__init__.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
from abc import ABCMeta, abstractmethod
2+
from enum import Enum
23
from nmigen.compat import *
34

45
from ..gateware.pads import Pads
56

67

7-
__all__ = ["AccessArguments"]
8-
__all__ += ["AccessMultiplexer", "AccessMultiplexerInterface"]
9-
__all__ += ["AccessDemultiplexer", "AccessDemultiplexerInterface"]
8+
__all__ = [
9+
"AccessArguments",
10+
"AccessMultiplexer", "AccessMultiplexerInterface",
11+
"AccessDemultiplexer", "AccessDemultiplexerInterface",
12+
"AccessHint"
13+
]
14+
15+
16+
class AccessHint(Enum):
17+
DEFAULT = "default"
18+
BANDWIDTH = "bandwidth"
19+
LATENCY = "latency"
1020

1121

1222
class AccessArguments(metaclass=ABCMeta):

‎software/glasgow/access/direct/demultiplexer.py

+34-16
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ...support.logging import *
66
from ...support.chunked_fifo import *
77
from ...support.task_queue import *
8-
from .. import AccessDemultiplexer, AccessDemultiplexerInterface
8+
from .. import AccessHint, AccessDemultiplexer, AccessDemultiplexerInterface
99

1010

1111
# On Linux, the total amount of in-flight USB requests for the entire system is limited
@@ -137,10 +137,18 @@ async def claim_interface(self, applet, mux_interface, args, pull_low=set(), pul
137137

138138

139139
class DirectDemultiplexerInterface(AccessDemultiplexerInterface):
140-
def __init__(self, device, applet, mux_interface,
141-
read_buffer_size=None, write_buffer_size=None):
140+
def __init__(self, device, applet, mux_interface, *,
141+
hint="default", read_buffer_size=None, write_buffer_size=None):
142142
super().__init__(device, applet)
143143

144+
hint = AccessHint(hint)
145+
if hint in (AccessHint.DEFAULT, AccessHint.BANDWIDTH):
146+
transfer_type = usb1.TRANSFER_TYPE_BULK
147+
elif hint == AccessHint.LATENCY:
148+
transfer_type = usb1.TRANSFER_TYPE_INTERRUPT
149+
else:
150+
assert False
151+
144152
self._write_buffer_size = write_buffer_size
145153
self._read_buffer_size = read_buffer_size
146154
self._in_pushback = asyncio.Condition()
@@ -158,18 +166,28 @@ def __init__(self, device, applet, mux_interface,
158166
assert self._pipe_num < len(interfaces)
159167
interface = interfaces[self._pipe_num]
160168

161-
settings = list(interface.iterSettings())
162-
setting = settings[1] # alt-setting 1 has the actual endpoints
163-
for endpoint in setting.iterEndpoints():
164-
address = endpoint.getAddress()
165-
packet_size = endpoint.getMaxPacketSize()
166-
if address & usb1.ENDPOINT_DIR_MASK == usb1.ENDPOINT_IN:
167-
self._endpoint_in = address
168-
self._in_packet_size = packet_size
169-
if address & usb1.ENDPOINT_DIR_MASK == usb1.ENDPOINT_OUT:
170-
self._endpoint_out = address
171-
self._out_packet_size = packet_size
172-
assert self._endpoint_in != None and self._endpoint_out != None
169+
self._alt_setting = None
170+
for setting in interface.iterSettings():
171+
self._endpoint_in = None
172+
self._endpoint_out = None
173+
for endpoint in setting.iterEndpoints():
174+
address = endpoint.getAddress()
175+
attributes = endpoint.getAttributes()
176+
packet_size = endpoint.getMaxPacketSize()
177+
if (address & usb1.ENDPOINT_DIR_MASK == usb1.ENDPOINT_IN and
178+
attributes & usb1.TRANSFER_TYPE_MASK == transfer_type):
179+
self._endpoint_in = address
180+
self._in_packet_size = packet_size
181+
if (address & usb1.ENDPOINT_DIR_MASK == usb1.ENDPOINT_OUT and
182+
attributes & usb1.TRANSFER_TYPE_MASK == transfer_type):
183+
self._endpoint_out = address
184+
self._out_packet_size = packet_size
185+
if self._endpoint_in is not None and self._endpoint_out is not None:
186+
self._alt_setting = setting.getAlternateSetting()
187+
break
188+
assert self._alt_setting is not None
189+
self.logger.debug("FIFO: choosing alternate setting %d for access hint %s",
190+
self._alt_setting, hint.name)
173191

174192
self._interface = self.device.usb_handle.claimInterface(self._pipe_num)
175193
self._in_tasks = TaskQueue()
@@ -193,7 +211,7 @@ async def reset(self):
193211
await self.device.write_register(self._addr_reset, 1)
194212

195213
self.logger.trace("FIFO: synchronizing buffers")
196-
self.device.usb_handle.setInterfaceAltSetting(self._pipe_num, 1)
214+
self.device.usb_handle.setInterfaceAltSetting(self._pipe_num, self._alt_setting)
197215
self._in_buffer .clear()
198216
self._out_buffer.clear()
199217

‎software/glasgow/applet/audio/yamaha_opx/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def __init__(self, pads, master_cyc):
169169

170170
###
171171

172-
self.submodules.clkgen = ClockGen(master_cyc)
172+
self.submodules.clkgen = CEInserter()(ClockGen(master_cyc))
173173
self.comb += self.stb_m.eq(self.clkgen.stb_r)
174174

175175
self.comb += [
@@ -245,6 +245,7 @@ def __init__(self, pads, in_fifo, out_fifo, sample_decoder_cls, channel_count,
245245
# The code below assumes that the FSM clock is under ~50 MHz, which frees us from the need
246246
# to explicitly satisfy setup/hold timings.
247247
self.submodules.control_fsm = FSM()
248+
self.comb += self.cpu_bus.clkgen.ce.eq(out_fifo.readable)
248249
self.control_fsm.act("IDLE",
249250
NextValue(cpu_bus.oe, 1),
250251
If(out_fifo.readable,

‎software/glasgow/applet/internal/benchmark/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,17 @@ def add_run_arguments(cls, parser, access):
127127
parser.add_argument(
128128
"-c", "--count", metavar="COUNT", type=int, default=1 << 23,
129129
help="transfer COUNT bytes (default: %(default)s)")
130+
parser.add_argument(
131+
"--hint", metavar="HINT", choices=("bandwidth", "latency"), default="default",
132+
help="optimize interface for HINT")
130133

131134
parser.add_argument(
132135
dest="modes", metavar="MODE", type=str, nargs="*", choices=[[]] + cls.__all_modes,
133136
help="run benchmark mode MODE (default: {})".format(" ".join(cls.__all_modes)))
134137

135138
async def run(self, device, args):
136-
iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args=None)
139+
iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args=None,
140+
hint=args.hint)
137141

138142
golden = bytearray()
139143
while len(golden) < args.count:

‎vendor/libfx2

0 commit comments

Comments
 (0)
Please sign in to comment.