Skip to content

Commit

Permalink
Merge pull request #781 from rdaly525/patch-verilog-inouts
Browse files Browse the repository at this point in the history
Repull of #777
  • Loading branch information
leonardt authored Aug 6, 2019
2 parents ab2cf72 + 2cad82b commit 3f50887
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 70 deletions.
85 changes: 45 additions & 40 deletions include/coreir/passes/analysis/verilog.h
Original file line number Diff line number Diff line change
@@ -1,55 +1,60 @@
#ifndef COREIR_VERILOG_HPP_
#define COREIR_VERILOG_HPP_

#include <memory>
#include <ostream>
#include "coreir.h"
#include "verilogAST.hpp"
#include <memory>
#include <ostream>

namespace vAST = verilogAST;

namespace CoreIR {
namespace Passes {

class Verilog : public InstanceGraphPass {
bool _inline = false;
bool verilator_debug = true;

// We store a vector of module name, module AST node pairs to support
// serializing to a single or multiple files
std::vector<std::pair<std::string, std::unique_ptr<vAST::AbstractModule>>>
modules;

// Externally defined modules (no moduleDef), for now we just emit comments
// listing them when compiling to a single file
std::vector<Module*> extern_modules;

// Set used to track generators that are compiled as parametrized verilog
// modules. These parametrized modules have been instanced to create coreir
// modules, but we only need to compile the verilog definition once
std::set<Generator*> verilog_generators_seen;

void compileModule(Module* module);

public:
static std::string ID;
Verilog() : InstanceGraphPass(ID, "Compiles IR to Verilog files", true) {}
~Verilog(){};
bool runOnInstanceGraphNode(InstanceGraphNode& node) override;
void initialize(int argc, char** argv) override;
void setAnalysisInfo() override {
onlyTop = true;
addDependency(
"verifyconnectivity --onlyinputs"); // Should change back to check
// all connections
addDependency("verifyflattenedtypes");
}

void writeToStream(std::ostream& os);
void writeToFiles(const std::string& dir,
std::unique_ptr<std::string> product_file);
bool _inline = false;
bool verilator_debug = false;

// We store a vector of module name, module AST node pairs to support
// serializing to a single or multiple files
std::vector<std::pair<std::string, std::unique_ptr<vAST::AbstractModule>>>
modules;

// Externally defined modules (no moduleDef), for now we just emit comments
// listing them when compiling to a single file
std::vector<Module *> extern_modules;

// Set used to track generators that are compiled as parametrized verilog
// modules. These parametrized modules have been instanced to create coreir
// modules, but we only need to compile the verilog definition once
std::set<Generator *> verilog_generators_seen;

void compileModule(Module *module);

std::vector<std::unique_ptr<vAST::AbstractPort>>
compilePorts(RecordType *record_type);

std::unique_ptr<vAST::AbstractModule>
compileStringBodyModule(json verilog_json, std::string name, Module *module);

public:
static std::string ID;
Verilog() : InstanceGraphPass(ID, "Compiles IR to Verilog files", true) {}
~Verilog(){};
bool runOnInstanceGraphNode(InstanceGraphNode &node) override;
void initialize(int argc, char **argv) override;
void setAnalysisInfo() override {
onlyTop = true;
addDependency("verifyconnectivity --onlyinputs"); // Should change back to
// check all connections
addDependency("verifyflattenedtypes");
}

void writeToStream(std::ostream &os);
void writeToFiles(const std::string &dir,
std::unique_ptr<std::string> product_file);
};

} // namespace Passes
} // namespace CoreIR
} // namespace Passes
} // namespace CoreIR
#endif
85 changes: 63 additions & 22 deletions src/passes/analysis/verilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ declare_connections(std::map<std::string, Instance *> instances) {
for (auto port :
cast<RecordType>(instance.second->getModuleRef()->getType())
->getRecord()) {
if (port.second->isOutput()) {
if (!port.second->isInput()) {
std::unique_ptr<vAST::Identifier> id =
std::make_unique<vAST::Identifier>(instance.first + "_" +
port.first);
Expand Down Expand Up @@ -142,11 +142,16 @@ std::unique_ptr<vAST::AbstractModule> compile_string_module(json verilog_json) {
// If the module `isGenerated`, the parameters to the module include
// `getDefaultGenArgs` and `getGenParams`
std::unique_ptr<vAST::AbstractModule>
compile_string_body_module(json verilog_json, std::string name,
Module *module) {
Passes::Verilog::compileStringBodyModule(json verilog_json, std::string name,
Module *module) {
std::vector<std::unique_ptr<vAST::AbstractPort>> ports;
for (auto port_str :
verilog_json["interface"].get<std::vector<std::string>>()) {
if (this->verilator_debug) {
// FIXME: Hack to get comment into port name, we need to design a way
// to attach comments to expressions
port_str += "/*verilator public*/";
}
ports.push_back(std::make_unique<vAST::StringPort>(port_str));
}
vAST::Parameters parameters;
Expand Down Expand Up @@ -177,19 +182,31 @@ compile_string_body_module(json verilog_json, std::string name,
std::make_unique<vAST::NumericLiteral>("1")));
}
}
std::string definition;
if (this->verilator_debug &&
verilog_json.count("verilator_debug_definition")) {
definition = verilog_json["verilator_debug_definition"].get<std::string>();
} else {
definition = verilog_json["definition"].get<std::string>();
}
return std::make_unique<vAST::StringBodyModule>(
name, std::move(ports), verilog_json["definition"].get<std::string>(),
std::move(parameters));
name, std::move(ports), definition, std::move(parameters));
}

// Compile a CoreIR record type corresponding to the interface of a module with
// flattened types into a vector of vAST Ports
std::vector<std::unique_ptr<vAST::AbstractPort>>
compile_ports(RecordType *record_type) {
Passes::Verilog::compilePorts(RecordType *record_type) {
std::vector<std::unique_ptr<vAST::AbstractPort>> ports;
for (auto entry : record_type->getRecord()) {
std::string name_str = entry.first;
if (this->verilator_debug) {
// FIXME: Hack to get comment into port name, we need to design a way
// to attach comments to expressions
name_str += "/*verilator public*/";
}
std::unique_ptr<vAST::Identifier> name =
std::make_unique<vAST::Identifier>(entry.first);
std::make_unique<vAST::Identifier>(name_str);

Type *type = entry.second;

Expand Down Expand Up @@ -249,10 +266,8 @@ class ConnMapEntry {
// when multiple signals drive an input to an instance (e.g. the input is an
// array of 3 bits, and each bit is connected to a 1-bit driver). In this
// case, each entry stores the index that it drives.
//
// **TODO** Need to add support for inouts
std::map<ConnMapKey, std::vector<ConnMapEntry>>
build_connection_map(std::set<Connection, ConnectionCompFast> connections,
build_connection_map(std::vector<Connection> connections,
std::map<std::string, Instance *> instances) {
std::map<ConnMapKey, std::vector<ConnMapEntry>> connection_map;
for (auto connection : connections) {
Expand Down Expand Up @@ -345,6 +360,7 @@ void assign_module_outputs(
args[entry.index] =
(std::make_unique<vAST::Identifier>(connection_name));
}
std::reverse(args.begin(), args.end());
std::unique_ptr<vAST::Concat> concat =
std::make_unique<vAST::Concat>(std::move(args));
body.push_back(std::make_unique<vAST::ContinuousAssign>(
Expand All @@ -360,12 +376,29 @@ void assign_module_outputs(
}
}

// assign inout ports
void assign_inouts(
std::vector<Connection> connections,
std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>,
std::unique_ptr<vAST::Declaration>>> &body) {
for (auto connection : connections) {
if (connection.first->getType()->isInOut() ||
connection.second->getType()->isInOut()) {
body.push_back(std::make_unique<vAST::ContinuousAssign>(
std::make_unique<vAST::Identifier>(
convert_to_verilog_connection(connection.first)),
std::make_unique<vAST::Identifier>(
convert_to_verilog_connection(connection.second))));
};
};
}

// Traverses the instance map and creates a vector of module instantiations
// using connection_map to wire up instance ports
std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>,
std::unique_ptr<vAST::Declaration>>>
compile_module_body(RecordType *module_type,
std::set<Connection, ConnectionCompFast> connections,
std::vector<Connection> connections,
std::map<std::string, Instance *> instances) {
std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>,
std::unique_ptr<vAST::Declaration>>>
Expand All @@ -385,6 +418,9 @@ compile_module_body(RecordType *module_type,
} else {
module_name = instance_module->getLongName();
}
} else if (instance_module->getMetaData().count("verilog") > 0) {
json verilog_json = instance_module->getMetaData()["verilog"];
module_name = make_name(module_name, verilog_json);
}
vAST::Parameters instance_parameters;
std::string instance_name = instance.first;
Expand All @@ -395,16 +431,19 @@ compile_module_body(RecordType *module_type,
verilog_connections;
for (auto port :
cast<RecordType>(instance_module->getType())->getRecord()) {
if (port.second->isOutput()) {
if (!port.second->isInput()) {
// output or inout, emit wire name
verilog_connections.insert(
std::make_pair(port.first, std::make_unique<vAST::Identifier>(
instance.first + "_" + port.first)));
continue;
}
auto entries = connection_map[ConnMapKey(instance.first, port.first)];
// If it is not a bulk connection, create a concat node and wire up
// the inputs by index
if (entries.size() > 1) {
if (entries.size() == 0) {
continue;
} else if (entries.size() > 1) {
// If it is not a bulk connection, create a concat node and wire up
// the inputs by index
std::vector<std::unique_ptr<vAST::Expression>> args;
args.resize(entries.size());
for (auto entry : entries) {
Expand All @@ -413,6 +452,7 @@ compile_module_body(RecordType *module_type,
args[entry.index] =
std::make_unique<vAST::Identifier>(connection_name);
}
std::reverse(args.begin(), args.end());
std::unique_ptr<vAST::Concat> concat =
std::make_unique<vAST::Concat>(std::move(args));
verilog_connections.insert(
Expand Down Expand Up @@ -448,8 +488,9 @@ compile_module_body(RecordType *module_type,
std::move(verilog_connections));
body.push_back(std::move(statement));
}
// Wire the outputs of the module
// Wire the outputs of the module and inout connections
assign_module_outputs(module_type, body, connection_map);
assign_inouts(connections, body);
return body;
}

Expand Down Expand Up @@ -488,7 +529,7 @@ void Passes::Verilog::compileModule(Module *module) {
} else {
std::string name = make_name(module->getName(), verilog_json);
modules.push_back(std::make_pair(
name, compile_string_body_module(verilog_json, name, module)));
name, compileStringBodyModule(verilog_json, name, module)));
}
return;
}
Expand All @@ -500,7 +541,7 @@ void Passes::Verilog::compileModule(Module *module) {
std::string name = make_name(module->getName(), verilog_json);

modules.push_back(std::make_pair(
name, compile_string_body_module(verilog_json, name, module)));
name, compileStringBodyModule(verilog_json, name, module)));

// We only need to compile the verilog generator once, even though
// there may be multiple instances of the generator represented as
Expand All @@ -514,14 +555,14 @@ void Passes::Verilog::compileModule(Module *module) {
return;
}
std::vector<std::unique_ptr<vAST::AbstractPort>> ports =
compile_ports(cast<RecordType>(module->getType()));
compilePorts(cast<RecordType>(module->getType()));

ModuleDef *definition = module->getDef();
std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>,
std::unique_ptr<vAST::Declaration>>>
body =
compile_module_body(module->getType(), definition->getConnections(),
definition->getInstances());
body = compile_module_body(module->getType(),
definition->getSortedConnections(),
definition->getInstances());

vAST::Parameters parameters = compile_params(module);

Expand Down
6 changes: 3 additions & 3 deletions tests/gtest/array_select_golden.v
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ endmodule
module top (output [3:0] O, input [3:0] self_I);
wire [3:0] inst0_O;
wire [3:0] inst1_O;
foo inst0(.I({self_I[0],self_I[0],self_I[1],self_I[2]}), .O(inst0_O));
foo inst1(.I({inst0_O[0],inst0_O[1],inst0_O[1],self_I[1]}), .O(inst1_O));
assign O = {inst1_O[0],inst1_O[0],self_I[0],self_I[1]};
foo inst0(.I({self_I[2],self_I[1],self_I[0],self_I[0]}), .O(inst0_O));
foo inst1(.I({self_I[1],inst0_O[1],inst0_O[1],inst0_O[0]}), .O(inst1_O));
assign O = {self_I[1],self_I[0],inst1_O[0],inst1_O[0]};
endmodule

8 changes: 7 additions & 1 deletion tests/gtest/intermediate_connection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
"foo":{
"type":["Record",[
["I","BitIn"],
["IO","BitInOut"],
["O","Bit"]
]],
"metadata": {
"verilog": {
"verilog_string": "// This is an important comment for foo!!\nmodule foo (input I, output O);\n assign O = I;\nendmodule"
"verilog_string": "// This is an important comment for foo!!\nmodule foo (input I, inout IO, output O);\n assign O = I;\n assign IO = I;\nendmodule"
}
}
},
"top":{
"type":["Record",[
["I","BitIn"],
["IO0","BitInOut"],
["IO1","BitInOut"],
["O","Bit"]
]],
"instances":{
Expand All @@ -28,7 +31,10 @@
},
"connections":[
["self.I","inst0.I"],
["self.IO0","inst0.IO"],
["inst0.IO","self.IO1"],
["inst0.O","inst1.I"],
["inst0.IO","inst1.IO"],
["inst1.O","self.O"]
]
}
Expand Down
14 changes: 10 additions & 4 deletions tests/gtest/intermediate_connection_golden.v
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// This is an important comment for foo!!
module foo (input I, output O);
module foo (input I, inout IO, output O);
assign O = I;
assign IO = I;
endmodule
module top (input I, output O);
module top (input I, inout IO0, inout IO1, output O);
wire inst0_IO;
wire inst0_O;
wire inst1_IO;
wire inst1_O;
foo inst0(.I(I), .O(inst0_O));
foo inst1(.I(inst0_O), .O(inst1_O));
foo inst0(.I(I), .IO(inst0_IO), .O(inst0_O));
foo inst1(.I(inst0_O), .IO(inst1_IO), .O(inst1_O));
assign O = inst1_O;
assign inst0_IO = inst1_IO;
assign IO0 = inst0_IO;
assign inst0_IO = IO1;
endmodule

0 comments on commit 3f50887

Please sign in to comment.