-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for SystemVerilog parameter passthroughs (#497)
- Loading branch information
Showing
7 changed files
with
319 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ | |
// 2021 August 26 | ||
// Author: Max Korbel <[email protected]> | ||
|
||
import 'dart:collection'; | ||
|
||
import 'package:collection/collection.dart'; | ||
import 'package:meta/meta.dart'; | ||
import 'package:rohd/rohd.dart'; | ||
|
@@ -23,7 +25,8 @@ class SystemVerilogSynthesizer extends Synthesizer { | |
bool generatesDefinition(Module module) => | ||
// ignore: deprecated_member_use_from_same_package | ||
!((module is CustomSystemVerilog) || | ||
(module is SystemVerilog && !module.generatesDefinition)); | ||
(module is SystemVerilog && | ||
module.generatedDefinitionType == DefinitionGenerationType.none)); | ||
|
||
/// Creates a line of SystemVerilog that instantiates [module]. | ||
/// | ||
|
@@ -37,6 +40,13 @@ class SystemVerilogSynthesizer extends Synthesizer { | |
/// Based on this module definition: `c <= a & b` | ||
/// The values for [ports] should be: | ||
/// ports: `{ 'a' : 'sig_a', 'b' : 'sig_b', 'c' : 'sig_c'}` | ||
/// | ||
/// If [forceStandardInstantiation] is set, then the standard instantiation | ||
/// for SystemVerilog modules will be used. | ||
/// | ||
/// If [parameters] is provided, then the module will be instantiated with | ||
/// all of the keys as parameter names set to the corresponding values | ||
/// provided. | ||
static String instantiationVerilogFor( | ||
{required Module module, | ||
required String instanceType, | ||
|
@@ -135,12 +145,19 @@ class SystemVerilogSynthesizer extends Synthesizer { | |
); | ||
|
||
@override | ||
SynthesisResult synthesize(Module module, | ||
String Function(Module module) getInstanceTypeOfModule) => | ||
module is SystemVerilog && module.generatesDefinition | ||
? _SystemVerilogCustomDefinitionSynthesisResult( | ||
module, getInstanceTypeOfModule) | ||
: _SystemVerilogSynthesisResult(module, getInstanceTypeOfModule); | ||
SynthesisResult synthesize( | ||
Module module, String Function(Module module) getInstanceTypeOfModule) { | ||
assert( | ||
module is! SystemVerilog || | ||
module.generatedDefinitionType != DefinitionGenerationType.none, | ||
'SystemVerilog modules synthesized must generate a definition.'); | ||
|
||
return module is SystemVerilog && | ||
module.generatedDefinitionType == DefinitionGenerationType.custom | ||
? _SystemVerilogCustomDefinitionSynthesisResult( | ||
module, getInstanceTypeOfModule) | ||
: _SystemVerilogSynthesisResult(module, getInstanceTypeOfModule); | ||
} | ||
} | ||
|
||
/// Allows a [Module] to define a custom implementation of SystemVerilog to be | ||
|
@@ -165,8 +182,26 @@ mixin CustomSystemVerilog on Module { | |
final List<String> expressionlessInputs = const []; | ||
} | ||
|
||
/// Allows a [Module] to define a custom implementation of SystemVerilog to be | ||
/// injected in generated output instead of instantiating a separate `module`. | ||
/// Represents the definition of a SystemVerilog parameter at the time of | ||
/// declaration of a module definition. | ||
class SystemVerilogParameterDefinition { | ||
/// The SystemVerilog type to use for declaring this parameter. | ||
final String type; | ||
|
||
/// The default value for this parameter. | ||
final String defaultValue; | ||
|
||
/// The name of the parameter. | ||
final String name; | ||
|
||
/// Creates a new SystemVerilog parameter definition with [name] of the | ||
/// provided [type] with the [defaultValue]. | ||
const SystemVerilogParameterDefinition(this.name, | ||
{required this.type, required this.defaultValue}); | ||
} | ||
|
||
/// Allows a [Module] to control the instantiation and/or definition of | ||
/// generated SystemVerilog for that module. | ||
mixin SystemVerilog on Module { | ||
/// Generates custom SystemVerilog to be injected in place of a `module` | ||
/// instantiation. | ||
|
@@ -179,12 +214,14 @@ mixin SystemVerilog on Module { | |
/// | ||
/// If a standard instantiation is desired, either return `null` or use | ||
/// [SystemVerilogSynthesizer.instantiationVerilogFor] with | ||
/// `forceStandardInstantiation` set to `true`. | ||
/// `forceStandardInstantiation` set to `true`. By default, `null` is | ||
/// returned and thus a standard instantiation is used. | ||
String? instantiationVerilog( | ||
String instanceType, | ||
String instanceName, | ||
Map<String, String> ports, | ||
); | ||
) => | ||
null; | ||
|
||
/// A list of names of [input]s which should not have any SystemVerilog | ||
/// expressions (including constants) in-lined into them. Only signal names | ||
|
@@ -194,16 +231,51 @@ mixin SystemVerilog on Module { | |
|
||
/// A custom SystemVerilog definition to be produced for this [Module]. | ||
/// | ||
/// If `null` is returned, then no definition will be generated. Otherwise, | ||
/// this function should be a pure function, i.e. it should have no side | ||
/// effects and always return the same thing for the same inputs. | ||
String? definitionVerilog(String definitionType) => null; | ||
/// If an empty string is returned (the default behavior), then no definition | ||
/// will be generated. | ||
/// | ||
/// If `null` is returned, then a default definition will be generated. | ||
/// | ||
/// This function should have no side effects and always return the same thing | ||
/// for the same inputs. | ||
String? definitionVerilog(String definitionType) => ''; | ||
|
||
/// A collection of SystemVerilog [SystemVerilogParameterDefinition]s to be | ||
/// declared on the definition when generating SystemVerilog for this [Module] | ||
/// if [generatedDefinitionType] is [DefinitionGenerationType.standard]. | ||
/// | ||
/// If `null` is returned (the default), then no parameters will be generated. | ||
/// Otherwise, this function should have no side effects and always return the | ||
/// same thing for the same inputs. | ||
List<SystemVerilogParameterDefinition>? get definitionParameters => null; | ||
|
||
/// Whether or not this [Module] generates a SystemVerilog definition. | ||
/// What kind of SystemVerilog definition this [Module] generates, or whether | ||
/// it does at all. | ||
/// | ||
/// By default, this is automatically calculated by whether or not | ||
/// [definitionVerilog] provides a definition. | ||
bool get generatesDefinition => definitionVerilog('*PLACEHOLDER*') != null; | ||
/// By default, this is automatically calculated based on the return value of | ||
/// [definitionVerilog]. | ||
DefinitionGenerationType get generatedDefinitionType { | ||
final def = definitionVerilog('*PLACEHOLDER*'); | ||
if (def == null) { | ||
return DefinitionGenerationType.standard; | ||
} else if (def.isNotEmpty) { | ||
return DefinitionGenerationType.custom; | ||
} else { | ||
return DefinitionGenerationType.none; | ||
} | ||
} | ||
} | ||
|
||
/// A type of generation for generated outputs. | ||
enum DefinitionGenerationType { | ||
/// No definition will be generated. | ||
none, | ||
|
||
/// A standard definition will be generated. | ||
standard, | ||
|
||
/// A custom definition will be generated. | ||
custom, | ||
} | ||
|
||
/// Allows a [Module] to define a special type of [SystemVerilog] which can be | ||
|
@@ -246,18 +318,25 @@ mixin InlineSystemVerilog on Module implements SystemVerilog { | |
final List<String> expressionlessInputs = const []; | ||
|
||
@override | ||
String? definitionVerilog(String definitionType) => null; | ||
String? definitionVerilog(String definitionType) => ''; | ||
|
||
@override | ||
DefinitionGenerationType get generatedDefinitionType => | ||
DefinitionGenerationType.none; | ||
|
||
@override | ||
bool get generatesDefinition => definitionVerilog('*PLACEHOLDER*') != null; | ||
List<SystemVerilogParameterDefinition>? get definitionParameters => null; | ||
} | ||
|
||
/// A [SynthesisResult] representing a [Module] that provides a custom | ||
/// SystemVerilog definition. | ||
class _SystemVerilogCustomDefinitionSynthesisResult extends SynthesisResult { | ||
_SystemVerilogCustomDefinitionSynthesisResult( | ||
super.module, super.getInstanceTypeOfModule) | ||
: assert(module is SystemVerilog && module.generatesDefinition, | ||
: assert( | ||
module is SystemVerilog && | ||
module.generatedDefinitionType == | ||
DefinitionGenerationType.custom, | ||
'This should only be used for custom system verilog definitions.'); | ||
|
||
@override | ||
|
@@ -278,12 +357,15 @@ class _SystemVerilogCustomDefinitionSynthesisResult extends SynthesisResult { | |
/// A [SynthesisResult] representing a conversion of a [Module] to | ||
/// SystemVerilog. | ||
class _SystemVerilogSynthesisResult extends SynthesisResult { | ||
/// A cached copy of the generated ports | ||
/// A cached copy of the generated ports. | ||
late final String _portsString; | ||
|
||
/// A cached copy of the generated contents of the module | ||
/// A cached copy of the generated contents of the module. | ||
late final String _moduleContentsString; | ||
|
||
/// A cached copy of the generated parameters. | ||
late final String? _parameterString; | ||
|
||
/// The main [_SynthModuleDefinition] for this. | ||
final _SynthModuleDefinition _synthModuleDefinition; | ||
|
||
|
@@ -295,17 +377,21 @@ class _SystemVerilogSynthesisResult extends SynthesisResult { | |
: _synthModuleDefinition = _SynthModuleDefinition(module) { | ||
_portsString = _verilogPorts(); | ||
_moduleContentsString = _verilogModuleContents(getInstanceTypeOfModule); | ||
_parameterString = _verilogParameters(module); | ||
} | ||
|
||
@override | ||
bool matchesImplementation(SynthesisResult other) => | ||
other is _SystemVerilogSynthesisResult && | ||
other._portsString == _portsString && | ||
other._parameterString == _parameterString && | ||
other._moduleContentsString == _moduleContentsString; | ||
|
||
@override | ||
int get matchHashCode => | ||
_portsString.hashCode ^ _moduleContentsString.hashCode; | ||
_portsString.hashCode ^ | ||
_moduleContentsString.hashCode ^ | ||
_parameterString.hashCode; | ||
|
||
@override | ||
String toFileContents() => _toVerilog(getInstanceTypeOfModule); | ||
|
@@ -396,11 +482,34 @@ class _SystemVerilogSynthesisResult extends SynthesisResult { | |
..._verilogInOuts(), | ||
].join(',\n'); | ||
|
||
String? _verilogParameters(Module module) { | ||
if (module is SystemVerilog) { | ||
final defParams = module.definitionParameters; | ||
if (defParams == null) { | ||
return null; | ||
} | ||
|
||
return [ | ||
'#(', | ||
defParams | ||
.map((p) => 'parameter ${p.type} ${p.name} = ${p.defaultValue}') | ||
.join(',\n'), | ||
')', | ||
].join('\n'); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/// The full SV representation of this module. | ||
String _toVerilog(String Function(Module module) getInstanceTypeOfModule) { | ||
final verilogModuleName = getInstanceTypeOfModule(module); | ||
return [ | ||
'module $verilogModuleName(', | ||
[ | ||
'module $verilogModuleName', | ||
_parameterString, | ||
'(', | ||
].nonNulls.join(' '), | ||
_portsString, | ||
');', | ||
_moduleContentsString, | ||
|
@@ -626,7 +735,7 @@ class _SynthModuleDefinition { | |
|
||
/// A mapping from original [Logic]s to the [_SynthLogic]s that represent | ||
/// them. | ||
final Map<Logic, _SynthLogic> logicToSynthMap = {}; | ||
final Map<Logic, _SynthLogic> logicToSynthMap = HashMap(); | ||
|
||
/// A mapping from the original [Module]s to the | ||
/// [_SynthSubModuleInstantiation]s that represent them. | ||
|
Oops, something went wrong.