Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Hierarchical netlists #92

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c72d937
Preparation of FlatModule for hierarchy
djwubs Mar 12, 2020
2eac567
Preparation of Cell for hierarchy
djwubs Mar 14, 2020
cbff383
Hierarchy changes for elkGraph (not working)
djwubs Mar 15, 2020
d686c2e
Fixed Elk input
djwubs Mar 16, 2020
ef62ec9
drawModule setup with Cell modifications
djwubs Mar 17, 2020
d481728
Fixed port- and module names
djwubs Mar 19, 2020
6de28df
Clean-up of Cell and Port
djwubs Mar 20, 2020
2fde0b8
Final cleanup phase 1
djwubs Mar 20, 2020
923f20f
Updated yosys schema for yosys update
djwubs Mar 20, 2020
0a15d58
Fix tests
djwubs Mar 20, 2020
f01fc41
Change parent to string
djwubs Mar 20, 2020
e39741c
Support for multiple of the same module
djwubs Mar 21, 2020
b401831
Fixed creation of dummies
djwubs Mar 23, 2020
137ae59
Fixed split and join width
djwubs Mar 23, 2020
ac17389
Removal of ExtendedEdge
djwubs Mar 25, 2020
541fb75
Start of config file
djwubs Mar 25, 2020
7fb05f9
Added basic config file functionality
djwubs Mar 27, 2020
82ef76a
Added more functionality to config file
djwubs Mar 28, 2020
6c83a84
Added basic color scheme for hierarchy
djwubs Apr 2, 2020
628ae71
Small color changes
djwubs Apr 2, 2020
156d56c
Removal of useless svg properties
djwubs Apr 4, 2020
c98d4cb
Fix of direct port lines in submodule
djwubs Apr 6, 2020
8b64a9f
Split and Join improvements
djwubs Apr 7, 2020
d388342
Added different top selection in config file
djwubs Apr 8, 2020
50a51ea
Yosys input update
djwubs Apr 9, 2020
512be5b
Quick change of top selection
djwubs Apr 19, 2020
0c84f5c
Addition of colour selection in config
djwubs Apr 21, 2020
c4782fa
Cleanup of defaultsvg
djwubs Apr 30, 2020
1be391f
Hierarchy update readme
djwubs May 8, 2020
0f2b4a7
Hierarchy example and readme update
djwubs May 8, 2020
74424cf
Readme reordering
djwubs May 9, 2020
40a009b
Moving colour options to svg file
djwubs May 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
482 changes: 366 additions & 116 deletions README.md

Large diffs are not rendered by default.

29 changes: 16 additions & 13 deletions bin/netlistsvg.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,50 @@ require('ajv-errors')(ajv);
if (require.main === module) {
var argv = yargs
.demand(1)
.usage('usage: $0 input_json_file [-o output_svg_file] [--skin skin_file] [--layout elk_json_file]')
.usage('usage: $0 input_json_file [-o output_svg_file] [--skin skin_file] [--layout elk_json_file] [--config config_json_file]')
.argv;
main(argv._[0], argv.o, argv.skin, argv.layout);
main(argv._[0], argv.o, argv.skin, argv.layout, argv.config);
}

function render(skinData, netlist, outputPath, elkData) {
function render(skinData, netlist, outputPath, elkData, configData) {
lib.render(skinData, netlist, (err, svgData) => {
if (err) throw err;
fs.writeFile(outputPath, svgData, 'utf-8', (err) => {
if (err) throw err;
});
}, elkData);
}, elkData, configData);
}

