Merge pull request #358 from YosysHQ/generic-improve
Generic Arch improvements
This commit is contained in:
commit
befc994806
@ -11,6 +11,6 @@ task:
|
|||||||
test_ice40_script: cd build && ./nextpnr-ice40-test
|
test_ice40_script: cd build && ./nextpnr-ice40-test
|
||||||
smoketest_ice40_script: export NEXTPNR=$(pwd)/build/nextpnr-ice40 && cd ice40/smoketest/attosoc && ./smoketest.sh
|
smoketest_ice40_script: export NEXTPNR=$(pwd)/build/nextpnr-ice40 && cd ice40/smoketest/attosoc && ./smoketest.sh
|
||||||
test_ecp5_script: cd build && ./nextpnr-ecp5-test
|
test_ecp5_script: cd build && ./nextpnr-ecp5-test
|
||||||
smoketest_generic_script: export NEXTPNR=$(pwd)/build/nextpnr-generic && cd generic/examples && ./simple.sh
|
smoketest_generic_script: export NEXTPNR=$(pwd)/build/nextpnr-generic && cd generic/examples && ./simple.sh && ./simtest.sh
|
||||||
regressiontest_ice40_script: make -j $(nproc) -C tests/ice40/regressions NPNR=$(pwd)/build/nextpnr-ice40
|
regressiontest_ice40_script: make -j $(nproc) -C tests/ice40/regressions NPNR=$(pwd)/build/nextpnr-ice40
|
||||||
regressiontest_ecp5_script: make -j $(nproc) -C tests/ecp5/regressions NPNR=$(pwd)/build/nextpnr-ecp5
|
regressiontest_ecp5_script: make -j $(nproc) -C tests/ecp5/regressions NPNR=$(pwd)/build/nextpnr-ecp5
|
||||||
|
@ -27,6 +27,30 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
WireInfo &Arch::wire_info(IdString wire)
|
||||||
|
{
|
||||||
|
auto w = wires.find(wire);
|
||||||
|
if (w == wires.end())
|
||||||
|
NPNR_ASSERT_FALSE_STR("no wire named " + wire.str(this));
|
||||||
|
return w->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
PipInfo &Arch::pip_info(IdString pip)
|
||||||
|
{
|
||||||
|
auto p = pips.find(pip);
|
||||||
|
if (p == pips.end())
|
||||||
|
NPNR_ASSERT_FALSE_STR("no pip named " + pip.str(this));
|
||||||
|
return p->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
BelInfo &Arch::bel_info(IdString bel)
|
||||||
|
{
|
||||||
|
auto b = bels.find(bel);
|
||||||
|
if (b == bels.end())
|
||||||
|
NPNR_ASSERT_FALSE_STR("no bel named " + bel.str(this));
|
||||||
|
return b->second;
|
||||||
|
}
|
||||||
|
|
||||||
void Arch::addWire(IdString name, IdString type, int x, int y)
|
void Arch::addWire(IdString name, IdString type, int x, int y)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wires.count(name) == 0);
|
NPNR_ASSERT(wires.count(name) == 0);
|
||||||
@ -50,8 +74,8 @@ void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWi
|
|||||||
pi.delay = delay;
|
pi.delay = delay;
|
||||||
pi.loc = loc;
|
pi.loc = loc;
|
||||||
|
|
||||||
wires.at(srcWire).downhill.push_back(name);
|
wire_info(srcWire).downhill.push_back(name);
|
||||||
wires.at(dstWire).uphill.push_back(name);
|
wire_info(dstWire).uphill.push_back(name);
|
||||||
pip_ids.push_back(name);
|
pip_ids.push_back(name);
|
||||||
|
|
||||||
if (int(tilePipDimZ.size()) <= loc.x)
|
if (int(tilePipDimZ.size()) <= loc.x)
|
||||||
@ -75,7 +99,7 @@ void Arch::addAlias(IdString name, IdString type, IdString srcWire, IdString dst
|
|||||||
pi.dstWire = dstWire;
|
pi.dstWire = dstWire;
|
||||||
pi.delay = delay;
|
pi.delay = delay;
|
||||||
|
|
||||||
wires.at(srcWire).aliases.push_back(name);
|
wire_info(srcWire).aliases.push_back(name);
|
||||||
pip_ids.push_back(name);
|
pip_ids.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,38 +139,38 @@ void Arch::addBel(IdString name, IdString type, Loc loc, bool gb)
|
|||||||
|
|
||||||
void Arch::addBelInput(IdString bel, IdString name, IdString wire)
|
void Arch::addBelInput(IdString bel, IdString name, IdString wire)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bels.at(bel).pins.count(name) == 0);
|
NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
|
||||||
PinInfo &pi = bels.at(bel).pins[name];
|
PinInfo &pi = bel_info(bel).pins[name];
|
||||||
pi.name = name;
|
pi.name = name;
|
||||||
pi.wire = wire;
|
pi.wire = wire;
|
||||||
pi.type = PORT_IN;
|
pi.type = PORT_IN;
|
||||||
|
|
||||||
wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name});
|
wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name});
|
||||||
wires.at(wire).bel_pins.push_back(BelPin{bel, name});
|
wire_info(wire).bel_pins.push_back(BelPin{bel, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addBelOutput(IdString bel, IdString name, IdString wire)
|
void Arch::addBelOutput(IdString bel, IdString name, IdString wire)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bels.at(bel).pins.count(name) == 0);
|
NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
|
||||||
PinInfo &pi = bels.at(bel).pins[name];
|
PinInfo &pi = bel_info(bel).pins[name];
|
||||||
pi.name = name;
|
pi.name = name;
|
||||||
pi.wire = wire;
|
pi.wire = wire;
|
||||||
pi.type = PORT_OUT;
|
pi.type = PORT_OUT;
|
||||||
|
|
||||||
wires.at(wire).uphill_bel_pin = BelPin{bel, name};
|
wire_info(wire).uphill_bel_pin = BelPin{bel, name};
|
||||||
wires.at(wire).bel_pins.push_back(BelPin{bel, name});
|
wire_info(wire).bel_pins.push_back(BelPin{bel, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addBelInout(IdString bel, IdString name, IdString wire)
|
void Arch::addBelInout(IdString bel, IdString name, IdString wire)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bels.at(bel).pins.count(name) == 0);
|
NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
|
||||||
PinInfo &pi = bels.at(bel).pins[name];
|
PinInfo &pi = bel_info(bel).pins[name];
|
||||||
pi.name = name;
|
pi.name = name;
|
||||||
pi.wire = wire;
|
pi.wire = wire;
|
||||||
pi.type = PORT_INOUT;
|
pi.type = PORT_INOUT;
|
||||||
|
|
||||||
wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name});
|
wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name});
|
||||||
wires.at(wire).bel_pins.push_back(BelPin{bel, name});
|
wire_info(wire).bel_pins.push_back(BelPin{bel, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); }
|
void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); }
|
||||||
@ -165,19 +189,19 @@ void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic)
|
|||||||
|
|
||||||
void Arch::setWireDecal(WireId wire, DecalXY decalxy)
|
void Arch::setWireDecal(WireId wire, DecalXY decalxy)
|
||||||
{
|
{
|
||||||
wires.at(wire).decalxy = decalxy;
|
wire_info(wire).decalxy = decalxy;
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::setPipDecal(PipId pip, DecalXY decalxy)
|
void Arch::setPipDecal(PipId pip, DecalXY decalxy)
|
||||||
{
|
{
|
||||||
pips.at(pip).decalxy = decalxy;
|
pip_info(pip).decalxy = decalxy;
|
||||||
refreshUiPip(pip);
|
refreshUiPip(pip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::setBelDecal(BelId bel, DecalXY decalxy)
|
void Arch::setBelDecal(BelId bel, DecalXY decalxy)
|
||||||
{
|
{
|
||||||
bels.at(bel).decalxy = decalxy;
|
bel_info(bel).decalxy = decalxy;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,11 +211,11 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
|
|||||||
refreshUiGroup(group);
|
refreshUiGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::setWireAttr(IdString wire, IdString key, const std::string &value) { wires.at(wire).attrs[key] = value; }
|
void Arch::setWireAttr(IdString wire, IdString key, const std::string &value) { wire_info(wire).attrs[key] = value; }
|
||||||
|
|
||||||
void Arch::setPipAttr(IdString pip, IdString key, const std::string &value) { pips.at(pip).attrs[key] = value; }
|
void Arch::setPipAttr(IdString pip, IdString key, const std::string &value) { pip_info(pip).attrs[key] = value; }
|
||||||
|
|
||||||
void Arch::setBelAttr(IdString bel, IdString key, const std::string &value) { bels.at(bel).attrs[key] = value; }
|
void Arch::setBelAttr(IdString bel, IdString key, const std::string &value) { bel_info(bel).attrs[key] = value; }
|
||||||
|
|
||||||
void Arch::setLutK(int K) { args.K = K; }
|
void Arch::setLutK(int K) { args.K = K; }
|
||||||
|
|
||||||
|
@ -122,6 +122,11 @@ struct Arch : BaseCtx
|
|||||||
std::unordered_map<IdString, BelInfo> bels;
|
std::unordered_map<IdString, BelInfo> bels;
|
||||||
std::unordered_map<GroupId, GroupInfo> groups;
|
std::unordered_map<GroupId, GroupInfo> groups;
|
||||||
|
|
||||||
|
// These functions include useful errors if not found
|
||||||
|
WireInfo &wire_info(IdString wire);
|
||||||
|
PipInfo &pip_info(IdString wire);
|
||||||
|
BelInfo &bel_info(IdString wire);
|
||||||
|
|
||||||
std::vector<IdString> bel_ids, wire_ids, pip_ids;
|
std::vector<IdString> bel_ids, wire_ids, pip_ids;
|
||||||
|
|
||||||
std::unordered_map<Loc, BelId> bel_by_loc;
|
std::unordered_map<Loc, BelId> bel_by_loc;
|
||||||
|
3
generic/examples/.gitignore
vendored
3
generic/examples/.gitignore
vendored
@ -1,3 +1,6 @@
|
|||||||
blinky.fasm
|
blinky.fasm
|
||||||
__pycache__
|
__pycache__
|
||||||
*.pyc
|
*.pyc
|
||||||
|
pnrblinky.v
|
||||||
|
/blinky_simtest
|
||||||
|
*.vcd
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
module top(input clk, output reg [7:0] leds);
|
module top(input clk, rst, output reg [7:0] leds);
|
||||||
|
|
||||||
reg [25:0] ctr;
|
reg [7:0] ctr;
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
ctr <= ctr + 1'b1;
|
if (rst)
|
||||||
|
ctr <= 8'h00;
|
||||||
|
else
|
||||||
|
ctr <= ctr + 1'b1;
|
||||||
|
|
||||||
assign leds = ctr[25:18];
|
assign leds = ctr;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
38
generic/examples/blinky_tb.v
Normal file
38
generic/examples/blinky_tb.v
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
module blinky_tb;
|
||||||
|
|
||||||
|
reg clk = 1'b0, rst = 1'b0;
|
||||||
|
reg [7:0] ctr_gold = 8'h00;
|
||||||
|
wire [7:0] ctr_gate;
|
||||||
|
top dut_i(.clk(clk), .rst(rst), .leds(ctr_gate));
|
||||||
|
|
||||||
|
task oneclk;
|
||||||
|
begin
|
||||||
|
clk = 1'b1;
|
||||||
|
#10;
|
||||||
|
clk = 1'b0;
|
||||||
|
#10;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("blinky_simtest.vcd");
|
||||||
|
$dumpvars(0, blinky_tb);
|
||||||
|
#100;
|
||||||
|
rst = 1'b1;
|
||||||
|
repeat (5) oneclk;
|
||||||
|
#5
|
||||||
|
rst = 1'b0;
|
||||||
|
#5
|
||||||
|
repeat (500) begin
|
||||||
|
if (ctr_gold !== ctr_gate) begin
|
||||||
|
$display("mismatch gold=%b gate=%b", ctr_gold, ctr_gate);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
oneclk;
|
||||||
|
ctr_gold = ctr_gold + 1'b1;
|
||||||
|
end
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
7
generic/examples/simtest.sh
Executable file
7
generic/examples/simtest.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -ex
|
||||||
|
yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v
|
||||||
|
${NEXTPNR:-../../nextpnr-generic} --no-iobs --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py --write pnrblinky.json
|
||||||
|
yosys -p "read_json pnrblinky.json; write_verilog -noattr -norename pnrblinky.v"
|
||||||
|
iverilog -o blinky_simtest ../synth/prims.v blinky_tb.v pnrblinky.v
|
||||||
|
vvp -N ./blinky_simtest
|
@ -46,6 +46,7 @@ po::options_description GenericCommandHandler::getArchOptions()
|
|||||||
{
|
{
|
||||||
po::options_description specific("Architecture specific options");
|
po::options_description specific("Architecture specific options");
|
||||||
specific.add_options()("generic", "set device type to generic");
|
specific.add_options()("generic", "set device type to generic");
|
||||||
|
specific.add_options()("no-iobs", "disable automatic IO buffer insertion");
|
||||||
return specific;
|
return specific;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,10 @@ std::unique_ptr<Context> GenericCommandHandler::createContext(std::unordered_map
|
|||||||
if (arch_name != "generic")
|
if (arch_name != "generic")
|
||||||
log_error("Unsuported architecture '%s'.\n", arch_name.c_str());
|
log_error("Unsuported architecture '%s'.\n", arch_name.c_str());
|
||||||
}
|
}
|
||||||
return std::unique_ptr<Context>(new Context(chipArgs));
|
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||||
|
if (vm.count("no-iobs"))
|
||||||
|
ctx->settings[ctx->id("disable_iobs")] = Property::State::S1;
|
||||||
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -249,6 +249,10 @@ static void pack_io(Context *ctx)
|
|||||||
delete_nets.insert(net2->name);
|
delete_nets.insert(net2->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (bool_or_default(ctx->settings, ctx->id("disable_iobs"))) {
|
||||||
|
// No IO buffer insertion; just remove nextpnr_[io]buf
|
||||||
|
for (auto &p : ci->ports)
|
||||||
|
disconnect_port(ctx, ci, p.first);
|
||||||
} else {
|
} else {
|
||||||
// Create a GENERIC_IOB buffer
|
// Create a GENERIC_IOB buffer
|
||||||
std::unique_ptr<CellInfo> ice_cell =
|
std::unique_ptr<CellInfo> ice_cell =
|
||||||
|
@ -2,18 +2,27 @@
|
|||||||
|
|
||||||
module LUT #(
|
module LUT #(
|
||||||
parameter K = 4,
|
parameter K = 4,
|
||||||
parameter [2**K-1:0] INIT = 0,
|
parameter [2**K-1:0] INIT = 0
|
||||||
) (
|
) (
|
||||||
input [K-1:0] I,
|
input [K-1:0] I,
|
||||||
output Q
|
output Q
|
||||||
);
|
);
|
||||||
assign Q = INIT[I];
|
wire [K-1:0] I_pd;
|
||||||
|
|
||||||
|
genvar ii;
|
||||||
|
generate
|
||||||
|
for (ii = 0; ii < K; ii = ii + 1'b1)
|
||||||
|
assign I_pd[ii] = (I[ii] === 1'bz) ? 1'b0 : I[ii];
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
assign Q = INIT[I_pd];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module DFF (
|
module DFF (
|
||||||
input CLK, D,
|
input CLK, D,
|
||||||
output reg Q
|
output reg Q
|
||||||
);
|
);
|
||||||
|
initial Q = 1'b0;
|
||||||
always @(posedge CLK)
|
always @(posedge CLK)
|
||||||
Q <= D;
|
Q <= D;
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -73,14 +73,17 @@ struct PortGroup
|
|||||||
PortType dir;
|
PortType dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<PortGroup> group_ports(Context *ctx)
|
std::vector<PortGroup> group_ports(Context *ctx, const std::unordered_map<IdString, PortInfo> &ports,
|
||||||
|
bool is_cell = false)
|
||||||
{
|
{
|
||||||
std::vector<PortGroup> groups;
|
std::vector<PortGroup> groups;
|
||||||
std::unordered_map<std::string, size_t> base_to_group;
|
std::unordered_map<std::string, size_t> base_to_group;
|
||||||
for (auto &pair : ctx->ports) {
|
for (auto &pair : ports) {
|
||||||
std::string name = pair.second.name.str(ctx);
|
std::string name = pair.second.name.str(ctx);
|
||||||
if ((name.back() != ']') || (name.find('[') == std::string::npos)) {
|
if ((name.back() != ']') || (name.find('[') == std::string::npos)) {
|
||||||
groups.push_back({name, {pair.first.index}, pair.second.type});
|
groups.push_back({name,
|
||||||
|
{is_cell ? (pair.second.net ? pair.second.net->name.index : -1) : pair.first.index},
|
||||||
|
pair.second.type});
|
||||||
} else {
|
} else {
|
||||||
int off1 = int(name.find_last_of('['));
|
int off1 = int(name.find_last_of('['));
|
||||||
std::string basename = name.substr(0, off1);
|
std::string basename = name.substr(0, off1);
|
||||||
@ -95,26 +98,27 @@ std::vector<PortGroup> group_ports(Context *ctx)
|
|||||||
if (int(grp.bits.size()) <= index)
|
if (int(grp.bits.size()) <= index)
|
||||||
grp.bits.resize(index + 1, -1);
|
grp.bits.resize(index + 1, -1);
|
||||||
NPNR_ASSERT(grp.bits.at(index) == -1);
|
NPNR_ASSERT(grp.bits.at(index) == -1);
|
||||||
grp.bits.at(index) = pair.second.net ? pair.second.net->name.index : pair.first.index;
|
grp.bits.at(index) = pair.second.net ? pair.second.net->name.index : (is_cell ? -1 : pair.first.index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
};
|
}
|
||||||
|
|
||||||
std::string format_port_bits(const PortGroup &port)
|
std::string format_port_bits(const PortGroup &port, int &dummy_idx)
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "[ ";
|
s << "[ ";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto bit : port.bits) {
|
if (port.bits.size() != 1 || port.bits.at(0) != -1) // skip single disconnected ports
|
||||||
if (!first)
|
for (auto bit : port.bits) {
|
||||||
s << ", ";
|
if (!first)
|
||||||
if (bit == -1)
|
s << ", ";
|
||||||
s << "\"x\"";
|
if (bit == -1)
|
||||||
else
|
s << (++dummy_idx);
|
||||||
s << bit;
|
else
|
||||||
first = false;
|
s << bit;
|
||||||
}
|
first = false;
|
||||||
|
}
|
||||||
s << " ]";
|
s << " ]";
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
@ -122,6 +126,7 @@ std::string format_port_bits(const PortGroup &port)
|
|||||||
void write_module(std::ostream &f, Context *ctx)
|
void write_module(std::ostream &f, Context *ctx)
|
||||||
{
|
{
|
||||||
auto val = ctx->attrs.find(ctx->id("module"));
|
auto val = ctx->attrs.find(ctx->id("module"));
|
||||||
|
int dummy_idx = int(ctx->idstring_idx_to_str->size()) + 1000;
|
||||||
if (val != ctx->attrs.end())
|
if (val != ctx->attrs.end())
|
||||||
f << stringf(" %s: {\n", get_string(val->second.as_string()).c_str());
|
f << stringf(" %s: {\n", get_string(val->second.as_string()).c_str());
|
||||||
else
|
else
|
||||||
@ -134,14 +139,14 @@ void write_module(std::ostream &f, Context *ctx)
|
|||||||
f << stringf("\n },\n");
|
f << stringf("\n },\n");
|
||||||
f << stringf(" \"ports\": {");
|
f << stringf(" \"ports\": {");
|
||||||
|
|
||||||
auto ports = group_ports(ctx);
|
auto ports = group_ports(ctx, ctx->ports);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto &port : ports) {
|
for (auto &port : ports) {
|
||||||
f << stringf("%s\n", first ? "" : ",");
|
f << stringf("%s\n", first ? "" : ",");
|
||||||
f << stringf(" %s: {\n", get_string(port.name).c_str());
|
f << stringf(" %s: {\n", get_string(port.name).c_str());
|
||||||
f << stringf(" \"direction\": \"%s\",\n",
|
f << stringf(" \"direction\": \"%s\",\n",
|
||||||
port.dir == PORT_IN ? "input" : port.dir == PORT_INOUT ? "inout" : "output");
|
port.dir == PORT_IN ? "input" : port.dir == PORT_INOUT ? "inout" : "output");
|
||||||
f << stringf(" \"bits\": %s\n", format_port_bits(port).c_str());
|
f << stringf(" \"bits\": %s\n", format_port_bits(port, dummy_idx).c_str());
|
||||||
f << stringf(" }");
|
f << stringf(" }");
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
@ -151,6 +156,7 @@ void write_module(std::ostream &f, Context *ctx)
|
|||||||
first = true;
|
first = true;
|
||||||
for (auto &pair : ctx->cells) {
|
for (auto &pair : ctx->cells) {
|
||||||
auto &c = pair.second;
|
auto &c = pair.second;
|
||||||
|
auto cell_ports = group_ports(ctx, c->ports, true);
|
||||||
f << stringf("%s\n", first ? "" : ",");
|
f << stringf("%s\n", first ? "" : ",");
|
||||||
f << stringf(" %s: {\n", get_name(c->name, ctx).c_str());
|
f << stringf(" %s: {\n", get_name(c->name, ctx).c_str());
|
||||||
f << stringf(" \"hide_name\": %s,\n", c->name.c_str(ctx)[0] == '$' ? "1" : "0");
|
f << stringf(" \"hide_name\": %s,\n", c->name.c_str(ctx)[0] == '$' ? "1" : "0");
|
||||||
@ -163,24 +169,18 @@ void write_module(std::ostream &f, Context *ctx)
|
|||||||
f << stringf("\n },\n");
|
f << stringf("\n },\n");
|
||||||
f << stringf(" \"port_directions\": {");
|
f << stringf(" \"port_directions\": {");
|
||||||
bool first2 = true;
|
bool first2 = true;
|
||||||
for (auto &conn : c->ports) {
|
for (auto &pg : cell_ports) {
|
||||||
auto &p = conn.second;
|
std::string direction = (pg.dir == PORT_IN) ? "input" : (pg.dir == PORT_OUT) ? "output" : "inout";
|
||||||
std::string direction = (p.type == PORT_IN) ? "input" : (p.type == PORT_OUT) ? "output" : "inout";
|
|
||||||
f << stringf("%s\n", first2 ? "" : ",");
|
f << stringf("%s\n", first2 ? "" : ",");
|
||||||
f << stringf(" %s: \"%s\"", get_name(conn.first, ctx).c_str(), direction.c_str());
|
f << stringf(" %s: \"%s\"", get_string(pg.name).c_str(), direction.c_str());
|
||||||
first2 = false;
|
first2 = false;
|
||||||
}
|
}
|
||||||
f << stringf("\n },\n");
|
f << stringf("\n },\n");
|
||||||
f << stringf(" \"connections\": {");
|
f << stringf(" \"connections\": {");
|
||||||
first2 = true;
|
first2 = true;
|
||||||
for (auto &conn : c->ports) {
|
for (auto &pg : cell_ports) {
|
||||||
auto &p = conn.second;
|
|
||||||
f << stringf("%s\n", first2 ? "" : ",");
|
f << stringf("%s\n", first2 ? "" : ",");
|
||||||
if (p.net)
|
f << stringf(" %s: %s", get_string(pg.name).c_str(), format_port_bits(pg, dummy_idx).c_str());
|
||||||
f << stringf(" %s: [ %d ]", get_name(conn.first, ctx).c_str(), p.net->name.index);
|
|
||||||
else
|
|
||||||
f << stringf(" %s: [ ]", get_name(conn.first, ctx).c_str());
|
|
||||||
|
|
||||||
first2 = false;
|
first2 = false;
|
||||||
}
|
}
|
||||||
f << stringf("\n }\n");
|
f << stringf("\n }\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user