That bit-bashing could
easily be done in software with XMOS processors - and you would be able to
guarantee it
before executing the code :0
Currently I am making a reciprocal frequency counter
using only software in a single XMOS processor to capture two 50Mb/s digital streams, count the edges in them, do some arithmetic,
and pass the results over USB to a host processor. The latter would stretch the capabilities of most processors, but XMOS handles it easily, by design.
The timing is
guaranteed by the development environment, so I
know it can do that continuously without interruption (literally!).
The I/O and environment allows I/O to be done on specific clock cycles, with a 2ns resolution. There are many fpga-like I/O facilities including SERDES, handshakes, strobes, serial to parallel conversions etc.
For why those remarkable properties are true, see
https://www.xmos.com/published/xcore-architecture?version=latestThen try it with a £12 development board
https://www.digikey.co.uk/en/product-highlight/x/xmos/startkitThe dev environment is free.
The code would be something like:
in buffered port:32 aIn = XS1_PORT_1F; // the _1F specifies a single input pin, and the buffered port:32 specifies that 32 sequential bits are deserialised into a single word
in buffered port:32 bIn = XS1_PORT_1G;
out port dataOut = XS1_PORT_32B; // the 32 bit wide output port
out port ab = XS1_PORT_1H; // a 1-bit port
configure_clock_rate(clkIn, 500, 1); // 500MHz, or could use a clock arriving on an external pin
configure_in_port(aIn, clkIn, 1);
configure_in_port(bIn, clkIn, 1);
configure_clock_rate(clkOut, 500, 32); // 1/32 of the clkIn, or could use a clock arriving on an external pin
configure_out_port(data, clkOut, 1);
configure_out_port(ab, clkOut, 1);
start_clock(clkIn);
start_clock(clkOut);
unsigned int aData;
unsigned int bData;
while (1) {
aIn :> aData; // wait until 32 bits available, then continue
bIn :> bData; // wait until 32 bits available, then continue
ab <: 0; // which one
dataOut <: aData; // output data one clock later,
ab <: 1; // other one
dataOut <: bData;
}
And that's it. But you could also specify that output occurs on clock cycle x with instructions like
ab <: 1 @ x;
dataOut <: aData @ x;
so that both change simultaneously.