function parseFiles(skinPath, netlistPath, elkJsonPath, callback) {
function parseFiles(skinPath, netlistPath, elkJsonPath, configPath, callback) {
var elkData;
var configData;
fs.readFile(skinPath, 'utf-8', (err, skinData) => {
if (err) throw err;
fs.readFile(netlistPath, (err, netlistData) => {
if (err) throw err;
if (elkJsonPath) {
fs.readFile(elkJsonPath, (err, elkString) => {
callback(skinData, netlistData, json5.parse(elkString));
});
} else {
callback(skinData, netlistData);
elkData = json5.parse(fs.readFileSync(elkJsonPath));
}
if (configPath) {
configData = json5.parse(fs.readFileSync(configPath));
}
callback(skinData, netlistData, elkData, configData);
});
});
}

function main(netlistPath, outputPath, skinPath, elkJsonPath) {
function main(netlistPath, outputPath, skinPath, elkJsonPath, configPath) {
skinPath = skinPath || path.join(__dirname, '../lib/default.svg');
configPath = configPath || path.join(__dirname, '../lib/config.json');
outputPath = outputPath || 'out.svg';
var schemaPath = path.join(__dirname, '../lib/yosys.schema.json5');
parseFiles(skinPath, netlistPath, elkJsonPath, (skinData, netlistString, elkData) => {
parseFiles(skinPath, netlistPath, elkJsonPath, configPath, (skinData, netlistString, elkData, configData) => {
var netlistJson = json5.parse(netlistString);
var valid = ajv.validate(json5.parse(fs.readFileSync(schemaPath)), netlistJson);
if (!valid) {
throw Error(JSON.stringify(ajv.errors, null, 2));
}
render(skinData, netlistJson, outputPath, elkData);
render(skinData, netlistJson, outputPath, elkData, configData);
});
}

Expand Down
227 changes: 200 additions & 27 deletions built/Cell.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions built/ConfigModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
100 changes: 82 additions & 18 deletions built/FlatModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,89 @@ var Skin_1 = require("./Skin");
var Cell_1 = require("./Cell");
var _ = require("lodash");
var FlatModule = /** @class */ (function () {
function FlatModule(netlist) {
function FlatModule(mod, name, depth, parent) {
var _this = this;
this.moduleName = null;
_.forEach(netlist.modules, function (mod, name) {
if (mod.attributes && mod.attributes.top === 1) {
_this.moduleName = name;
if (parent === void 0) { parent = null; }
this.parent = parent;
this.moduleName = name;
var ports = _.map(mod.ports, function (port, portName) { return Cell_1.default.fromPort(port, portName, _this.moduleName); });
var cells = _.map(mod.cells, function (c, key) {
switch (FlatModule.config.hierarchy.enable) {
case 'level': {
if (FlatModule.config.hierarchy.expandLevel > depth) {
if (_.includes(FlatModule.modNames, c.type)) {
return Cell_1.default.createSubModule(c, key, _this.moduleName, FlatModule.netlist.modules[c.type], depth);
}
else {
return Cell_1.default.fromYosysCell(c, key, _this.moduleName);
}
}
else {
return Cell_1.default.fromYosysCell(c, key, _this.moduleName);
}
}
case 'all': {
if (_.includes(FlatModule.modNames, c.type)) {
return Cell_1.default.createSubModule(c, key, _this.moduleName, FlatModule.netlist.modules[c.type], depth);
}
else {
return Cell_1.default.fromYosysCell(c, key, _this.moduleName);
}
}
case 'modules': {
if (_.includes(FlatModule.config.hierarchy.expandModules.types, c.type) ||
_.includes(FlatModule.config.hierarchy.expandModules.ids, key)) {
if (!_.includes(FlatModule.modNames, c.type)) {
throw new Error('Submodule in config file not defined in input json file.');
}
return Cell_1.default.createSubModule(c, key, _this.moduleName, FlatModule.netlist.modules[c.type], depth);
}
else {
return Cell_1.default.fromYosysCell(c, key, _this.moduleName);
}
}
default: {
return Cell_1.default.fromYosysCell(c, key, _this.moduleName);
}
}
});
// Otherwise default the first one in the file...
if (this.moduleName == null) {
this.moduleName = Object.keys(netlist.modules)[0];
}
var top = netlist.modules[this.moduleName];
var ports = _.map(top.ports, Cell_1.default.fromPort);
var cells = _.map(top.cells, function (c, key) { return Cell_1.default.fromYosysCell(c, key); });
this.nodes = cells.concat(ports);
// populated by createWires
this.wires = [];
// this can be skipped if there are no 0's or 1's
if (FlatModule.layoutProps.constants !== false) {
this.addConstants();
}
// this can be skipped if there are no splits or joins
if (FlatModule.layoutProps.splitsAndJoins !== false) {
this.addSplitsJoins();
}
this.createWires();
}
FlatModule.fromNetlist = function (netlist, config) {
this.layoutProps = Skin_1.default.getProperties();
this.modNames = Object.keys(netlist.modules);
this.netlist = netlist;
this.config = config;
var topName = null;
if (this.config.top.enable) {
topName = this.config.top.module;
if (!_.includes(this.modNames, topName)) {
throw new Error('Top module in config file not defined in input json file.');
}
}
else {
_.forEach(netlist.modules, function (mod, name) {
if (mod.attributes && Number(mod.attributes.top) === 1) {
topName = name;
}
});
// Otherwise default the first one in the file...
if (topName == null) {
topName = this.modNames[0];
}
}
var top = netlist.modules[topName];
return new FlatModule(top, topName, 0);
};
// converts input ports with constant assignments to constant nodes
FlatModule.prototype.addConstants = function () {
// find the maximum signal number
Expand All @@ -37,6 +101,7 @@ var FlatModule = /** @class */ (function () {
};
// solves for minimal bus splits and joins and adds them to module
FlatModule.prototype.addSplitsJoins = function () {
var _this = this;
var allInputs = _.flatMap(this.nodes, function (n) { return n.inputPortVals(); });
var allOutputs = _.flatMap(this.nodes, function (n) { return n.outputPortVals(); });
var allInputsCopy = allInputs.slice();
Expand All @@ -46,19 +111,18 @@ var FlatModule = /** @class */ (function () {
gather(allOutputs, allInputsCopy, input, 0, input.length, splits, joins);
});
this.nodes = this.nodes.concat(_.map(joins, function (joinOutput, joinInputs) {
return Cell_1.default.fromJoinInfo(joinInputs, joinOutput);
return Cell_1.default.fromJoinInfo(joinInputs, joinOutput, _this.moduleName);
})).concat(_.map(splits, function (splitOutputs, splitInput) {
return Cell_1.default.fromSplitInfo(splitInput, splitOutputs);
return Cell_1.default.fromSplitInfo(splitInput, splitOutputs, _this.moduleName);
}));
};
// search through all the ports to find all of the wires
FlatModule.prototype.createWires = function () {
var layoutProps = Skin_1.default.getProperties();
var ridersByNet = {};
var driversByNet = {};
var lateralsByNet = {};
this.nodes.forEach(function (n) {
n.collectPortsByDirection(ridersByNet, driversByNet, lateralsByNet, layoutProps.genericsLaterals);
n.collectPortsByDirection(ridersByNet, driversByNet, lateralsByNet, FlatModule.layoutProps.genericsLaterals);
});
// list of unique nets
var nets = removeDups(_.keys(ridersByNet).concat(_.keys(driversByNet)).concat(_.keys(lateralsByNet)));
Expand Down
41 changes: 31 additions & 10 deletions built/Port.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ var Port = /** @class */ (function () {
Port.prototype.valString = function () {
return ',' + this.value.join() + ',';
};
Port.prototype.findConstants = function (sigsByConstantName, maxNum, constantCollector) {
Port.prototype.findConstants = function (sigsByConstantName, maxNum, constantCollector, parent) {
var _this = this;
var constNameCollector = '';
var constNumCollector = [];
var portSigs = this.value;
portSigs.forEach(function (portSig, portSigIndex) {
// is constant?
if (portSig === '0' || portSig === '1') {
if (portSig === '0' || portSig === '1' || portSig === 'x') {
maxNum += 1;
constNameCollector += portSig;
// replace the constant with new signal num
Expand All @@ -39,19 +39,19 @@ var Port = /** @class */ (function () {
// string of constants ended before end of p.value
}
else if (constNumCollector.length > 0) {
_this.assignConstant(constNameCollector, constNumCollector, portSigIndex, sigsByConstantName, constantCollector);
_this.assignConstant(constNameCollector, constNumCollector, portSigIndex, sigsByConstantName, constantCollector, parent);
// reset name and num collectors
constNameCollector = '';
constNumCollector = [];
}
});
if (constNumCollector.length > 0) {
this.assignConstant(constNameCollector, constNumCollector, portSigs.length, sigsByConstantName, constantCollector);
this.assignConstant(constNameCollector, constNumCollector, portSigs.length, sigsByConstantName, constantCollector, parent);
}
return maxNum;
};
Port.prototype.getGenericElkPort = function (index, templatePorts, dir) {
var nkey = this.parentNode.Key;
var nkey = this.parentNode.parent + '.' + this.parentNode.Key;
var type = this.parentNode.getTemplate()[1]['s:type'];
if (index === 0) {
var ret = {
Expand All @@ -61,7 +61,7 @@ var Port = /** @class */ (function () {
x: Number(templatePorts[0][1]['s:x']),
y: Number(templatePorts[0][1]['s:y']),
};
if ((type === 'generic' || type === 'join') && dir === 'in') {
if ((type === 'generic' || type === 'sub_even' || type === 'sub_odd' || type === 'join') && dir === 'in') {
ret.labels = [{
id: nkey + '.' + this.key + '.label',
text: this.key,
Expand All @@ -70,8 +70,12 @@ var Port = /** @class */ (function () {
width: (6 * this.key.length),
height: 11,
}];
if (type === 'sub_even' || type === 'sub_odd') {
ret.layoutOptions = { 'org.eclipse.elk.port.side': 'WEST' };
}
}
if ((type === 'generic' || type === 'split') && dir === 'out') {
if ((type === 'generic' || type === 'sub_even' || type === 'sub_odd' || type === 'split')
&& dir === 'out') {
ret.labels = [{
id: nkey + '.' + this.key + '.label',
text: this.key,
Expand All @@ -80,6 +84,13 @@ var Port = /** @class */ (function () {
width: (6 * this.key.length),
height: 11,
}];
if (type === 'sub_even' || type === 'sub_odd') {
ret.layoutOptions = { 'org.eclipse.elk.port.side': 'EAST' };
}
}
if (type === 'sub_even' || type === 'sub_odd') {
delete ret.x;
delete ret.y;
}
return ret;
}
Expand All @@ -92,7 +103,7 @@ var Port = /** @class */ (function () {
x: Number(templatePorts[0][1]['s:x']),
y: (index) * gap + Number(templatePorts[0][1]['s:y']),
};
if (type === 'generic') {
if (type === 'generic' || type === 'sub_even' || type === 'sub_odd') {
ret.labels = [{
id: nkey + '.' + this.key + '.label',
text: this.key,
Expand All @@ -101,11 +112,21 @@ var Port = /** @class */ (function () {
width: (6 * this.key.length),
height: 11,
}];
if (dir === 'in') {
ret.layoutOptions = { 'org.eclipse.elk.port.side': 'WEST' };
}
if (dir === 'out') {
ret.layoutOptions = { 'org.eclipse.elk.port.side': 'EAST' };
}
}
if (type === 'sub_even' || type === 'sub_odd') {
delete ret.x;
delete ret.y;
}
return ret;
}
};
Port.prototype.assignConstant = function (nameCollector, constants, currIndex, signalsByConstantName, constantCollector) {
Port.prototype.assignConstant = function (nameCollector, constants, currIndex, signalsByConstantName, constantCollector, parent) {
var _this = this;
// we've been appending to nameCollector, so reverse to get const name
var constName = nameCollector.split('').reverse().join('');
Expand All @@ -121,7 +142,7 @@ var Port = /** @class */ (function () {
});
}
else {
constantCollector.push(Cell_1.default.fromConstantInfo(constName, constants));
constantCollector.push(Cell_1.default.fromConstantInfo(constName, constants, parent));
signalsByConstantName[constName] = constants;
}
};
Expand Down
29 changes: 21 additions & 8 deletions built/Skin.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ var Skin;
});
}
Skin.getLateralPortPids = getLateralPortPids;
function findSkinType(type) {
function findSkinType(type, depth) {
if (depth === void 0) { depth = null; }
var ret = null;
onml.traverse(Skin.skin, {
enter: function (node, parent) {
Expand All @@ -68,13 +69,25 @@ var Skin;
},
});
if (ret == null) {
onml.traverse(Skin.skin, {
enter: function (node) {
if (node.attr['s:type'] === 'generic') {
ret = node;
}
},
});
if (depth == null) {
onml.traverse(Skin.skin, {
enter: function (node) {
if (node.attr['s:type'] === 'generic') {
ret = node;
}
},
});
}
else {
var sub_1 = ['sub_odd', 'sub_even'];
onml.traverse(Skin.skin, {
enter: function (node) {
if (node.attr['s:type'] === sub_1[depth % 2]) {
ret = node;
}
},
});
}
}
return ret.full;
}
Expand Down
Loading