Skip to content

Commit

Permalink
enabling instantiation context on IO parsing, taking it into account …
Browse files Browse the repository at this point in the history
…on bindings
  • Loading branch information
sylefeb committed Jan 12, 2024
1 parent eededd2 commit bfa6fef
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 96 deletions.
159 changes: 86 additions & 73 deletions src/Algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,10 @@ void Algorithm::instantiateBlueprint(t_instanced_nfo& _nfo, const t_instantiatio
cerr << "instantiating unit '" << _nfo.blueprint_name << "' as '" << _nfo.instance_name << "'\n";
// parse the unit ios
try {
auto cbp = ictx.compiler->parseUnitIOs(_nfo.blueprint_name);
// instantiation context for IO parsing
t_instantiation_context local_ictx;
makeBlueprintInstantiationContext(_nfo, ictx, local_ictx);
auto cbp = ictx.compiler->parseUnitIOs(_nfo.blueprint_name, local_ictx);
_nfo.parsed_unit = cbp;
_nfo.blueprint = cbp.unit;
} catch (Fatal&) {
Expand All @@ -1289,15 +1292,9 @@ void Algorithm::instantiateBlueprint(t_instanced_nfo& _nfo, const t_instantiatio
// finish the unit if non static
if (!_nfo.parsed_unit.unit.isNull()) {
// instantiation context
t_instantiation_context local_ictx = ictx;
for (auto spc : _nfo.specializations.autos) {
local_ictx.autos[spc.first] = spc.second; // makes sure new specializations overwrite any existing ones
}
for (auto spc : _nfo.specializations.params) {
local_ictx.params[spc.first] = spc.second;
}
t_instantiation_context local_ictx;
// update the instantiation context now that we have the unit ios
makeBlueprintInstantiationContext(_nfo, local_ictx, local_ictx);
makeBlueprintInstantiationContext(_nfo, ictx, local_ictx);
// record the specializations
_nfo.specializations = local_ictx;
// resolve instanced blueprint inputs/outputs var types
Expand Down Expand Up @@ -2911,7 +2908,8 @@ Algorithm::t_combinational_block* Algorithm::gatherCircuitryInst(
if (C == m_KnownCircuitries.end()) {
// attempt dynamic instantiation
try {
auto result = _context->ictx->compiler->parseCircuitryIOs(name);
sl_assert(_context->ictx != nullptr);
auto result = _context->ictx->compiler->parseCircuitryIOs(name, *_context->ictx);
m_InstancedCircuitries.push_back(result);
ioList = result.ioList;
} catch (Fatal&) {
Expand Down Expand Up @@ -6085,10 +6083,12 @@ void Algorithm::determineBlueprintBoundVIO(const t_instantiation_context& ictx)
// check width of output vs range width
// -> get output width if possible
{
// produce instantiation context
t_instantiation_context local_ictx;
makeBlueprintInstantiationContext(ib.second, ictx, local_ictx);
// verify width
int iobw = -1;
string obw = ib.second.blueprint->resolveWidthOf(b.left, ictx, sourceloc(access));
// ^^^^^^
/// TODO NOTE: this should produce an instantiation context to support parameterized outputs
string obw = ib.second.blueprint->resolveWidthOf(b.left, local_ictx, sourceloc(access));
try {
iobw = stoi(obw);
} catch (...) {
Expand Down Expand Up @@ -6137,8 +6137,26 @@ void Algorithm::determineBlueprintBoundVIO(const t_instantiation_context& ictx)
if (m_VIOBoundToBlueprintOutputs.find(bindingRightIdentifier(b)) != m_VIOBoundToBlueprintOutputs.end()) {
reportError(b.srcloc, "vio '%s' is already bound as the output of another instance", bindingRightIdentifier(b).c_str());
}
// check width if it is an access
auto access = std::get<siliceParser::AccessContext*>(b.right);
if (access) {
// produce instantiation context
t_instantiation_context local_ictx;
makeBlueprintInstantiationContext(ib.second, ictx, local_ictx);
// verify width (mismatch not possible with inouts)
string iow = ib.second.blueprint->resolveWidthOf(b.left, local_ictx, b.srcloc);
int iiow = -1;
try {
iiow = stoi(iow);
} catch (...) {
reportError(b.srcloc, "cannot determine width of inout '%s'", b.left.c_str());
}
auto tw = determineAccessTypeAndWidth(nullptr, access, nullptr);
if (tw.width != iiow) {
reportError(b.srcloc, "cannot bind to inout of different width");
}
}
// record wire name for this inout
/// TODO NOTE: move width check here? (curently in writeAsModule, L9720)
std::string bindpoint = ib.second.instance_prefix + "_" + b.left;
m_BlueprintInOutsBoundToVIO[bindpoint] = b.right;
m_VIOToBlueprintInOutsBound[bindingRightIdentifier(b)] = bindpoint;
Expand Down Expand Up @@ -9351,58 +9369,67 @@ bool Algorithm::isInOutAccessed(std::string var) const
void Algorithm::makeBlueprintInstantiationContext(const t_instanced_nfo& nfo, const t_instantiation_context& ictx, t_instantiation_context& _local_ictx) const
{
_local_ictx = ictx;
// parameters for parameterized variables
ForIndex(i, nfo.blueprint->parameterized().size()) {
string var = nfo.blueprint->parameterized()[i];
if (varIsInInstantiationContext(var, nfo.specializations)) {
// var has been specialized explicitly already
continue;
}
bool found = false;
auto io_nfo = nfo.blueprint->getVIODefinition(var, found);
sl_assert(found);
if (io_nfo.type_nfo.same_as.empty()) {
// a binding is needed to parameterize this io, find it
found = false;
const auto &b = findBindingLeft(var, nfo.bindings, found);
if (!found) {
reportError(nfo.srcloc, "io '%s' of instance '%s' is not bound nor specialized, cannot automatically determine it",
var.c_str(), nfo.instance_name.c_str());
}
std::string bound = bindingRightIdentifier(b);
t_var_nfo bnfo;
if (!getVIONfo(bound, bnfo)) {
continue; // NOTE: This is fine, we might be missing a binding that will be later resolved.
// Later (when writing the output) this is strictly asserted.
// This will only be an issue if the bound var is actually a paramterized var,
// however the designer is expected to worry about instantiation order in such cases.
}
if (bnfo.table_size != 0) {
// parameterized vars cannot be tables
for (auto spc : nfo.specializations.autos) {
_local_ictx.autos [spc.first] = spc.second; // makes sure new specializations overwrite any existing ones
}
for (auto spc : nfo.specializations.params) {
_local_ictx.params[spc.first] = spc.second;
}
// if the blueprint is defined (not the case before IOs are parsed)
if (!nfo.blueprint.isNull()) {
// parameters for parameterized variables
ForIndex(i, nfo.blueprint->parameterized().size()) {
string var = nfo.blueprint->parameterized()[i];
if (varIsInInstantiationContext(var, nfo.specializations)) {
// var has been specialized explicitly already
continue;
}
// add to context
addToInstantiationContext(this, var, bnfo, _local_ictx, _local_ictx);
bool found = false;
auto io_nfo = nfo.blueprint->getVIODefinition(var, found);
sl_assert(found);
if (io_nfo.type_nfo.same_as.empty()) {
// a binding is needed to parameterize this io, find it
found = false;
const auto& b = findBindingLeft(var, nfo.bindings, found);
if (!found) {
reportError(nfo.srcloc, "io '%s' of instance '%s' is not bound nor specialized, cannot automatically determine it",
var.c_str(), nfo.instance_name.c_str());
}
std::string bound = bindingRightIdentifier(b);
t_var_nfo bnfo;
if (!getVIONfo(bound, bnfo)) {
continue; // NOTE: This is fine, we might be missing a binding that will be later resolved.
// Later (when writing the output) this is strictly asserted.
// This will only be an issue if the bound var is actually a paramterized var,
// however the designer is expected to worry about instantiation order in such cases.
}
if (bnfo.table_size != 0) {
// parameterized vars cannot be tables
continue;
}
// add to context
addToInstantiationContext(this, var, bnfo, _local_ictx, _local_ictx);
}
}
}
// parameters of non-parameterized ios (for pre-processor widthof/signed)
Algorithm *alg = dynamic_cast<Algorithm*>(nfo.blueprint.raw());
for (auto io : nfo.blueprint->inputs()) {
if (io.type_nfo.base_type != Parameterized || !io.type_nfo.same_as.empty()) {
addToInstantiationContext(alg, io.name, io, _local_ictx, _local_ictx);
// parameters of non-parameterized ios (for pre-processor widthof/signed)
Algorithm* alg = dynamic_cast<Algorithm*>(nfo.blueprint.raw());
for (auto io : nfo.blueprint->inputs()) {
if (io.type_nfo.base_type != Parameterized || !io.type_nfo.same_as.empty()) {
addToInstantiationContext(alg, io.name, io, _local_ictx, _local_ictx);
}
}
}
for (auto io : nfo.blueprint->outputs()) {
if (io.type_nfo.base_type != Parameterized || !io.type_nfo.same_as.empty()) {
addToInstantiationContext(alg, io.name, io, _local_ictx, _local_ictx);
for (auto io : nfo.blueprint->outputs()) {
if (io.type_nfo.base_type != Parameterized || !io.type_nfo.same_as.empty()) {
addToInstantiationContext(alg, io.name, io, _local_ictx, _local_ictx);
}
}
}
for (auto io : nfo.blueprint->inOuts()) {
if (io.type_nfo.base_type != Parameterized || !io.type_nfo.same_as.empty()) {
addToInstantiationContext(alg, io.name, io, _local_ictx, _local_ictx);
for (auto io : nfo.blueprint->inOuts()) {
if (io.type_nfo.base_type != Parameterized || !io.type_nfo.same_as.empty()) {
addToInstantiationContext(alg, io.name, io, _local_ictx, _local_ictx);
}
}
}
// instance context
// instance name
_local_ictx.instance_name = (ictx.instance_name.empty() ? ictx.top_name : ictx.instance_name) + "_" + nfo.instance_name;
}

Expand Down Expand Up @@ -9714,20 +9741,6 @@ void Algorithm::writeAsModule(std::ostream& out, const t_instantiation_context&
out << WIRE << "_" << bndid;
}
} else {
// verify width (mismatch not possible with inouts)
string iow = nfo.blueprint->resolveWidthOf(os.name, ictx, nfo.srcloc);
// ^^^^^^
/// TODO NOTE: this should produce an instantiation context to support parameterized inouts!
int iiow = -1;
try {
iiow = stoi(iow);
} catch (...) {
reportError(nfo.srcloc, "cannot determine width of inout '%s'", os.name.c_str());
}
auto tw = determineAccessTypeAndWidth(nullptr, std::get<siliceParser::AccessContext*>(vio->second), nullptr);
if (tw.width != iiow) {
reportError(nfo.srcloc, "cannot bind to inout of different width");
}
// write access
t_vio_dependencies _;
writeAccess("_", out, false, std::get<siliceParser::AccessContext*>(vio->second),
Expand Down
19 changes: 7 additions & 12 deletions src/LuaPreProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1311,17 +1311,16 @@ void LuaPreProcessor::generateBody(
// create Lua context
createLuaContext();
// execute body (Lua context also contains all unit functions)
executeLuaString(lua_code, dst_file, false, ictx);
executeLuaString(lua_code, dst_file, ictx);

}

// -------------------------------------------------

void LuaPreProcessor::generateUnitIOSource(std::string unit, std::string dst_file)
void LuaPreProcessor::generateUnitIOSource(std::string unit, std::string dst_file, const Blueprint::t_instantiation_context& ictx)
{
std::string lua_code = "_G['__io__" + unit + "']()\n";
Blueprint::t_instantiation_context empty_ictx;
executeLuaString(lua_code, dst_file, false, empty_ictx);
executeLuaString(lua_code, dst_file, ictx);
}

// -------------------------------------------------
Expand All @@ -1330,7 +1329,7 @@ void LuaPreProcessor::generateUnitSource(
std::string unit, std::string dst_file, const Blueprint::t_instantiation_context& ictx)
{
std::string lua_code = "_G['" + unit + "']()\n";
executeLuaString(lua_code, dst_file, true, ictx);
executeLuaString(lua_code, dst_file, ictx);
}

// -------------------------------------------------
Expand All @@ -1353,14 +1352,12 @@ void LuaPreProcessor::createLuaContext()

// -------------------------------------------------

void LuaPreProcessor::executeLuaString(std::string lua_code, std::string dst_file, bool has_ictx, const Blueprint::t_instantiation_context& ictx)
void LuaPreProcessor::executeLuaString(std::string lua_code, std::string dst_file, const Blueprint::t_instantiation_context& ictx)
{
// reset line counter
m_CurOutputLine = 0;
// prepare instantiation context
if (has_ictx) {
g_LuaInstCtx.insert(std::make_pair(m_LuaState, ictx));
}
g_LuaInstCtx.insert(std::make_pair(m_LuaState, ictx));
// prepare output
g_LuaOutputs.insert(std::make_pair(m_LuaState, ofstream(dst_file)));
// execute
Expand Down Expand Up @@ -1391,9 +1388,7 @@ void LuaPreProcessor::executeLuaString(std::string lua_code, std::string dst_fil
// close output
g_LuaOutputs.at(m_LuaState).close();
g_LuaOutputs.erase(m_LuaState);
if (has_ictx) {
g_LuaInstCtx.erase(m_LuaState);
}
g_LuaInstCtx.erase(m_LuaState);
}

// -------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions src/LuaPreProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace Silice {

void createLuaContext();
void destroyLuaContext();
void executeLuaString(std::string lua_code, std::string dst_file, bool has_ictx, const Blueprint::t_instantiation_context& ictx);
void executeLuaString(std::string lua_code, std::string dst_file, const Blueprint::t_instantiation_context& ictx);

public:

Expand All @@ -90,7 +90,7 @@ namespace Silice {
void generateBody(std::string src_file, const std::vector<std::string> &defaultLibraries,
const Blueprint::t_instantiation_context& ictx, std::string lua_header_code, std::string dst_file);
/// \brief generates a unit IO source code (the part defining unit ios) in dst_file
void generateUnitIOSource(std::string unit, std::string dst_file);
void generateUnitIOSource(std::string unit, std::string dst_file, const Blueprint::t_instantiation_context& ictx);
/// \brief generates a unit source code in dst_file
void generateUnitSource(std::string unit, std::string dst_file, const Blueprint::t_instantiation_context& ictx);

Expand Down
12 changes: 6 additions & 6 deletions src/SiliceCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ void SiliceCompiler::endParsing()

// -------------------------------------------------

t_parsed_circuitry SiliceCompiler::parseCircuitryIOs(std::string to_parse)
t_parsed_circuitry SiliceCompiler::parseCircuitryIOs(std::string to_parse, const Blueprint::t_instantiation_context& ictx)
{
t_parsed_circuitry parsed;

Expand All @@ -419,7 +419,7 @@ t_parsed_circuitry SiliceCompiler::parseCircuitryIOs(std::string to_parse)
// bind local context
parsed.ios_parser->bind();
// pre-process unit IOs (done first to gather intel on parameterized vs static ios
m_BodyContext->lpp->generateUnitIOSource(parsed.parsed_circuitry, preprocessed_io);
m_BodyContext->lpp->generateUnitIOSource(parsed.parsed_circuitry, preprocessed_io, ictx);
// gather the unit
parsed.ios_parser->prepareParser(preprocessed_io);
auto ios_root = parsed.ios_parser->parser->rootIoList();
Expand Down Expand Up @@ -459,7 +459,7 @@ void SiliceCompiler::parseCircuitryBody(t_parsed_circuitry& _parse

// -------------------------------------------------

t_parsed_unit SiliceCompiler::parseUnitIOs(std::string to_parse)
t_parsed_unit SiliceCompiler::parseUnitIOs(std::string to_parse, const Blueprint::t_instantiation_context& ictx)
{
t_parsed_unit parsed;

Expand All @@ -479,7 +479,7 @@ t_parsed_unit SiliceCompiler::parseUnitIOs(std::string to_parse)
// bind local context
parsed.ios_parser->bind();
// pre-process unit IOs (done first to gather intel on parameterized vs static ios
m_BodyContext->lpp->generateUnitIOSource(parsed.parsed_unit, preprocessed_io);
m_BodyContext->lpp->generateUnitIOSource(parsed.parsed_unit, preprocessed_io, ictx);
// gather the unit
parsed.ios_parser->prepareParser(preprocessed_io);
auto ios_root = parsed.ios_parser->parser->rootInOutList();
Expand Down Expand Up @@ -637,7 +637,7 @@ void SiliceCompiler::writeFormalTests(std::ostream& _out, const Blueprint::t_ins
Blueprint::t_instantiation_context local_ictx = ictx;
local_ictx.top_name = "formal_" + name + "$"; // FIXME: inelegant
// parse and write unit
auto bp = parseUnitIOs(name);
auto bp = parseUnitIOs(name, local_ictx);
parseUnitBody(bp, local_ictx);
bp.unit->setAsTopMost();
// -> first pass
Expand Down Expand Up @@ -738,7 +738,7 @@ void SiliceCompiler::run(
}
ictx.top_name = "M_" + to_export;
// parse and write top unit
auto bp = parseUnitIOs(to_export);
auto bp = parseUnitIOs(to_export, ictx);
parseUnitBody(bp, ictx);
bp.unit->setAsTopMost();
// -> first pass
Expand Down
6 changes: 3 additions & 3 deletions src/SiliceCompiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,14 @@ namespace Silice {
bool first_pass);

/// \brief parses a specific unit ios
t_parsed_unit parseUnitIOs(std::string to_parse);
t_parsed_unit parseUnitIOs(std::string to_parse, const Blueprint::t_instantiation_context& ictx);
/// \brief parses a unit body (call after parseUnitIOs);
void parseUnitBody(t_parsed_unit& _parsed, const Blueprint::t_instantiation_context& ictx);

/// \brief parses a specific circuitry ios
t_parsed_circuitry parseCircuitryIOs(std::string to_parse);
t_parsed_circuitry parseCircuitryIOs(std::string to_parse, const Blueprint::t_instantiation_context& ictx);
/// \brief parses a circuitry body (call after parseCircuitryIOs);
void parseCircuitryBody(t_parsed_circuitry& _parsed,const Blueprint::t_instantiation_context& ictx);
void parseCircuitryBody(t_parsed_circuitry& _parsed, const Blueprint::t_instantiation_context& ictx);

/// \brief returns the static blueprint for 'unit', otherwise null
AutoPtr<Blueprint> isStaticBlueprint(std::string bpname);
Expand Down
22 changes: 22 additions & 0 deletions tests/bind8.si
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

unit foo(output uint3 b,inout uint$W$ a)
{
always {
__display("W=%d",$W$);
a.oenable = 2b11;
a.o = 2b01;
}
}

unit main(inout uint4 tmp,output uint8 leds)
{

foo f<W=2>(
a <:> tmp[0,2] // ok, width do match
);

algorithm {
__display("hello world");
}

}

0 comments on commit bfa6fef

Please sign in to comment.