Skip to content

[RFC] OTTF / test harness binary protocol #28788

@jwnrt

Description

@jwnrt

This RFC proposes changes to how OTTF communicates with test harnesses.

The key points are:

  • Introduction of a new binary SPI protocol.
  • Deprecation of SPI console.
  • Deprecation of UJSON.

The idea is to use UART exclusively for asynchronous logs and SPI for binary data transfers and synchronisation.

Current communication flow

OTTF communicates with the host test harness via a console which may use either the UART or SPI device as its transport.

Logs, data, and synchronisation messages are sent over the console. Data is encoded as JSON and serialized / deserialized at each end of the transport (UJSON). The UART console is asynchronous but uses software flow control to mitigate data loss. The SPI console is synchronous and requires polling from the host in order for the device to send logs. There is an optional TX notification GPIO available for the SPI console.

Problems

Serializing data as JSON is required over the UART console to allow for in-band flow control support. The (de)serialization adds complexity and overheads. The in-band software flow control is not foolproof and has shown reliability problems in the past with lost data. Increasing reliability requires slowing the data rate by "pacing" each byte to give time for flow control bytes to arrive.

The SPI console uses a (subjectively) complex framing protocol to transport data in chunks. Asynchronous logs from the host cannot be sent until the host polls for them. An extra GPIO pin can be used to notify the host of awaiting data, but adds further complexity. Data is still serialized as UJSON over the SPI console potentially unnecessarily.

Binary SPI protocol

This RFC proposes splitting the work of logs and data between two transports.

UART will be used exclusively for informative logs and not for data transfers or synchronisation. Device-side tests should not rely on the host receiving UART logs for test success.

The SPI will be used to transfer binary data between the device and host and for synchronising control flow. The protocol is built on the following SPI commands sent from the host to device:

  1. READ <addr> - read bytes from addr on the device.
  2. WRITE <addr> - write bytes to addr on the device.
  3. SYNC <code> - synchronise with the device using some code.
  4. READ_STATUS - poll the busy status of OTTF synchronisation.

Commands 1-3 will interrupt OTTF and cause an upload. Command 4 will be handled by the SPI device hardware.

The host is able to read and write data to any address at any time. The intended use is writing test data and reading test results to/from SRAM. Known SRAM addresses are obtained from the ELF as is currently done with UJSON. Struct layouts are generated for Rust from the C using bindgen unlike the macro generation system from UJSON.

Synchronisation

The SYNC and READ_STATUS commands are used together for synchronisation.

At startup, the device:

  1. Configures the SPI device to upload the SYNC command and set the busy bit.
  2. When SYNC is uploaded, the interrupt handler writes the code to a global OTTF variable.

To synchronise, the host:

  1. Sends a SYNC <code> command.
  2. Sends a READ_STATUS command and continuously reads until the device is no longer busy.
  3. The host now knows that the device has synchronised with the same code.

To synchronise, the device:

  1. Continuously reads the global OTTF variable until it matches the expected code.
  2. Clears the busy bit in the SPI device.
  3. The device now knows that the host has also synchronised with the same code.

Test results

Instead of reading PASS! and FAIL! messages from the UART, the host should synchronise on a special end-of-test code and then read the test status from SRAM.

Similarly the host may choose to read out coverage data from a known location in SRAM at the end of the test. This replaces the current coverage data transfer mechanism.

Migration plan

The following is the proposed migration plan for the master branch:

  1. Introduce the binary SPI protocol to OTTF and OpenTitanLib.
  2. Introduce an OTTF API for synchronisation and migrate all tests.
  3. Depending on the console that is used:
    • For UART: log over UART but synchronise and send binary data via the SPI.
    • For SPI: log, synchronise, and send UJSON data over the SPI console still.
  4. Deprecate and remove the SPI console.
  5. Deprecate and remove UJSON.

Benefits

The new flow should be faster as the UART does not need to be paced, the SPI does not need to be framed, and JSON (de)serialization is no longer needed.

The protocol complexity should be reduced as the SPI no longer requires framing or a GPIO to notify of asynchronous data from the device. The new protocol is expected to be simpler than the current SPI console protocol.

We expect improved reliability by using a synchronous protocol for data transfer instead of UART. We have frequently had problems with data loss and parsing by sending both logs and data over the same UART console channel.

Drawbacks

Two channels are now required for testing instead of one. We currently require both UART and SPI for tests anyway in order to bootstrap, so this should not add extra overhead for Earl Grey.

Inspecting ASCII JSON over the console for debugging (as is currently done) could be easier than inspecting binary data (as would be required). The tools used to capture signals often translate binary into ASCII anyway (for example most logic analyzer viewers can do this).

Interrupts must be enabled in order to process SPI commands.

Future possibilities

The binary protocol doesn't necessarily need to use SPI as its transport. Future posibilities include USB, I2C, and JTAG.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions