Bluetree
Bluetree (previously XPortMC), part of Blueshell, is a tree-like interconnect for a network on chip (NoC) built using Bluespec System Verilog (BSV). The interconnect enables a large number of CPUs to share access to a single shared memory port. The memory port is the root of the tree, and the CPUs are its leaves. Find Bluetree in the internal SVN at https://svn.cs.york.ac.uk/svn/rtslab/blueshell/
Other sorts of device (I/O, co-processors) can be connected together via Bluetiles, our NoC system. Bluetiles is intended to be used for communications between CPUs, and between CPUs and I/O devices.
typedef Client#(BluetreeClientPacket, BluetreeServerPacket) BluetreeClient;
typedef Server#(BluetreeClientPacket, BluetreeServerPacket) BluetreeServer;
The BluetreeClientPacket/BluetreeServerPacket structures describe the meaning of the data bus lines running in each direction. CPUs have BluetreeClient interfaces:
interface IfcMicroblaze;
interface BluetreeClient client;
endinterface
A RAM provides a Server interface, for example:
interface IfcBRAMServer;
interface BluetreeServer server;
endinterface
The Bluetree is created using the mkConnection method, defined in BSV's ClientServer package. For instance, we may link a Microblaze CPU to a block RAM:
IfcMicroblaze cpu <- mkMicroblaze();
IfcBRAMServer ram <- mkBRAMServer();
mkConnection(cpu.client, ram.server);
Other components can provide multiple Client and Server interfaces. For instance, each non-leaf, non-root node in the tree acts as a Server for each child, and acts as a Client for its parent. The BluetreeMux2 component serves exactly two children:
interface IfcBluetreeMux2;
interface BluetreeClient client;
interface BluetreeServer server0;
interface BluetreeServer server1;
endinterface
We may use this to connect more than one CPU to a single RAM, e.g.
IfcMicroblaze cpu0 <- mkMicroblaze();
IfcMicroblaze cpu1 <- mkMicroblaze();
IfcBRAMServer ram <- mkBRAMServer();
IfcBluetreeMux2 mux <- mkBluetreeMux2();
mkConnection(cpu0.client, mux.server0);
mkConnection(cpu1.client, mux.server1);
mkConnection(mux.client, ram.server);
Since BluetreeMux2 is itself a client we can connect two or more instances together, building a tree of (almost) arbitrary size. The BluetreeMuxN component does this automatically. It is given the required number of servers as a parameter, e.g.
BluetreeMuxN#(10) mem_service <- mkBluetreeCompoundMuxN();
The servers are then named mem_service.server[0] through mem_service.server[9]. A tree of BluetreeMux2 components is automatically generated. If the number of services is not a power of 2, then low-numbered servers will have a shorter path through the tree.
Tree sizes are ultimately limited by the size of the BluetreeCPUId type which identifies the CPU making each a request. You can redefine this type (or any other) by introducing a local copy of the BluetreeIf.bsv file within the directory for each board.
Scope
Bluetree is only intended to be used to connect CPUs (and other processing elements) to memory.Other sorts of device (I/O, co-processors) can be connected together via Bluetiles, our NoC system. Bluetiles is intended to be used for communications between CPUs, and between CPUs and I/O devices.
Introduction
In Bluetree, components provide Client and Server interfaces (these are standards defined by BSV's IP library). A Client interface originates requests; a Server interface serves them. The interfaces are defined as follows (in the Bluetree.bsv package):typedef Client#(BluetreeClientPacket, BluetreeServerPacket) BluetreeClient;
typedef Server#(BluetreeClientPacket, BluetreeServerPacket) BluetreeServer;
The BluetreeClientPacket/BluetreeServerPacket structures describe the meaning of the data bus lines running in each direction. CPUs have BluetreeClient interfaces:
interface IfcMicroblaze;
interface BluetreeClient client;
endinterface
A RAM provides a Server interface, for example:
interface IfcBRAMServer;
interface BluetreeServer server;
endinterface
The Bluetree is created using the mkConnection method, defined in BSV's ClientServer package. For instance, we may link a Microblaze CPU to a block RAM:
IfcMicroblaze cpu <- mkMicroblaze();
IfcBRAMServer ram <- mkBRAMServer();
mkConnection(cpu.client, ram.server);
Other components can provide multiple Client and Server interfaces. For instance, each non-leaf, non-root node in the tree acts as a Server for each child, and acts as a Client for its parent. The BluetreeMux2 component serves exactly two children:
interface IfcBluetreeMux2;
interface BluetreeClient client;
interface BluetreeServer server0;
interface BluetreeServer server1;
endinterface
We may use this to connect more than one CPU to a single RAM, e.g.
IfcMicroblaze cpu0 <- mkMicroblaze();
IfcMicroblaze cpu1 <- mkMicroblaze();
IfcBRAMServer ram <- mkBRAMServer();
IfcBluetreeMux2 mux <- mkBluetreeMux2();
mkConnection(cpu0.client, mux.server0);
mkConnection(cpu1.client, mux.server1);
mkConnection(mux.client, ram.server);
Since BluetreeMux2 is itself a client we can connect two or more instances together, building a tree of (almost) arbitrary size. The BluetreeMuxN component does this automatically. It is given the required number of servers as a parameter, e.g.
BluetreeMuxN#(10) mem_service <- mkBluetreeCompoundMuxN();
The servers are then named mem_service.server[0] through mem_service.server[9]. A tree of BluetreeMux2 components is automatically generated. If the number of services is not a power of 2, then low-numbered servers will have a shorter path through the tree.
Tree sizes are ultimately limited by the size of the BluetreeCPUId type which identifies the CPU making each a request. You can redefine this type (or any other) by introducing a local copy of the BluetreeIf.bsv file within the directory for each board.