Add some additional commentary.
by Martin Ling 3 years 10 months
8bd37452
Rewrite sweep mode using timed operations.
by Martin Ling 3 years 10 months
Rewrite sweep mode using timed operations.

The previous implementation of sweep mode had the M0 continuing to
receive and buffer samples during retuning. To avoid using data affected
by retuning, the code discarded two 16K blocks of samples after
retuning, before transferring one 16K block to the host.

However, retuning has to be done with the USB IRQ masked. The M4 byte
count cannot be advanced by the bulk transfer completion callback whilst
retuning is ongoing. This makes an RX buffer overrun likely, and
overruns now stall the M0, causing sweep timing to become inconsistent.

It makes much more sense to stop the M0 receiving data during retuning.
Using scheduled M0 mode changes between the RX and WAIT modes, it's now
possible to do this whilst retaining consistent sweep timing. The
comment block added to the start of the `sleep_mode()` function explains
the new implementation.

The new scheme substantially reduces the timing constraints on the host
retrieving the data. Previously, the host had to retrieve each sample
block before the M0 overwrote it, which would occur midway through
retuning for the next sweep, with samples that were going to be
discarded anyway.

With the new scheme, buffer space is used efficiently. No data is
written to the buffer which will be discarded. The host does not need to
finish retrieving each 16K block until its buffer space is due to be
reused, which is not until two sweep steps later. A great deal more
jitter in the bulk transfer timing can therefore now be tolerated,
without affecting sweep timing.

If the host does delay the retrieval of a block enough that its buffer
space is about to be reused, the M0 now stalls. This in turn will stall
the M4 sweep loop, causing the sweep to be paused until there is enough
buffer space to continue. Previously, sweeping continued regardless, and
the host received corrupted data if it did not keep up.
9f79a16b
Add a wait mode for the M0.
by Martin Ling 3 years 10 months
Add a wait mode for the M0.

In wait mode, the byte counter is advanced, but no SGPIO read/writes are
done. This mode is intended to be used for implementing timed operations.
cca7320f
Add a counter threshold at which the M0 will chang...
by Martin Ling 3 years 10 months
Add a counter threshold at which the M0 will change to a new mode.

This lays the groundwork for implementing timed operations (#86). The M0
can be configured to automatically change modes when its byte count
reaches a specific value.

Checking the counter against the threshold and dispatching to the next
mode is handled by a new `jump_next_mode` macro, which replaces the
unconditional branches back to the start of the TX and RX loops.

Making this change work requires some rearrangement of the code, such
that the destinations of all conditional branch instructions are within
reach. These branch instructions (`b[cond] label`) have a range of -256
to +254 bytes from the current program counter.

For this reason, the TX shortfall handling is moved earlier in the file,
and branches in the idle loop are restructured to use an unconditional
branch to rx_start, which is furthest away.

The additional code for switching modes adds 9 cycles to the normal RX
path, and 10 to the TX path (the difference is because the dispatch in
`jump_next_mode` is optimised for the longer RX path).
3618a535
Roll back shortfall stats if switched to idle in a...
by Martin Ling 3 years 10 months
Roll back shortfall stats if switched to idle in a shortfall.

During shutdown of TX or RX, the host may stop supplying or retrieving
sample data some time before a stop request causes the M0 to be set back
to idle mode.

This makes it common for a spurious shortfall to occur during shutdown,
giving the misleading impression that there has been a throughput
problem. In fact, the final shortfall is simply an artifact.

This commit detects when this happens, and excludes the spurious
shortfall from the stats.

To implement this, we back up the shortfall stats whenever a new
shortfall begins. If the new shortfall later turns out to be spurious,
as indicated by a transition to IDLE while it is ongoing, then we roll
back the stats to their previous values.

We actually only need to back up previous longest shortfall length. To
get a previous shortfall count, can simply to subtract one from the
current shortfall count.

This change adds four cycles to the two shortfall paths - a load and
store to back up the previous longest shortfall length.
7124b719
Don't update buffer pointer until after checking f...
by Martin Ling 3 years 10 months
Don't update buffer pointer until after checking for shortfall.

The buffer pointer is not needed in the shortfall paths. Moving this
update after the shortfall checks saves 3 cycles in each shortfall path.
a5e15215
Don't load M0 byte count from memory.
by Martin Ling 3 years 10 months
Don't load M0 byte count from memory.

This count is only written by the M0, so there's no need to reload it
when the current value is already retained in a register.

Removing this load saves two cycles in all code paths.
0e99419b
Use separate loops for RX and TX modes.
by Martin Ling 3 years 10 months
Use separate loops for RX and TX modes.

Using our newly-defined macros, it's now straightforward to write
separate loops for RX and TX, with the idle loop dispatching to them
when a new mode setting is written by the M4.

This saves some cycles by reducing branches needed within each loop, and
makes it simpler to add new modes.

For macros which use internal labels, a name parameter is added. This
parameter is prefixed to the labels used, so that each mode's use of
that macro produces its own label names.

Similarly, where branches were taken in the handle_shortfall macro to
the "loop" label, these are replaced with the appropriate tx_loop or
rx_loop label.

The syntax `\name\()_suffix` is necessary to perform concatenation in
the GNU assembler.
4e205994
Use new macros in M0 code.
by Martin Ling 3 years 10 months
Use new macros in M0 code.

This commit is separate from the previous one which adds the macros, in
order to make the diffs easier to read.
f08e0c17
Add macro versions of key parts of M0 code.
by Martin Ling 3 years 10 months
Add macro versions of key parts of M0 code.

This commit is separate from the following one which uses the macros, in
order to make the diffs easier to read.
9d570cb5
Report a bug