Intro

All data in the Awesomebus protocol is in network order (big-endian). An Awesomebus network consists of a number of nodes on a daisy-chained Ethernet bus. To communicate with the nodes, the Awesomebus host sends out a frame across the bus. The frame is made up of a ‘bucket’ for each node on the bus. Each bucket contains instructions for that specific node to perform.

Frames

An Awesomebus frame is a standard Ethernet frame with ethertype 0x8888. Both the source and destination MAC addresses are set to the broadcast address. The payload consists of a 2 byte wordcount followed by a number of buckets, followed by padding (up to the required Ethernet payload size of 42 bytes). The wordcount is the total byte count of all buckets in this frame, divided by 4.

uint8[6] mac_dest
uint8[6] mac_src
uint16   ethertype
uint16   wordcount
<buckets>
<padding>
uint32   crc

Buckets

A bucket starts with a 2 byte node ID, followed by a 2 byte instruction count. This is followed by a number of 4 byte instructions.

uint16   node
uint16   length
uint32[] instructions

When a node receives a bucket that matches it’s ID, it processes each instruction and modifies it as needed before sending the bucket on to the next node. When receiving a bucket with a non-matching ID, the bucket is immediately passed onto the next node. Nodes will also process buckets addressed to the broadcast address.

Node State

Each node has the following bus-visible state:

uint16     address
uint24[16] registers

A node will only process buckets which match its address. This address is set with the AB_SETADDR instruction. AB_READ and AB_WRITE instructions allow operation on the node’s registers.

At startup a node has its address initialised to 0xFF (the broadcast address).

Instructions

An instruction fits into a 4 byte word. All instructions take the following form:

uint24 value
uint4  register
uint4  opcode

Packed as follows into a word:

31               8    4    0
+----------------+----+----+
|     value      | reg| op |
+----------------+----+----+

The lowest 4 bits specify the instruction’s opcode, which in turn determines its behaviour and format. Any unused bits in an instruction are set to 0.

The opcodes are described below. Each instruction takes a word as input (in), processes (and potentially modifies the word and the node state), and returns a new word (out).

AB_NOP (0x0)

This instruction does nothing.

+---------------------+----+      +---------------------+----+
|                     | 00 |  ->  |                     | 00 |
+---------------------+----+      +---------------------+----+

out = in

AB_READ (0x1)

This instruction returns the specified register’s 24 bit value.

+----------------+----+----+      +----------------+----+----+
|                | reg| 01 |  ->  |     value      | reg| 01 |
+----------------+----+----+      +----------------+----+----+

out = in | (node.registers[reg] << 8)

AB_WRITE (0x2)

This instruction sets the specified register’s 24 bit value.

+----------------+----+----+      +----------------+----+----+
|     value      | reg| 02 |  ->  |     value      | reg| 02 |
+----------------+----+----+      +----------------+----+----+

node.registers[reg] = value
out = in

AB_PING (0x3)

This instruction simply returns an AB_NOP instruction. This is useful for detecting if a node exists at a certain address (An AB_PING written to a unallocated node address will not return AB_NOP).

+---------------------+----+      +---------------------+----+
|                     | 03 |  ->  |                     | 00 |
+---------------------+----+      +---------------------+----+

if (address != 0xFF):
        out = AB_NOP

AB_SETADDR (0x4)

This instruction sets the node address, only if it is currently not set. When the address is set, the node returns an AB_NOP instruction, otherwise it passes the instruction through.

+----------------+----+----+      +---------------------+----+
|    address     | 00 | 04 |  ->  |                     | 00 |
+----------------+----+----+      +---------------------+----+

if (address == 0xFF):
    node.address = address
    out = AB_NOP
else:
    out = in