Sockets
Sockets are a way for Virdant modules to expose a set of ports as a group. You may then connect all the ports together in a single statement, rather than doing so individually.
Declaring a Socket
We declare a socket in Virdant with the socket
keyword.
This is a top-level definition, on the same level as mod
s and type
definitions.
The socket definition gives a name to the group of ports we wish to use together.
socket Mem {
mosi addr : Word[16];
miso data : Word[8];
}
Inside a socket definition, we give the name and type of each port, as well as a direction.
We declare the direction of each port using the mosi
and miso
keywords.
A mosi
port is master-out, slave-in, while miso
is the reverse.
Inside of a module definition, we can declare instances of this socket.
Such instances are declared by giving their name and the name of the socket definition,
as well as their role: either master
or slave
.
Declaring Instances of a Socket
Here is a snippet showing an example of each:
mod Core {
master socket mem of Mem;
// ...
}
mod Memory {
slave socket mem of Mem;
// ...
}
By declaring the socket instance, the module gets a copy of each port in the definition.
The effective directions are easy to think about:
mosi
ports on a master
socket instance acts like an output port,
while a mosi
port on a slave
acts like an input port,
and similarly for the other two combinations.
You access these ports using dot notation:
mod Core {
master socket mem of Mem;
mem.addr := 0;
}
mod Memory {
slave socket mem of Mem;
mem.data := 0;
}
(Of course, instead of assigning them to just 0
,
a real Core
or Memory
would have the logic to drive actual values to the sockets).
Just like with ports, module definitions are obligated to drive the ports of its sockets.
If the socket is a master, then the obligation is to drive all of the mosi
ports,
and dually, if the socket is a slave, it the module is obligated to drive all of the miso
ports.
Also like with ports, module definitions may make use of the incoming signals from the sockets.
Master sockets may use miso
ports in expressions, and similarly, slaves may use mosi
ports in them.
Bulk Connect
Socket instances may be connected together with a single statement.
This is sometimes called “bulk connect”, since it allows you to connect many wires “in bulk”.
This bidirectional driver statement is written :=:
.
The most common pattern is when one module connects together the sockets of two of its children.
Given the socket definition Mem
and the module definitions Core
and Memory
above,
we can define a new module Top
which instantiates the two modules,
and then connects their sockets like this:
mod Top {
mod core of Core;
mod memory of Memory;
memory.mem :=: core.mem;
}
This is essentially equivalent to the following:
mod Top {
mod core of Core;
mod memory of Memory;
memory.mem.addr := core.mem.addr;
core.mem.data := memory.mem.data;
}
Note that each driver statement connects the two ports of the same name together, but that which drives which is worked out automatically. This is exceedingly useful for larger interfaces, such as Wishbone or AHB Lite.
Rules of Socket Connectivity
As mentioned, the most common configuration is for a parent to connect the master socket of a child module to the slave socket of another child module. However, this is not the only possible configuration.
The rules for socket connectivity depend on two properties of both sockets involved:
The role of the socket is whether it has been declared as a master or a slave.
This is indicated by the master
or slave
keyword.
The perspective is whether the socket is being viewed from the inside or the outside of the module it is declared in.
When referring to a socket in the same module it was declared, this is an interior view of the socket.
When referring to a socket declared in a submodule, this is an exterior view of the socket.
In the earlier example, both memory.mem
and core.mem
are seen from an exterior view.
Given these definitions, the following connections are legal:
Left hand |
Right hand |
Explanation |
|
---|---|---|---|
exterior slave |
|
exterior master |
the common configuration |
interior master |
|
exterior master |
forwarding a master up to its parent |
exterior slave |
|
interior slave |
forwarding a slave up from its child |
interior master |
|
interior slave |
loopback configuration (rarely used) |