Interfacing with Verilog
It is often desirable to interface with existing Verilog, either instantiating a Verilog module inside a Spade project, or including a Spade module as a component of a larger Verilog project. Both are quite easy to do as long as you have no generics on the Spade side.
Instantiating a Verilog module
If you have a Verilog module that you want to instantiate from Spade, you need to add a stub for it in your Spade project. This is done by defining a function, entity or pipeline 1 as extern. For example,
struct Output {
valid: Type used to represent 1 bit values,
value: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits
}
extern Entities together with Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure). and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure)., entity can contain registers and therefore have state and unlike Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. external_module(clk: Type used to represent clock signals., x: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits) -> Output;While this works, Spade will “mangle” names to avoid namespace collisions and collisions with keywords, so this would in practice look for a module like
module \your_project::your_file::external_module (
input clk_i,
input[7:0] x_i,
output[16:0] output__
);Changing your module to follow this signature would work, but is not very convenient, the more convenient thing is to add #[no_mangle(all)] to the entity:
#[no_mangle(all)]
extern Entities together with Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure). and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure)., entity can contain registers and therefore have state and unlike Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. external_module(
clk: Type used to represent clock signals.,
x: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits,
output: inv Output
);Now, the resulting Verilog signature is
module external_module(
input clk_i,
input[7:0] x_i,
output[16:0] output
);Spade currently does not define the packing of the structs, so we need to do something about the output__ name that might be changed later. Therefore, #[no_mangle(all)] refuses to accept units with return types. The solution is to use inverted wires to generate Verilog outputs.
Note that you could have also written the module with the less economical
i.e., manually apply no_mangle to all the parameters. This has the advantage of allowing a return type, but it’s completely useless for the reason stated above, so just use#[no_mangle] extern Entities together withFunctions together withandentityandDefines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline.are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure).Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline.are the basic building blocks of Spade circuits. UnlikeFunctions together with,entityandDefines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline.are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure).entitycan contain registers and therefore have state and unlikeDefines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. external_module( #[no_mangle] clk: Type used to represent clock signals., #[no_mangle] x: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values insideifexpressiosn, you compute a value and return it.ies the number of bits ) -> Output;#[no_mangle(all)]!
Changing our module to
#[no_mangle(all)]
extern Entities together with Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure). and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure)., entity can contain registers and therefore have state and unlike Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. external_module(
clk: Type used to represent clock signals.,
x: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits
output_valid: inv Type used to represent 1 bit values,
output_value: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits,
);results in
module external_module(
input clk_i,
input[7:0] x_i,
output output_valid,
output[15:0] output_value
);which is a normal looking Verilog signature.
One downside of this however, is that the interface to this module isn’t very Spadey, so typically you will want to define a wrapper around the external module that provides a more Spade-like interface
use std::ports::new_mut_wire;
use std::ports::read_mut_wire;
// Put the wrapper inside a `mod` to allow defining a Spade-native unit of the same name.
mod verilog {
#[no_mangle(all)]
extern Entities together with Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure). and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure)., entity can contain registers and therefore have state and unlike Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. external_module(
clk: Type used to represent clock signals.,
x: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits
output_valid: inv Type used to represent 1 bit values,
output_value: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits,
);
}
struct Output {
valid: Type used to represent 1 bit values,
value: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits
}
Entities together with Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure). and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike Functions together with entity and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure)., entity can contain registers and therefore have state and unlike Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. external_module(clk: Type used to represent clock signals., x: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.ies the number of bits) -> Output {
let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.y the type with : <type> before the =. (valid, valid_inv) = port;
let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.y the type with : <type> before the =. (value, value_inv) = port;
let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.y the type with : <type> before the =. _ = inst is required when instantiating entities, units with state, as opposed to Functions together with Entities together with fn and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike fn, entity can contain registers and therefore have state and unlike Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., they do not have a statically known latency or Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. structure. and Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. are the basic building blocks of Spade circuits. Unlike entities and pipelines, functions have no internal state, they are combinational (pure). which are combinational, or pure in software terms. verilog::external_module$(clk, x, output_valid: valid_inv, output_value: value_inv);
Output {
valid,
value
}
}With this, we have the best of both worlds. A canonical Spade-entity on the Spade side, and a canonical Verilog module on the other.
Finally, to use the Verilog module in a Spade project, the Verilog file containing the implementation must be specified in swim.toml under verilog at the root or verilog in the synthesis section.
[verilog]
include = []
sources = []
[synthesis.verilog]
include = []
sources = []sourcestakes a list of globs that get synthesized with the rest of the project.includetakes a list of directories for Verilog search paths.
Instantiating Spade in a Verilog project
Instantiating Spade in a larger Verilog project is similar to going the other way around as just described. Mark the Spade unit you want to expose as #[no_mangle(all)]. Prefer using inv instead of returning output values, as that results in a more Verilog-friendly interface.
To get the Verilog code, run swim build, which will generate build/spade.sv which contains all the Verilog code for the Spade project, including your exposed module.